1
0
mirror of https://github.com/docker/docker-credential-helpers.git synced 2026-06-28 15:21:29 +05:30

Compare commits

...

166 Commits

Author SHA1 Message Date
Paweł Gronowski ed71c9e95d Merge pull request #425 from thaJeztah/bump_xx
Dockerfile: update xx to v1.9.0
2026-04-17 17:47:17 +02:00
Paweł Gronowski 8af787bb3e Merge pull request #424 from thaJeztah/bump_go
update to Go 1.25.9
2026-04-17 17:47:10 +02:00
Paweł Gronowski 8b34acde14 Merge pull request #426 from thaJeztah/bump_golangci
Dockerfile: update golangci-lint to v2.11
2026-04-17 17:47:07 +02:00
Sebastiaan van Stijn 815dddf301 Dockerfile: update xx to v1.9.0
full diff: https://github.com/tonistiigi/xx/compare/v1.7.0...v1.9.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-04-17 15:52:06 +02:00
Sebastiaan van Stijn 1be1c1e190 update to Go 1.25.9
go1.25.9 (released 2026-04-07) includes security fixes to the go command,
the compiler, and the archive/tar, crypto/tls, crypto/x509, html/template,
and os packages, as well as bug fixes to the go command, the compiler, and
the runtime. See the Go 1.25.9 milestone on our issue tracker for details.

- https://github.com/golang/go/issues?q=milestone%3AGo1.25.9+label%3ACherryPickApproved
- full diff: https://github.com/golang/go/compare/go1.25.8...go1.25.9

From the security announce:

We have just released Go versions 1.26.2 and 1.25.9, minor point releases.

These releases include 10 security fixes following the security policy:

- os: Root.Chmod can follow symlinks out of the root on Linux

  On Linux, if the target of Root.Chmod is replaced with a symlink while
  the chmod operation is in progress, Chmod could operate on the target
  of the symlink, even when the target lies outside the root.

  The Linux fchmodat syscall silently ignores the AT_SYMLINK_NOFOLLOW flag,
  which Root.Chmod uses to avoid symlink traversal. Root.Chmod checks its
  target before acting and returns an error if the target is a symlink
  lying outside the root, so the impact is limited to cases where the
  target is replaced with a symlink between the check and operation.

  On Linux, Root.Chmod now uses the fchmodat2 syscall when available, and
  an workaround using /proc/self/fd otherwise.

  Thanks to Uuganbayar Lkhamsuren for reporting this issue.

  This is CVE-2026-32282 and Go issue https://go.dev/issue/78293.

- html/template: JS template literal context incorrectly tracked

  Context was not properly tracked across template branches for JS template
  literals, leading to possibly incorrect escaping of content when branches were
  used.

  Additionally template actions within JS template literals did not properly
  track
  the brace depth, leading to incorrect escaping being applied.

  These issues could cause actions within JS template literals to be incorrectly
  or improperly escaped, leading to XSS vulnerabilities.

  This only affects templates that use template actions within JS template
  literals.

  This is CVE-2026-32289 and Go issue https://go.dev/issue/78331.

- crypto/x509: excluded DNS constraints not properly applied to wildcard domains

  When verifying a certificate chain containing excluded DNS constraints, these
  constraints are not correctly applied to wildcard DNS SANs which use a
  different
  case than the constraint.

  For example, if a certificate contains the DNS name "*.example.com" and the
  excluded DNS name "EXAMPLE.COM", the constraint will not be applied.

  This only affects validation of otherwise trusted certificate chains, issued
  by
  a root CA in the VerifyOptions.Roots CertPool, or in the system certificate
  pool.

  This issue only affects Go 1.26.

  Thank you to Riyas from Saintgits College of Engineering, k1rnt, @1seal for
  reporting this issue.

  This is CVE-2026-33810 and Go issue https://go.dev/issue/78332.

- cmd/compile: no-op interface conversion bypasses overlap checking

  Previously, the compiler failed to unwrap pointers contained within
  a no-op interface conversion leading to an incorrect determination
  of a non-overlapping move.

  To prevent unsafe move operations, the compiler will now unwrap all
  such conversions before considering a move non-overlapping.

  Thank you to Jakub Ciolek - https://ciolek.dev/ for reporting this issue.

  This is CVE-2026-27144 and Go issue https://go.dev/issue/78371.

- cmd/compile: possible memory corruption after bound check elimination

  Previously, slices and arrays accessed using induction variables
  were sometimes incorrectly proved in-bound. If the induction variable
  used for indexing were to overflow or underflow, it could allow access
  to memory beyond the scope of the original slice or array.

  To prevent this behavior, the compiler ensures that any mutated induction
  variable that overflows/underflows with respect to its loop condition
  is not used for bound check elimination.

  Thank you to Jakub Ciolek - https://ciolek.dev/ for reporting this issue.

  This is CVE-2026-27143 and Go issue https://go.dev/issue/78333.

- archive/tar: unbounded allocation when parsing old format GNU sparse map

  tar.Reader could allocate an unbounded amount of memory when reading
  a maliciously-crafted archive containing a large number of sparse
  regions encoded in the "old GNU sparse map" format.

  We now limit both the number of old GNU sparse map extension blocks,
  and the total number of sparse file entries, regardless of encoding.

  Thanks to Colin Walters (wal...@verbum.org) who initially reported this issue.
  Thanks also to Uuganbayar Lkhamsuren (https://github.com/uug4na) and Jakub
  Ciolek
  who additionally reported this issue.

  This is CVE-2026-32288 and Go issue https://go.dev/issue/78301.

- crypto/tls: multiple key update handshake messages can cause connection to
  deadlock

  If one side of the TLS connection sends multiple key update messages
  post-handshake in a single record, the connection can deadlock, causing
  uncontrolled consumption of resources. This can lead to a denial of service.

  This only affects TLS 1.3.

  Thank you to Jakub Ciolek - https://ciolek.dev/ for reporting this issue.

  This is CVE-2026-32283 and Go issue https://go.dev/issue/78334.

- cmd/go: trust layer bypass when using cgo and SWIG

  A well-crafted SWIG source file could take advantage
  of a file-naming convention used inside the trust
  boundary of the cgo compiler. Doing so could result
  in arbitrary code execution during build time.

  SWIG files are disallowed from using this convention.

  Thank you to Juho Forsén of Mattermost for reporting this issue.

  This is CVE-2026-27140 and Go issue https://go.dev/issue/78335.

- crypto/x509: unexpected work during chain building

  During chain building, the amount of work that is done is not correctly
  limited
  when a large number of intermediate certificates are passed in
  VerifyOptions.Intermediates, which can lead to a denial of service. This
  affects
  both direct users of crypto/x509 and users of crypto/tls.

  Thank you to Jakub Ciolek - https://ciolek.dev/ for reporting this issue.

  This is CVE-2026-32280 and Go issue https://go.dev/issue/78282.

- crypto/x509: inefficient policy validation

  Validating certificate chains which use policies is unexpectedly inefficient
  when certificates in the chain contain a very large number of policy mappings,
  possibly causing denial of service.

  This only affects validation of otherwise trusted certificate chains, issued
  by
  a root CA in the VerifyOptions.Roots CertPool, or in the system certificate
  pool.

  Thank you to Jakub Ciolek - https://ciolek.dev/ for reporting this issue.

  This is CVE-2026-32281 and Go issue https://go.dev/issue/78281.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-04-17 15:51:51 +02:00
Sebastiaan van Stijn 73bc2ff95d Dockerfile: update golangci-lint to v2.11
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-04-17 15:51:34 +02:00
Paweł Gronowski ae9f7a436a Merge pull request #412 from thaJeztah/dockerfile_docs
Dockerfile: document build-args
2026-04-17 15:41:51 +02:00
Sebastiaan van Stijn 27baf766de Merge pull request #423 from crazy-max/zizmor
ci: zizmor workflow
2026-04-16 16:05:09 +02:00
CrazyMax 9264cc84b4 fix zizmor findings
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2026-04-15 12:21:16 +02:00
CrazyMax 28f86c4a07 ci: zizmor workflow
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2026-04-15 12:21:07 +02:00
Sebastiaan van Stijn 6fe9815c68 Dockerfile: document build-args
```
docker buildx build --quiet --call=outline .

BUILD ARG            VALUE                                         DESCRIPTION
GO_VERSION           1.25.8                                        sets the version of the golang base image to use.
BASE_DEBIAN_DISTRO   bookworm                                      sets the golang base image debian variant to use.
XX_VERSION           1.7.0                                         sets the version of the xx utility to use.
OSXCROSS_VERSION     11.3-r8-debian                                sets the MacOSX cross toolchain to use.
PACKAGE              github.com/docker/docker-credential-helpers   sets the package name to print in the "--version" output.
```

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-04-15 11:52:15 +02:00
Sebastiaan van Stijn 16a8c2ce61 Merge pull request #421 from docker/dependabot/github_actions/actions/upload-artifact-7.0.1
build(deps): bump actions/upload-artifact from 7.0.0 to 7.0.1
2026-04-15 11:49:37 +02:00
Sebastiaan van Stijn 164ec8c494 Merge pull request #422 from docker/dependabot/github_actions/actions/setup-go-6.4.0
build(deps): bump actions/setup-go from 6.3.0 to 6.4.0
2026-04-15 11:48:45 +02:00
dependabot[bot] defdb5e2f5 build(deps): bump actions/setup-go from 6.3.0 to 6.4.0
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6.3.0 to 6.4.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/4b73464bb391d4059bd26b0524d20df3927bd417...4a3601121dd01d1626a1e23e37211e3254c1c06c)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: 6.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-15 09:43:51 +00:00
dependabot[bot] 28e11f3745 build(deps): bump actions/upload-artifact from 7.0.0 to 7.0.1
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/bbbca2ddaa5d8feaa63e36b76fdaad77386f024f...043fb46d1a93c77aae656e7c1c64a875d1fc6a0a)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-15 09:43:47 +00:00
Sebastiaan van Stijn e3d1da694f Merge pull request #419 from docker/dependabot/github_actions/actions/github-script-9
build(deps): bump actions/github-script from 8 to 9
2026-04-14 23:26:08 +02:00
Sebastiaan van Stijn 98a1b9ce53 Merge pull request #413 from docker/dependabot/github_actions/docker/bake-action-7
build(deps): bump docker/bake-action from 6 to 7
2026-04-14 23:25:31 +02:00
Sebastiaan van Stijn ca21698edc Merge pull request #418 from docker/dependabot/github_actions/codecov/codecov-action-6
build(deps): bump codecov/codecov-action from 5 to 6
2026-04-14 23:17:01 +02:00
dependabot[bot] 300c1b491f build(deps): bump docker/bake-action from 6 to 7
Bumps [docker/bake-action](https://github.com/docker/bake-action) from 6 to 7.
- [Release notes](https://github.com/docker/bake-action/releases)
- [Commits](https://github.com/docker/bake-action/compare/v6...v7)

---
updated-dependencies:
- dependency-name: docker/bake-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-14 21:16:09 +00:00
Sebastiaan van Stijn 14b6d371c9 Merge pull request #420 from docker/dependabot/github_actions/softprops/action-gh-release-3.0.0
build(deps): bump softprops/action-gh-release from 2.5.0 to 3.0.0
2026-04-14 23:13:27 +02:00
dependabot[bot] bfd43cacbb build(deps): bump codecov/codecov-action from 5 to 6
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5 to 6.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-14 21:12:32 +00:00
dependabot[bot] 7b43509f5b build(deps): bump actions/github-script from 8 to 9
Bumps [actions/github-script](https://github.com/actions/github-script) from 8 to 9.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v8...v9)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: '9'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-14 21:12:31 +00:00
Sebastiaan van Stijn 5ad51ee4a4 Merge pull request #417 from thaJeztah/pin_actions
ci: pin actions by sha
2026-04-14 23:11:29 +02:00
dependabot[bot] 5b6a1880fa build(deps): bump softprops/action-gh-release from 2.5.0 to 3.0.0
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.5.0 to 3.0.0.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/a06a81a03ee405af7f2048a818ed3f03bbf83c7b...b4309332981a82ec1c5618f44dd2e27cc8bfbfda)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-13 10:33:46 +00:00
Sebastiaan van Stijn 29038b4df4 ci: pin actions by sha
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-03-25 20:24:38 +01:00
Sebastiaan van Stijn 955f6c518d Merge pull request #414 from thaJeztah/update_go1.25.8
update to go1.25.8
2026-03-10 17:30:11 +01:00
Sebastiaan van Stijn 0202e5a960 update to go1.25.8
go1.25.8 (released 2026-03-05) includes security fixes to the html/template,
net/url, and os packages, as well as bug fixes to the go command, the compiler,
and the os package. See the Go 1.25.8 milestone on our issue tracker for details.

- 1.25.8 https://github.com/golang/go/issues?q=milestone%3AGo1.25.8+label%3ACherryPickApproved
- diff: https://github.com/golang/go/compare/go1.25.7...go1.25.8
- 1.26.1 https://github.com/golang/go/issues?q=milestone%3AGo1.26.1+label%3ACherryPickApproved
- diff: https://github.com/golang/go/compare/go1.26.0...go1.26.1

---

We have just released Go versions 1.26.1 and 1.25.8, minor point releases.

These releases include 5 security fixes following the security policy:

crypto/x509: incorrect enforcement of email constraints

- When verifying a certificate chain which contains a certificate containing
  multiple email address constraints (composed of the full email address) which
  share common local portions (the portion of the address before the '@'
  character) but different domain portions (the portion of the address after the
  '@' character), these constraints will not be properly applied, and only the
  last constraint will be considered.

  This can allow certificates in the chain containing email addresses which are
  either not permitted or excluded by the relevant constraints to be returned by
  calls to Certificate.Verify. Since the name constraint checks happen after chain
  building is complete, this only applies to certificate chains which chain to
  trusted roots (root certificates either in VerifyOptions.Roots or in the system
  root certificate pool), requiring a trusted CA to issue certificates containing
  either not permitted or excluded email addresses.

  This issue only affects Go 1.26.

  Thanks to Jakub Ciolek for reporting this issue.

  This is CVE-2026-27137 and Go issue https://go.dev/issue/77952.

- crypto/x509: panic in name constraint checking for malformed certificates

  Certificate verification can panic when a certificate in the chain has an empty
  DNS name and another certificate in the chain has excluded name constraints.
  This can crash programs that are either directly verifying X.509 certificate
  chains, or those that use TLS.

  Since the name constraint checks happen after chain building is complete, this
  only applies to certificate chains which chain to trusted roots (root
  certificates either in VerifyOptions.Roots or in the system root certificate
  pool), requiring a trusted CA to issue certificates containing malformed DNS
  names.

  This issue only affects Go 1.26.

  Thanks to Jakub Ciolek for reporting this issue.

  This is CVE-2026-27138 and Go issue https://go.dev/issue/77953.

- html/template: URLs in meta content attribute actions are not escaped

  Actions which insert URLs into the content attribute of HTML meta tags are not
  escaped. This can allow XSS if the meta tag also has an http-equiv attribute
  with the value "refresh".

  A new GODEBUG setting has been added, htmlmetacontenturlescape, which can be
  used to disable escaping URLs in actions in the meta content attribute which
  follow "url=" by setting htmlmetacontenturlescape=0.

  This is CVE-2026-27142 and Go issue https://go.dev/issue/77954.

- net/url: reject IPv6 literal not at start of host

  The Go standard library function net/url.Parse insufficiently
  validated the host/authority component and accepted some invalid URLs
  by effectively treating garbage before an IP-literal as ignorable.
  The function should have rejected this as invalid.

  To prevent this behavior, net/url.Parse now rejects IPv6 literals
  that do not appear at the start of the host subcomponent of a URL.

  Thanks to Masaki Hara (https://github.com/qnighy) of Wantedly.

  This is CVE-2026-25679 and Go issue https://go.dev/issue/77578.

- os: FileInfo can escape from a Root

  On Unix platforms, when listing the contents of a directory using
  File.ReadDir or File.Readdir the returned FileInfo could reference
  a file outside of the Root in which the File was opened.

  The contents of the FileInfo were populated using the lstat system
  call, which takes the path to the file as a parameter. If a component
  of the full path of the file described by the FileInfo is replaced with
  a symbolic link, the target of the lstat can be directed to another
  location on the filesystem.

  The impact of this escape is limited to reading metadata provided by
  lstat from arbitrary locations on the filesystem. This could be used
  to probe for the presence or absence of files as well as gleaning
  metadata like file sizes, but does not permit reading or writing files
  outside the root.

  The FileInfo is now populated using fstatat.

  Thank you to Miloslav Trmač of Red Hat for reporting this issue.

  This is CVE-2026-27139 and Go issue https://go.dev/issue/77827.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-03-06 13:58:18 +01:00
CrazyMax 4e2b0ff14f Merge pull request #408 from docker/dependabot/github_actions/actions/upload-artifact-7
build(deps): bump actions/upload-artifact from 6 to 7
2026-03-05 11:15:50 +01:00
CrazyMax 8fe8d458f7 Merge pull request #409 from docker/dependabot/github_actions/crazy-max/ghaction-import-gpg-7
build(deps): bump crazy-max/ghaction-import-gpg from 6 to 7
2026-03-05 11:15:27 +01:00
CrazyMax af758c414c Merge pull request #411 from docker/dependabot/github_actions/docker/setup-buildx-action-4
build(deps): bump docker/setup-buildx-action from 3 to 4
2026-03-05 11:15:06 +01:00
dependabot[bot] dc6f4f5cb9 build(deps): bump docker/setup-buildx-action from 3 to 4
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3 to 4.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-05 09:43:23 +00:00
CrazyMax 4e68cd824e Merge pull request #410 from docker/dependabot/github_actions/docker/setup-qemu-action-4
build(deps): bump docker/setup-qemu-action from 3 to 4
2026-03-04 11:02:41 +01:00
dependabot[bot] d520877610 build(deps): bump docker/setup-qemu-action from 3 to 4
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3 to 4.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 09:43:23 +00:00
dependabot[bot] f0e4adbf36 build(deps): bump crazy-max/ghaction-import-gpg from 6 to 7
Bumps [crazy-max/ghaction-import-gpg](https://github.com/crazy-max/ghaction-import-gpg) from 6 to 7.
- [Release notes](https://github.com/crazy-max/ghaction-import-gpg/releases)
- [Commits](https://github.com/crazy-max/ghaction-import-gpg/compare/v6...v7)

---
updated-dependencies:
- dependency-name: crazy-max/ghaction-import-gpg
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-03 09:43:35 +00:00
dependabot[bot] bf6137df6b build(deps): bump actions/upload-artifact from 6 to 7
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-27 09:43:12 +00:00
Sebastiaan van Stijn 2b4e08bca3 Merge pull request #407 from thaJeztah/bump_go1.25.7
update to go1.25.7
2026-02-05 13:23:39 +01:00
Sebastiaan van Stijn 62deeb49c1 update to go1.25.7
go1.25.7 (released 2026-02-04) includes security fixes to the go command
and the crypto/tls package, as well as bug fixes to the compiler and the
crypto/x509 package. See the Go 1.25.7 milestone on our issue tracker for
details:
https://github.com/golang/go/issues?q=milestone%3AGo1.25.7+label%3ACherryPickApproved

full diff: https://github.com/golang/go/compare/go1.25.6...go1.25.7

From the security mailing list:

> Hello gophers,
>
> We have just released Go versions 1.25.7 and 1.24.13, minor point releases.
>
> These releases include 2 security fixes following the security policy:
>
> - cmd/cgo: remove user-content from doc strings in cgo ASTs
>
>   A discrepancy between how Go and C/C++ comments
>   were parsed allowed for code smuggling into the
>   resulting cgo binary.
>
>   To prevent this behavior, the cgo compiler
>   will no longer parse user-provided doc
>   comments.
>
>   Thank you to RyotaK (https://ryotak.net) of
>   GMO Flatt Security Inc. for reporting this issue.
>
>   This is CVE-2025-61732 and https://go.dev/issue/76697.
>
> - crypto/tls: unexpected session resumption when using Config.GetConfigForClient
>
>   Config.GetConfigForClient is documented to use the original Config's session
>   ticket keys unless explicitly overridden. This can cause unexpected behavior if
>   the returned Config modifies authentication parameters, like ClientCAs: a
>   connection initially established with the parent (or a sibling) Config can be
>   resumed, bypassing the modified authentication requirements.
>
>   If ClientAuth is VerifyClientCertIfGiven or RequireAndVerifyClientCert (on the
>   server) or InsecureSkipVerify is false (on the client), crypto/tls now checks
>   that the root of the previously-verified chain is still in ClientCAs/RootCAs
>   when resuming a connection.
>
>   Go 1.26 Release Candidate 2, Go 1.25.6, and Go 1.24.12 had fixed a similar issue
>   related to session ticket keys being implicitly shared by Config.Clone. Since
>   this fix is broader, the Config.Clone behavior change has been reverted.
>
>   Note that VerifyPeerCertificate still behaves as documented: it does not apply
>   to resumed connections. Applications that use Config.GetConfigForClient or
>   Config.Clone and do not wish to blindly resume connections established with the
>   original Config must use VerifyConnection instead (or SetSessionTicketKeys or
>   SessionTicketsDisabled).
>
>   Thanks to Coia Prant (github.com/rbqvq) for reporting this issue.
>
>   This updates CVE-2025-68121 and Go issue https://go.dev/issue/77217.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-02-05 13:13:02 +01:00
Paweł Gronowski 6ca9924445 Merge pull request #406 from thaJeztah/bump_go
update to go1.25.6
2026-01-19 13:51:23 +00:00
Sebastiaan van Stijn 806dc5f678 update to go1.25.6
This releases includes 6 security fixes following the security policy:

- archive/zip: denial of service when parsing arbitrary ZIP archives

    archive/zip used a super-linear file name indexing algorithm that is invoked the first time a file in an archive is opened. This can lead to a denial of service when consuming a maliciously constructed ZIP archive.

    Thanks to Thanks to Jakub Ciolek for reporting this issue.

    This is CVE-2025-61728 and Go issue https://go.dev/issue/77102.

- net/http: memory exhaustion in Request.ParseForm

    When parsing a URL-encoded form net/http may allocate an unexpected amount of
    memory when provided a large number of key-value pairs. This can result in a
    denial of service due to memory exhaustion.

    Thanks to jub0bs for reporting this issue.

    This is CVE-2025-61726 and Go issue https://go.dev/issue/77101.

- crypto/tls: Config.Clone copies automatically generated session ticket keys, session resumption does not account for the expiration of full certificate chain

    The Config.Clone methods allows cloning a Config which has already been passed
    to a TLS function, allowing it to be mutated and reused.

    If Config.SessionTicketKey has not been set, and Config.SetSessionTicketKeys has
    not been called, crypto/tls will generate random session ticket keys and
    automatically rotate them. Config.Clone would copy these automatically generated
    keys into the returned Config, meaning that the two Configs would share session
    ticket keys, allowing sessions created using one Config could be used to resume
    sessions with the other Config. This can allow clients to resume sessions even
    though the Config may be configured such that they should not be able to do so.

    Config.Clone no longer copies the automatically generated session ticket keys.
    Config.Clone still copies keys which are explicitly provided, either by setting
    Config.SessionTicketKey or by calling Config.SetSessionTicketKeys.

    This issue was discoverd by the Go Security team while investigating another
    issue reported by Coia Prant (github.com/rbqvq).

    Additionally, on the server side only the expiration of the leaf certificate, if
    one was provided during the initial handshake, was checked when considering if a
    session could be resumed. This allowed sessions to be resumed if an intermediate
    or root certificate in the chain had expired.

    Session resumption now takes into account of the full chain when determining if
    the session can be resumed.

    Thanks to Coia Prant (github.com/rbqvq) for reporting this issue.

    This is CVE-2025-68121 and Go issue https://go.dev/issue/77113.

- cmd/go: bypass of flag sanitization can lead to arbitrary code execution

    Usage of 'CgoPkgConfig' allowed execution of the pkg-config
    binary with flags that are not explicitly safe-listed.

    To prevent this behavior, compiler flags resulting from usage
    of 'CgoPkgConfig' are sanitized prior to invoking pkg-config.

    Thank you to RyotaK (https://ryotak.net) of GMO Flatt Security Inc.
    for reporting this issue.

    This is CVE-2025-61731 and go.dev/issue/77100.

- cmd/go: unexpected code execution when invoking toolchain

    The Go toolchain supports multiple VCS which are used retrieving modules and
    embedding build information into binaries.

    On systems with Mercurial installed (hg) downloading modules (e.g. via go get or
    go mod download) from non-standard sources (e.g. custom domains) can cause
    unexpected code execution due to how external VCS commands are constructed.

    On systems with Git installed, downloading and building modules with malicious
    version strings could allow an attacker to write to arbitrary files on the
    system the user has access to. This can only be triggered by explicitly
    providing the malicious version strings to the toolchain, and does not affect
    usage of @latest or bare module paths.

    The toolchain now uses safer VCS options to prevent misinterpretation of
    untrusted inputs. In addition, the toolchain now disallows module version
    strings prefixed with a "-" or "/" character.

    Thanks to splitline (@splitline) from DEVCORE Research Team for reporting this
    issue.

    This is CVE-2025-68119 and Go issue https://go.dev/issue/77099.

- crypto/tls: handshake messages may be processed at the incorrect encryption level

    During the TLS 1.3 handshake if multiple messages are sent in records that span
    encryption level boundaries (for instance the Client Hello and Encrypted
    Extensions messages), the subsequent messages may be processed before the
    encryption level changes. This can cause some minor information disclosure if a
    network-local attacker can inject messages during the handshake.

    Thanks to Coia Prant (github.com/rbqvq) for reporting this issue.

    This is CVE-2025-61730 and Go issue https://go.dev/issue/76443

View the release notes for more information:
https://go.dev/doc/devel/release#go1.25.6

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-19 14:21:10 +01:00
Sebastiaan van Stijn a7b23cd2b5 Merge pull request #405 from thaJeztah/gha_perms
gha: set default permissions, add guardrail timeouts, and update branch name (master -> main)
2026-01-09 11:41:43 +01:00
Sebastiaan van Stijn 178a3a4e57 gha: update master branch to main
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-09 09:43:50 +01:00
Sebastiaan van Stijn f5fd80af0f gha: add guardrails timeouts to jobs
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-09 09:35:19 +01:00
Sebastiaan van Stijn ae163ade7b gha: set "read" permissions as default
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-09 09:28:23 +01:00
Sebastiaan van Stijn b871f76540 Merge pull request #404 from thaJeztah/rm_noninteractive
Dockerfile: remove redundant DEBIAN_FRONTEND=noninteractive
2026-01-08 17:44:32 +01:00
Sebastiaan van Stijn 50c1460bf5 Dockerfile: remove redundant DEBIAN_FRONTEND=noninteractive
This should no longer be needed for current versions of Debian
and Ubuntu.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-08 13:06:40 +01:00
Sebastiaan van Stijn aecf6e5780 Merge pull request #402 from thaJeztah/bump_golangci_lint
Dockerfile: update golangci-lint to v2.8
2026-01-08 13:06:09 +01:00
Sebastiaan van Stijn ecf6c1ccc7 Merge pull request #399 from ameya-keskar/bump_go_1.25.5
update to go1.25.5
2026-01-08 12:40:22 +01:00
Ameya Keskar b844409a12 update to go1.25.5
- Update Go version to v1.25.5 in build workflow
- Update GO_VERSION to 1.25.5 in Dockerfile
- Update GO_VERSION to 1.25.5

Signed-off-by: Ameya Keskar <55844298+ameya-keskar@users.noreply.github.com>
2026-01-08 11:59:16 +01:00
Sebastiaan van Stijn 9df2c7782a Merge pull request #401 from thaJeztah/bump_ubuntu
gha: update some actions to ubuntu 24.04
2026-01-08 11:57:23 +01:00
Sebastiaan van Stijn 7a15b77bcb Dockerfile: update golangci-lint to v2.8
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-08 11:55:17 +01:00
Sebastiaan van Stijn 81f7ebebfd gha: update some actions to ubuntu 24.04
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-01-08 11:49:17 +01:00
Sebastiaan van Stijn 3f97cf3ce3 Merge pull request #398 from docker/dependabot/github_actions/actions/upload-artifact-6
build(deps): bump actions/upload-artifact from 4 to 6
2026-01-08 11:28:12 +01:00
Sebastiaan van Stijn 8b5e6dffc6 Merge pull request #397 from docker/dependabot/github_actions/softprops/action-gh-release-2.5.0
build(deps): bump softprops/action-gh-release from 2.4.1 to 2.5.0
2026-01-08 11:27:39 +01:00
Sebastiaan van Stijn 4741f33d28 Merge pull request #395 from docker/dependabot/github_actions/actions/checkout-6
build(deps): bump actions/checkout from 5 to 6
2026-01-08 11:25:55 +01:00
dependabot[bot] 78303955b8 build(deps): bump actions/upload-artifact from 4 to 6
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 09:09:36 +00:00
dependabot[bot] 9b0c242b5c build(deps): bump softprops/action-gh-release from 2.4.1 to 2.5.0
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.4.1 to 2.5.0.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/6da8fa9354ddfdc4aeace5fc48d7f679b5214090...a06a81a03ee405af7f2048a818ed3f03bbf83c7b)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-02 09:09:45 +00:00
dependabot[bot] 057ed818a9 build(deps): bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-21 09:09:36 +00:00
Sebastiaan van Stijn b7a754b9ff Merge pull request #392 from thaJeztah/bump_go_1.25.2
update to go1.25.2
2025-10-13 14:20:23 +02:00
Sebastiaan van Stijn 62777f0887 Merge pull request #391 from docker/dependabot/github_actions/softprops/action-gh-release-2.4.1
build(deps): bump softprops/action-gh-release from 2.3.3 to 2.4.1
2025-10-13 13:24:04 +02:00
Sebastiaan van Stijn 9d04e49561 update to go1.25.2
This minor release includes 10 security fixes following the security policy:

- net/mail: excessive CPU consumption in ParseAddress

    The ParseAddress function constructed domain-literal address components through repeated string concatenation. When parsing large domain-literal components, this could cause excessive CPU consumption.

    Thanks to Philippe Antoine (Catena cyber) for reporting this issue.

    This is CVE-2025-61725 and Go issue https://go.dev/issue/75680.

- crypto/x509: quadratic complexity when checking name constraints

    Due to the design of the name constraint checking algorithm, the processing time
    of some inputs scales non-linearly with respect to the size of the certificate.

    This affects programs which validate arbitrary certificate chains.

    Thanks to Jakub Ciolek for reporting this issue.

    This is CVE-2025-58187 and Go issue https://go.dev/issue/75681.

- crypto/tls: ALPN negotiation errors can contain arbitrary text

    The crypto/tls conn.Handshake method returns an error on the server-side when
    ALPN negotation fails which can contain arbitrary attacker controlled
    information provided by the client-side of the connection which is not escaped.

    This affects programs which log these errors without any additional form of
    sanitization, and may allow injection of attacker controlled information into
    logs.

    Thanks to National Cyber Security Centre Finland for reporting this issue.

    This is CVE-2025-58189 and Go issue https://go.dev/issue/75652.

- encoding/pem: quadratic complexity when parsing some invalid inputs

    Due to the design of the PEM parsing function, the processing time for some
    inputs scales non-linearly with respect to the size of the input.

    This affects programs which parse untrusted PEM inputs.

    Thanks to Jakub Ciolek for reporting this issue.

    This is CVE-2025-61723 and Go issue https://go.dev/issue/75676.

- net/url: insufficient validation of bracketed IPv6 hostnames

    The Parse function permitted values other than IPv6 addresses to be included in square brackets within the host component of a URL. RFC 3986 permits IPv6 addresses to be included within the host component, enclosed within square brackets. For example: "http://[::1]/". IPv4 addresses and hostnames must not appear within square brackets. Parse did not enforce this requirement.

    Thanks to Enze Wang, Jingcheng Yang and Zehui Miao of Tsinghua University for reporting this issue.

    This is CVE-2025-47912 and Go issue https://go.dev/issue/75678.

- encoding/asn1: pre-allocating memory when parsing DER payload can cause memory exhaustion

    When parsing DER payloads, memories were being allocated prior to fully validating the payloads.
    This permits an attacker to craft a big empty DER payload to cause memory exhaustion in functions such as asn1.Unmarshal, x509.ParseCertificateRequest, and ocsp.ParseResponse.

    Thanks to Jakub Ciolek for reporting this issue.

    This is CVE-2025-58185 and Go issue https://go.dev/issue/75671.

- net/http: lack of limit when parsing cookies can cause memory exhaustion

    Despite HTTP headers having a default limit of 1 MB, the number of cookies that can be parsed did not have a limit.
    By sending a lot of very small cookies such as "a=;", an attacker can make an HTTP server allocate a large amount of structs, causing large memory consumption.

    net/http now limits the number of cookies accepted to 3000, which can be adjusted using the httpcookiemaxnum GODEBUG option.

    Thanks to jub0bs for reporting this issue.

    This is CVE-2025-58186 and Go issue https://go.dev/issue/75672.

- crypto/x509: panic when validating certificates with DSA public keys

    Validating certificate chains which contain DSA public keys can cause programs
    to panic, due to a interface cast that assumes they implement the Equal method.

    This affects programs which validate arbitrary certificate chains.

    Thanks to Jakub Ciolek for reporting this issue.

    This is CVE-2025-58188 and Go issue https://go.dev/issue/75675.

- archive/tar: unbounded allocation when parsing GNU sparse map

    tar.Reader did not set a maximum size on the number of sparse region data blocks in GNU tar pax 1.0 sparse files. A maliciously-crafted archive containing a large number of sparse regions could cause a Reader to read an unbounded amount of data from the archive into memory. When reading from a compressed source, a small compressed input could result in large allocations.

    Thanks to Harshit Gupta (Mr HAX) - https://www.linkedin.com/in/iam-harshit-gupta/ for reporting this issue.

    This is CVE-2025-58183 and Go issue https://go.dev/issue/75677.

- net/textproto: excessive CPU consumption in Reader.ReadResponse

    The Reader.ReadResponse function constructed a response string through
    repeated string concatenation of lines. When the number of lines in a response is large,
    this could cause excessive CPU consumption.

    Thanks to Jakub Ciolek for reporting this issue.

    This is CVE-2025-61724 and Go issue https://go.dev/issue/75716.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-13 13:22:38 +02:00
dependabot[bot] bc131d729d build(deps): bump softprops/action-gh-release from 2.3.3 to 2.4.1
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.3.3 to 2.4.1.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/6cbd405e2c4e67a21c47fa9e383d020e4e28b836...6da8fa9354ddfdc4aeace5fc48d7f679b5214090)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.4.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 09:27:58 +00:00
Sebastiaan van Stijn 84c3413e0e Merge pull request #387 from thaJeztah/bump_go1.25
update to go1.25.1
2025-10-02 21:54:13 +02:00
Sebastiaan van Stijn fcb0b664b5 update to go1.25.1
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-02 21:49:20 +02:00
Sebastiaan van Stijn cf4e41fbb0 Merge pull request #388 from thaJeztah/bump_wincred
vendor: github.com/danieljoos/wincred v1.2.3
2025-10-02 21:48:59 +02:00
Sebastiaan van Stijn 53f7bdc3fa vendor: github.com/danieljoos/wincred v1.2.3
fix unsafe uintptr usage to be GC-safe on go1.25

full diff: https://github.com/danieljoos/wincred/compare/v1.2.2...v1.2.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-02 21:43:59 +02:00
Sebastiaan van Stijn d4602cd917 Merge pull request #249 from crazy-max/upd-dockerfile
Dockerfile: merge build stages
2025-10-01 16:45:53 +02:00
CrazyMax ae84c25786 Dockerfile: merge build stages
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-10-01 16:34:48 +02:00
Sebastiaan van Stijn 2adf3cf9aa Merge pull request #383 from thaJeztah/bump_go_deps
update to go1.24.7, xx v1.7.0
2025-10-01 16:29:36 +02:00
Sebastiaan van Stijn 1fdce4c733 Dockerfile: update xx to v1.7.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-01 16:24:12 +02:00
Sebastiaan van Stijn 962a779645 update to go1.24.7
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-01 16:23:59 +02:00
Sebastiaan van Stijn ec5efac3ca Merge pull request #386 from thaJeztah/bump_golangci_lint
Dockerfile: update golangci-lint to v2.5
2025-10-01 16:20:44 +02:00
Sebastiaan van Stijn 8154b98959 Merge pull request #385 from thaJeztah/bump_deb
deb: Dockerfile: update to debian bookworm, ubuntu jammy (22.04)
2025-10-01 16:20:25 +02:00
CrazyMax d075f3cecc Merge pull request #379 from docker/dependabot/github_actions/softprops/action-gh-release-2.3.3
build(deps): bump softprops/action-gh-release from 2.3.2 to 2.3.3
2025-10-01 16:15:13 +02:00
Sebastiaan van Stijn fdddb02817 deb: Dockerfile: use ubuntu:jammy (22.04 LTS)
ubuntu 20.04 reached end of standard support;
https://ubuntu.com/blog/ubuntu-20-04-lts-end-of-life-standard-support-is-coming-to-an-end-heres-how-to-prepare

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-01 15:56:28 +02:00
Sebastiaan van Stijn c07513a69d deb: Dockerfile: update to golang bookworm
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-01 15:56:28 +02:00
Sebastiaan van Stijn 4142982fb8 Dockerfile: update golangci-lint to v2.5
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-01 15:55:19 +02:00
Sebastiaan van Stijn 860f1459e3 pass: fix QF1001 (staticcheck)
pass/pass_test.go:86:6: QF1001: could apply De Morgan's law (staticcheck)
            if !(strings.HasSuffix(server, "2376/v1") || strings.HasSuffix(server, "2375/v1")) {
               ^
    pass/pass_test.go:89:6: QF1001: could apply De Morgan's law (staticcheck)
            if !(username == "foo" || username == "bar") {
               ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-01 15:55:19 +02:00
Sebastiaan van Stijn d378d46316 Merge pull request #384 from thaJeztah/bump_distros
gha: add macos-15-intel, remove macos-13 (deprecated)
2025-10-01 15:53:03 +02:00
Sebastiaan van Stijn 4c97a761df Merge pull request #378 from docker/dependabot/github_actions/actions/github-script-8
build(deps): bump actions/github-script from 7 to 8
2025-10-01 15:22:51 +02:00
Sebastiaan van Stijn b61abf1cb8 Merge pull request #377 from docker/dependabot/github_actions/actions/setup-go-6
build(deps): bump actions/setup-go from 5 to 6
2025-10-01 15:22:19 +02:00
Sebastiaan van Stijn 85841ea0ce Merge pull request #376 from docker/dependabot/github_actions/actions/checkout-5
build(deps): bump actions/checkout from 4 to 5
2025-10-01 15:21:38 +02:00
Sebastiaan van Stijn c32e697324 gha: add macos-15-intel, remove macos-13 (deprecated)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-01 15:11:20 +02:00
dependabot[bot] d770c60191 build(deps): bump softprops/action-gh-release from 2.3.2 to 2.3.3
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.3.2 to 2.3.3.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/72f2c25fcb47643c292f7107632f7a47c1df5cd8...6cbd405e2c4e67a21c47fa9e383d020e4e28b836)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.3.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 09:15:45 +00:00
dependabot[bot] 5095e43ecf build(deps): bump actions/github-script from 7 to 8
Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 8.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-05 09:08:21 +00:00
dependabot[bot] 00313838c6 build(deps): bump actions/setup-go from 5 to 6
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5 to 6.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-04 13:01:52 +00:00
dependabot[bot] bcf656656f build(deps): bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-12 18:09:48 +00:00
Sebastiaan van Stijn fd27520bbd Merge pull request #375 from austinvazquez/update-golang-1.23.12
update to go1.23.12
2025-08-11 16:01:13 +02:00
Austin Vazquez 4849c2328b update to go1.23.12
Signed-off-by: Austin Vazquez <austin.vazquez@docker.com>
2025-08-08 10:54:56 -05:00
Austin Vazquez 2e8005f3a7 Merge pull request #373 from docker/dependabot/github_actions/softprops/action-gh-release-2.3.2
build(deps): bump softprops/action-gh-release from 2.2.1 to 2.3.2
2025-08-08 08:38:17 -07:00
dependabot[bot] 5d4d5150ae build(deps): bump softprops/action-gh-release from 2.2.1 to 2.3.2
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.2.1 to 2.3.2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda...72f2c25fcb47643c292f7107632f7a47c1df5cd8)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.3.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-11 09:52:55 +00:00
Albin Kerouanton f9d3010165 Merge pull request #367 from akerouanton/osxkeychain-set-atyp
osxkeychain: store: add atyp attribute
2025-03-14 12:52:36 +01:00
Albin Kerouanton e7bd3957ae osxkeychain: store: add atyp attribute
Prior to v0.9.0, the osxkeychain creds helper was adding the `atyp`
attribute (ie. authentication type) to its credentials. It was also
specifying this attribute when querying the keychain for credentials.

Since v0.9.0, we don't set this attribute anymore. So, if a credential
is stored with v0.9.0+ and then queried with a v0.8.2 helper, the
atyp attribute will be missing and the credential won't be found.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-03-14 12:45:31 +01:00
Albin Kerouanton cfd6d21216 Merge pull request #366 from thaJeztah/gha_bump_ubuntu
gha: add ubuntu 24.04, remove 20.04
2025-03-04 17:29:11 +01:00
Sebastiaan van Stijn ab29a6c87b gha: add ubuntu 24.04, remove 20.04
Github is phasing out Ubuntu 20.04, and currently is doing brownouts;
https://github.com/actions/runner-images/issues/11101

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-04 17:23:42 +01:00
Sebastiaan van Stijn 576efaa084 Merge pull request #363 from akerouanton/retract-v0.9.1
go.mod: retract v0.9.1
2025-03-04 17:21:35 +01:00
Sebastiaan van Stijn 9d6cdddf25 Merge pull request #364 from akerouanton/fix-regression-v0.9.0
osxkeychain: list: return full server URIs
2025-03-04 13:42:33 +01:00
Albin Kerouanton d8e34f8743 osxkeychain: tests: uncleaned paths are preserved
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-03-04 11:43:16 +01:00
Albin Kerouanton b1d5bf0326 osxkeychain: list: return full server URIs
Commit 4cdcdc2 changed the format of `list` output. Before that commit,
the json keys were containing full URIs (scheme://host/path[:port]),
but afterward, the keys were only containing the path component.

With this commit, the `list` operation now returns full URIs (fixing the
regression), and also fixes the malformed URIs issue when a port is
specified (introduced by 19ec1c3, and affecting >=v0.4.2,<v0.9.0).

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-03-04 11:20:57 +01:00
Albin Kerouanton 50b162c340 go.mod: retract v0.9.1
`osxkeychain` in v0.9.1 still doesn't list credentials as prior versions
did. We're retracting this version too.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-02-28 19:40:33 +01:00
Albin Kerouanton 833d2c334f Merge pull request #362 from akerouanton/retract-v0.9.0
go.mod: retract v0.9.0
2025-02-28 13:10:46 +01:00
Albin Kerouanton 9651bf7802 go.mod: retract v0.9.0
Commit 4cdcdc2 introduced two regressions in the `osxkeychain`
credential helper,  on `list` and `get` operations. These were addressed
in:

- Commit c7514a0: osxkeychain: list: do not error out when keychain is empty
- Commit f4cdabf: osxkeychain: store: use Apple's proto consts

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-02-28 13:05:40 +01:00
Sebastiaan van Stijn 26274da6cf Merge pull request #361 from akerouanton/fix-regressions-v0.9.0
[v0.9.0] osxkeychain: fix regressions on get and list
2025-02-28 12:51:02 +01:00
Albin Kerouanton f4cdabf916 osxkeychain: store: use Apple's proto consts
Commit 4cdcdc2 swapped consts `kSecProtocolTypeHTTPS` and
`kSecProtocolTypeHTTP` with plain-text "https" and "http" strings.

This is causing a regression where credentials stored with prior
versions (< v0.9.0) can't be fetched anymore.

Unfortunately we can't just revert back to using Objective-C consts, as
these are unsigned integers that need to be converted into `CFStringRef`
and then passed to an helper like `keychain.CFStringToString`.

Although `keychain.CFStringToString` is exported, it takes a C type
`C.CFStringRef` so it's not consumable from other packages due to Cgo
restrictions:

> Cgo translates C types into equivalent unexported Go types. Because
> the translations are unexported, a Go package should not expose C
> types in its exported API: a C type used in one Go package is
> different from the same C type used in another.

We could alternatively copy `keychain.CFStringToString` into the
`osxkeychain` package, but this commit takes a simpler approach: just
hardcode the value of `kSecProtocolTypeHTTPS` and `kSecProtocolTypeHTTP`
as strings. (These consts are very unlikely to ever change since it'd
break all existing consumers.)

This is **NOT** handling backward compatibility with v0.9.0, since it
was released only 12hrs ago. So this fix won't work with credentials
created with v0.9.0.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-02-28 12:19:53 +01:00
Albin Kerouanton c7514a0999 osxkeychain: list: do not error out when keychain is empty
Commit 4cdcdc2 replaced the in-tree Objective-C code with github.com/keybase/go-keychain
and inadvertently introduced a new failure mode on the `List` operation -
it now fails when the keychain is empty.

Before:

```
$ ./bin/build/docker-credential-osxkeychain list
{}
```

After:

```
$ ./bin/build/docker-credential-osxkeychain list
credentials not found in native keychain
```

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-02-28 10:00:35 +01:00
Sebastiaan van Stijn 36a3c50452 Merge pull request #359 from thaJeztah/bump_golangci_lint
Dockerfile: update golangci-lint to v1.64.5
2025-02-28 00:13:45 +01:00
Sebastiaan van Stijn 4e957ecd1b Merge pull request #340 from thaJeztah/bump_golang_1.22.8
update to go1.23.6
2025-02-28 00:13:26 +01:00
Sebastiaan van Stijn f7f8554b4c Merge pull request #258 from The-Alchemist/patch-1
minor formatting tweaks to README
2025-02-28 00:06:58 +01:00
The Alchemist 1a77fa667f minor formatting tweaks to README
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-28 00:00:29 +01:00
Sebastiaan van Stijn 8a779f2b11 Dockerfile: update golangci-lint to v1.64.5
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-27 23:47:17 +01:00
Sebastiaan van Stijn a767624e34 update to go1.23.6
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-27 23:40:02 +01:00
Sebastiaan van Stijn a5569fbfff update to go1.22.11 (fix CVE-2024-45341, CVE-2024-45336)
go1.22.11 (released 2025-01-16) includes security fixes to the crypto/x509 and
net/http packages, as well as bug fixes to the runtime. See the Go 1.22.11
milestone on our issue tracker for details.

- https://github.com/golang/go/issues?q=milestone%3AGo1.22.11+label%3ACherryPickApproved
- full diff: https://github.com/golang/go/compare/go1.22.10...go1.22.11

Hello gophers,

We have just released Go versions 1.23.5 and 1.22.11, minor point releases.

These minor releases include 2 security fixes following the security policy:

- crypto/x509: usage of IPv6 zone IDs can bypass URI name constraints

  A certificate with a URI which has a IPv6 address with a zone ID may
  incorrectly satisfy a URI name constraint that applies to the certificate
  chain.

  Certificates containing URIs are not permitted in the web PKI, so this
  only affects users of private PKIs which make use of URIs.

  Thanks to Juho Forsén of Mattermost for reporting this issue.

  This is CVE-2024-45341 and Go issue https://go.dev/issue/71156.

- net/http: sensitive headers incorrectly sent after cross-domain redirect

  The HTTP client drops sensitive headers after following a cross-domain redirect.
  For example, a request to a.com/ containing an Authorization header which is
  redirected to b.com/ will not send that header to b.com.

  In the event that the client received a subsequent same-domain redirect, however,
  the sensitive headers would be restored. For example, a chain of redirects from
  a.com/, to b.com/1, and finally to b.com/2 would incorrectly send the Authorization
  header to b.com/2.

  Thanks to Kyle Seely for reporting this issue.

  This is CVE-2024-45336 and Go issue https://go.dev/issue/70530.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-27 23:40:02 +01:00
Albin Kerouanton 99bf48e5f8 Makefile: set CGO_LDFLAGS=-latomic on arm/v6
Compiling with Go >= 1.22 on arm/v6 is failing with the following error
message:

27.84 gcc_libinit.c:44:8: error: large atomic operation may incur significant performance penalty; the access size (4 bytes) exceeds the max lock-free size (0  bytes) [-Werror,-Watomic-alignment]

For these Go versions, we need to manually link to libatomic as arm/v6
does not support atomic intrinsics and neither the CGo, nor the C
toolchain automatically link to that library.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-02-27 23:39:54 +01:00
Sebastiaan van Stijn 1041211a6e Merge pull request #358 from thaJeztah/bump_go_keychain
vendor: github.com/keybase/go-keychain v0.0.1
2025-02-27 19:38:01 +01:00
Sebastiaan van Stijn 8c804df56c vendor: github.com/keybase/go-keychain v0.0.1
- removes pkg/errors as dependency

full diff: https://github.com/keybase/go-keychain/compare/7f41edfa9689...v0.0.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-27 19:19:36 +01:00
Sebastiaan van Stijn a7974e91c5 Merge pull request #282 from crazy-max/darwin-go-keychain
osxkeychain: switch to github.com/keybase/go-keychain
2025-02-27 18:35:34 +01:00
CrazyMax ffe5a9835c ci: add macOS-15 to test matrix
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2025-02-27 14:39:23 +01:00
CrazyMax e79a8203ca osxkeychain: TestOSXKeychainHelperRetrieveAliases print err
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2025-02-27 14:39:23 +01:00
CrazyMax 4cdcdc29eb osxkeychain: switch to github.com/keybase/go-keychain
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2025-02-27 14:39:22 +01:00
CrazyMax 8438667191 Merge pull request #357 from thaJeztah/bump_wincred
vendor:  github.com/danieljoos/wincred v1.2.2
2025-02-27 14:38:31 +01:00
Sebastiaan van Stijn fc66c3f02c Merge pull request #356 from WanzenBug/master
secretservice: fix null derefence on locked collections
2025-02-27 14:18:14 +01:00
Sebastiaan van Stijn 7810dc4db9 vendor: github.com/danieljoos/wincred v1.2.2
- Bump golang.org/x/sys from 0.17.0 to 0.20.0
- Bump github.com/stretchr/testify from 1.8.4 to 1.9.0
- Added missing constant to sys_unsupported.go to avoid breaking builds on non-Windows platforms.

full diff: https://github.com/danieljoos/wincred/compare/v1.2.1...v1.2.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-02-27 13:07:17 +01:00
Moritz "WanzenBug" Wanzenböck 28e893e56d secretservice: fix null derefence on locked collections
secret_item_get_secret() may return null if an item is locked or not loaded.
While we set SECRET_SEARCH_LOAD_SECRETS and SECRET_SEARCH_UNLOCK, there may
still be locked items, for example the user may refuse the unlock request.

So we still need to check if the secret data is NULL before we can try to
reference it.

Signed-off-by: Moritz "WanzenBug" Wanzenböck <moritz@wanzenbug.xyz>
2025-02-19 15:56:07 +01:00
Sebastiaan van Stijn 1161e9c157 Merge pull request #353 from thaJeztah/bump_xx
Dockerfile: bump XX_VERSION to 1.6.1
2025-01-20 17:37:43 +01:00
Sebastiaan van Stijn a17e9a013b Dockerfile: bump XX_VERSION to 1.6.1
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-01-20 16:54:10 +01:00
Sebastiaan van Stijn fe0e8e3a01 Merge pull request #324 from thaJeztah/carry_207_friendlier_labels
Set a better displaylabel for secretservice
2025-01-20 16:35:26 +01:00
Hugo Osvaldo Barrera c2ca986943 Set a better displaylabel for secretservice
Secretservice entries have a "label". This is intended to be a
human-readable description. It's actually called "Description" in UIs
like seahorse, and the listing of existing secrets shows this as a name
for each one.

The entries stored by the credential helper set this to simply the
repository URL. This is rather unfriendly, since entries like
"gitlab.com" and "index.docker.io/v1" show up. Mixed in with
entries from all other applications, it's hard to figure out what
application owns each entry.

This commit changes the label used when saving entries to be something
human-readable (this is the intent of the "label" field, btw). Because
of the naming scheme, this also results in all entries being shown
together by default (since UIs tend to sort lexicographically).

New entries will now be stores as:

  Registry credentials for $REGISTRY_URL

Note that items stored by the secret service have multiple fields inside
of them. One of those fields is called "label", and is used by the
helper to filter items from the secret service. This "label" field is
entirely unrelated to the items' label. The naming is most unfortunate.

Signed-off-by: Hugo Osvaldo Barrera <hugo@barrera.io>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-01-20 16:28:06 +01:00
Sebastiaan van Stijn 407e50d36e Merge pull request #352 from crazy-max/bake-v6
ci: update bake-action to v6
2025-01-13 22:28:27 +01:00
CrazyMax 10845d8f94 Merge pull request #350 from docker/dependabot/github_actions/softprops/action-gh-release-2.2.1
build(deps): bump softprops/action-gh-release from 2.0.8 to 2.2.1
2025-01-10 11:00:25 +01:00
CrazyMax 43ae7f3412 Merge pull request #345 from docker/dependabot/github_actions/codecov/codecov-action-5
build(deps): bump codecov/codecov-action from 4 to 5
2025-01-10 11:00:08 +01:00
CrazyMax 1d9eaaa4ef ci: fix deprecated codecov-action input
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-01-10 10:55:01 +01:00
CrazyMax 7346714456 ci: update bake-action to v6
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2025-01-10 10:53:21 +01:00
dependabot[bot] ab3fc5283d build(deps): bump softprops/action-gh-release from 2.0.8 to 2.2.1
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.0.8 to 2.2.1.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/c062e08bd532815e2082a85e87e3ef29c3e6d191...c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-08 09:38:33 +00:00
dependabot[bot] 713df50a2d build(deps): bump codecov/codecov-action from 4 to 5
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4 to 5.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-15 10:06:35 +00:00
Sebastiaan van Stijn 7e7c5576ba Merge pull request #342 from thaJeztah/less_indirection
client: remove some indirection and touch-up GoDoc
2024-10-28 10:43:29 +01:00
Sebastiaan van Stijn ad253f54a5 client: remove some indirection and touch-up GoDoc
Both NewShellProgramFunc and NewShellProgramFuncWithEnv were using
createProgramCmdRedirectErr under the hood, but NewShellProgramFunc
had an extra indirection through NewShellProgramFuncWithEnv.

Make both a direct wrapper for createProgramCmdRedirectErr instead.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-25 14:41:30 +02:00
Sebastiaan van Stijn fa991bcbeb Merge pull request #338 from thaJeztah/bump_golangci_lint
Dockerfile: update golangci-lint to v1.61.0
2024-10-25 14:22:44 +02:00
Sebastiaan van Stijn db1da9da5d Merge pull request #339 from thaJeztah/bump_xx
Dockerfile: bump xx to v1.5.0
2024-10-25 13:54:32 +02:00
Sebastiaan van Stijn c23b2d6e4f Merge pull request #331 from docker/dependabot/github_actions/softprops/action-gh-release-2.0.8
build(deps): bump softprops/action-gh-release from 2.0.5 to 2.0.8
2024-10-25 13:49:14 +02:00
Sebastiaan van Stijn 13e62f3bbe Dockerfile: update golangci-lint to v1.61.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-25 13:48:02 +02:00
Sebastiaan van Stijn 2d241f3602 Dockerfile: bump xx to v1.5.0
full diff: https://github.com/tonistiigi/xx/compare/v1.4.0...v1.5.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-25 13:47:42 +02:00
Sebastiaan van Stijn 58c87f0952 Merge pull request #341 from crazy-max/update-debian
dockerfile: update debian to bookworm
2024-10-25 13:46:27 +02:00
CrazyMax dbb72e35c3 dockerfile: update debian to bookworm
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-10-25 12:41:21 +02:00
Sebastiaan van Stijn 6e5b45e59f Merge pull request #328 from docker/dependabot/github_actions/docker/bake-action-5
build(deps): bump docker/bake-action from 4 to 5
2024-10-24 21:45:11 +02:00
dependabot[bot] 2ed5a274b6 build(deps): bump softprops/action-gh-release from 2.0.5 to 2.0.8
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.0.5 to 2.0.8.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/69320dbe05506a9a39fc8ae11030b214ec2d1f87...c062e08bd532815e2082a85e87e3ef29c3e6d191)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-19 09:38:39 +00:00
dependabot[bot] 7dbcc1c472 build(deps): bump docker/bake-action from 4 to 5
Bumps [docker/bake-action](https://github.com/docker/bake-action) from 4 to 5.
- [Release notes](https://github.com/docker/bake-action/releases)
- [Commits](https://github.com/docker/bake-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: docker/bake-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 09:24:10 +00:00
Sebastiaan van Stijn 6b9df3ebb5 Merge pull request #323 from thaJeztah/pass_simplify_get
pass: Get: remove redundant stat
2024-05-10 14:15:26 +02:00
Sebastiaan van Stijn dc10c50685 Merge pull request #317 from docker/dependabot/github_actions/softprops/action-gh-release-2
build(deps): bump softprops/action-gh-release from 1 to 2
2024-05-10 14:14:16 +02:00
CrazyMax 896eb37d47 build(deps): bump softprops/action-gh-release to 2.0.5
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-05-10 11:04:52 +02:00
Sebastiaan van Stijn a14669f4ff pass: Get: remove redundant stat
listPassdir already handles "not found" errors, in which case it returns
an [empty result][1]. Previously this would return a custom error, but
since 1bb9aa3210, an empty result produces
a `errCredentialsNotFound`, making this check redundant.

This patch removes the redundant check.

[1]: https://github.com/docker/docker-credential-helpers/blob/f64d6b131b3da07a6337dc63a882e08ce541d1c1/pass/pass.go#L118-L125

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-05-10 10:28:57 +02:00
Sebastiaan van Stijn 74840b3740 Merge pull request #322 from thaJeztah/pass_dry
pass: add utilities for encoding/decoding serverURL
2024-05-10 10:23:32 +02:00
Sebastiaan van Stijn d3ef442f59 pass: add utilities for encoding/decoding serverURL
While the implementation of these is fairly trivial, we want them
to remain the same. This patch adds utilities to handle the encoding
and decoding of the server-URLs.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-05-09 16:58:34 +02:00
Sebastiaan van Stijn f64d6b131b Merge pull request #321 from thaJeztah/fix_pass_errors
pass: return correct error, and ignore empty stores on list
2024-05-09 16:44:30 +02:00
Sebastiaan van Stijn 1bb9aa3210 pass: return correct error, and ignore empty stores on list
commit 2fc2313bb1 changed the errors returned
by the pass credentials-helper to use a errCredentialsNotFound. This error
string is used in the client to distinguish a "not found" error from other
errors. (see [client.Get][1]).

However, there were additional second code-paths that returned a custom error,
which would not be detected as a "not found" error, resulting in an error when
logging out;

    Removing login credentials for https://index.docker.io/v1/
    WARNING: could not erase credentials:
    https://index.docker.io/v1/: error erasing credentials - err: exit status 1, out: `error getting credentials - err: exit status 1, out: `no usernames for https://index.docker.io/v1/``

This patch:

- updates Pass.Get() to return a errCredentialsNotFound if no credentials
  were found
- updates Pass.List() to not return an error if any of the domains had no
  credentials stored.

[1]: https://github.com/docker/docker-credential-helpers/blob/73b9e5d51f8dc9f598e08a0f2171c5d5a828e76b/client/client.go#L51-L55

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-05-09 12:19:23 +02:00
Sebastiaan van Stijn 73b9e5d51f Merge pull request #320 from thaJeztah/update_gha
update GHA to macOS-13, macOS-14, and update to go1.21.10
2024-05-08 22:48:19 +02:00
Sebastiaan van Stijn 0c43fede6d update to go1.21.10
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-05-08 15:59:23 +02:00
Sebastiaan van Stijn a941c5247f gha: update to use macos-13, macos-14
macos-11 runners are being deprecated; updating to use
macos-13 (x86) and macos-14 (arm64)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-05-08 15:56:13 +02:00
Sebastiaan van Stijn 097f945536 Merge pull request #318 from thaJeztah/pr_template
add pull-request template
2024-03-18 12:07:36 +01:00
Sebastiaan van Stijn 9272dcb90a add pull-request template
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-03-18 11:17:06 +01:00
dependabot[bot] ecacf8cdcf build(deps): bump softprops/action-gh-release from 1 to 2
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/de2c0eb89ae2a093876385947365aca7b0e5f844...d99959edae48b5ffffd7b00da66dcdb0a33a52ee)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 09:10:25 +00:00
Sebastiaan van Stijn 5be670a285 Merge pull request #316 from crazy-max/codecov-token
ci: set codecov token
2024-02-22 23:44:22 +01:00
CrazyMax 73aa8c0daa ci: set codecov token
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-02-22 23:25:37 +01:00
Sebastiaan van Stijn c23afb6c37 Merge pull request #313 from crazy-max/bump-gha
ci: update github actions to latest stable
2024-02-06 10:11:41 +01:00
CrazyMax d622133060 Merge pull request #310 from thaJeztah/update_xx
Dockerfile: update xx to v1.4.0
2024-02-06 10:05:26 +01:00
CrazyMax 12500fb753 chore: dependabot to keep gha up to date
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-02-06 10:03:08 +01:00
CrazyMax bf726a0656 ci: update github actions to latest stable
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-02-06 10:02:31 +01:00
Sebastiaan van Stijn d9632f6a08 Dockerfile: update xx to v1.4.0
full diff: https://github.com/tonistiigi/xx/compare/v1.2.1...v1.4.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-02-06 09:55:36 +01:00
42 changed files with 2135 additions and 557 deletions
+30
View File
@@ -0,0 +1,30 @@
<!--
Please make sure you've read and understood our contributing guidelines;
https://github.com/docker/cli/blob/master/CONTRIBUTING.md
** Make sure all your commits include a signature generated with `git commit -s` **
For additional information on our contributing process, read our contributing
guide https://docs.docker.com/opensource/code/
If this is a bug fix, make sure your description includes "fixes #xxxx", or
"closes #xxxx"
Please provide the following information:
-->
**- What I did**
**- How I did it**
**- How to verify it**
**- Description for the changelog**
<!--
Write a short (one line) summary that describes the changes in this
pull request for inclusion in the changelog:
-->
**- A picture of a cute animal (not mandatory but encouraged)**
+12
View File
@@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: "github-actions"
open-pull-requests-limit: 10
directory: "/"
schedule:
interval: "daily"
cooldown:
default-days: 2
labels:
- "dependencies"
- "bot"
+41 -30
View File
@@ -4,22 +4,26 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
permissions:
contents: read
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: branches:
- 'master' - 'main'
tags: tags:
- 'v*' - 'v*'
pull_request: pull_request:
env: env:
DESTDIR: ./bin DESTDIR: ./bin
GO_VERSION: 1.21.6 GO_VERSION: 1.25.9
jobs: jobs:
validate: validate:
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
timeout-minutes: 30 # guardrails timeout for the whole job
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -29,10 +33,10 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- -
name: Run name: Run
run: | run: |
@@ -40,24 +44,26 @@ jobs:
test: test:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
timeout-minutes: 30 # guardrails timeout for the whole job
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: os:
- ubuntu-24.04
- ubuntu-22.04 - ubuntu-22.04
- ubuntu-20.04 - macOS-15-intel
- macOS-11 - macOS-15
- macOS-14
- windows-2022 - windows-2022
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- -
name: Set up Go name: Set up Go
uses: actions/setup-go@v3 uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with: with:
go-version: ${{ env.GO_VERSION }} go-version: ${{ env.GO_VERSION }}
cache: true
- -
name: Install deps (ubuntu) name: Install deps (ubuntu)
if: startsWith(matrix.os, 'ubuntu-') if: startsWith(matrix.os, 'ubuntu-')
@@ -72,7 +78,7 @@ jobs:
- -
name: GPG conf name: GPG conf
if: ${{ !startsWith(matrix.os, 'windows-') }} if: ${{ !startsWith(matrix.os, 'windows-') }}
uses: actions/github-script@v6 uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
id: gpg id: gpg
with: with:
script: | script: |
@@ -89,7 +95,7 @@ jobs:
- -
name: Import GPG key name: Import GPG key
if: ${{ !startsWith(matrix.os, 'windows-') }} if: ${{ !startsWith(matrix.os, 'windows-') }}
uses: crazy-max/ghaction-import-gpg@v5 uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0
with: with:
gpg_private_key: ${{ steps.gpg.outputs.key }} gpg_private_key: ${{ steps.gpg.outputs.key }}
passphrase: ${{ steps.gpg.outputs.passphrase }} passphrase: ${{ steps.gpg.outputs.passphrase }}
@@ -107,22 +113,21 @@ jobs:
shell: bash shell: bash
- -
name: Upload coverage name: Upload coverage
uses: codecov/codecov-action@v3 uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
with: with:
file: ${{ env.DESTDIR }}/coverage.txt files: ${{ env.DESTDIR }}/coverage.txt
token: ${{ secrets.CODECOV_TOKEN }}
test-sandboxed: test-sandboxed:
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
timeout-minutes: 30 # guardrails timeout for the whole job
steps: steps:
-
name: Checkout
uses: actions/checkout@v3
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- -
name: Test name: Test
uses: docker/bake-action@v2 uses: docker/bake-action@a66e1c87e2eca0503c343edf1d208c716d54b8a8 # v7.1.0
with: with:
targets: test targets: test
set: | set: |
@@ -130,24 +135,29 @@ jobs:
*.cache-to=type=gha,scope=test,mode=max *.cache-to=type=gha,scope=test,mode=max
- -
name: Upload coverage name: Upload coverage
uses: codecov/codecov-action@v3 uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
with: with:
file: ${{ env.DESTDIR }}//coverage.txt files: ${{ env.DESTDIR }}//coverage.txt
token: ${{ secrets.CODECOV_TOKEN }}
build: build:
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
timeout-minutes: 30 # guardrails timeout for the whole job
permissions:
# required to create GitHub release
contents: write
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
fetch-depth: 0 fetch-depth: 0
- -
name: Set up QEMU name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- -
name: Build name: Build
run: | run: |
@@ -165,7 +175,7 @@ jobs:
find ${{ env.DESTDIR }} -type f -exec file -e ascii -e text -- {} + find ${{ env.DESTDIR }} -type f -exec file -e ascii -e text -- {} +
- -
name: Upload artifacts name: Upload artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: docker-credential-helpers name: docker-credential-helpers
path: ${{ env.DESTDIR }}/* path: ${{ env.DESTDIR }}/*
@@ -173,7 +183,7 @@ jobs:
- -
name: GitHub Release name: GitHub Release
if: startsWith(github.ref, 'refs/tags/v') if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5 uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
@@ -181,11 +191,12 @@ jobs:
files: ${{ env.DESTDIR }}/* files: ${{ env.DESTDIR }}/*
build-deb: build-deb:
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
timeout-minutes: 30 # guardrails timeout for the whole job
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
fetch-depth: 0 fetch-depth: 0
- -
+28
View File
@@ -0,0 +1,28 @@
name: zizmor
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
on:
workflow_dispatch:
push:
branches:
- 'main'
tags:
- 'v*'
pull_request:
jobs:
run:
uses: crazy-max/.github/.github/workflows/zizmor.yml@d89fe92d808a15e2b2ed5cdb62db7c172c31410d # v1.6.0
permissions:
contents: read
security-events: write
with:
min-severity: medium
min-confidence: medium
persona: pedantic
+12 -20
View File
@@ -1,31 +1,23 @@
version: "2"
run: run:
timeout: 10m
modules-download-mode: vendor modules-download-mode: vendor
linters: linters:
default: none
enable: enable:
- gofmt
- govet - govet
- depguard
- goimports
- ineffassign - ineffassign
- misspell - misspell
- unused
- revive - revive
- staticcheck - staticcheck
- typecheck - unused
disable-all: true settings:
revive:
rules:
- name: package-comments # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#package-comments
disabled: true
linters-settings: formatters:
depguard: enable:
rules: - gofmt
main: - goimports
deny:
- pkg: "io/ioutil"
desc: The io/ioutil package has been deprecated. See https://go.dev/doc/go1.16#ioutil
issues:
exclude-rules:
- linters:
- revive
text: "stutters"
+44 -47
View File
@@ -1,11 +1,28 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
ARG GO_VERSION=1.21.6 # GO_VERSION sets the version of the golang base image to use.
ARG XX_VERSION=1.2.1 # It must be a valid tag in the docker.io/library/golang image repository.
ARG OSXCROSS_VERSION=11.3-r7-debian ARG GO_VERSION=1.25.9
ARG GOLANGCI_LINT_VERSION=v1.55.2
ARG DEBIAN_FRONTEND=noninteractive
# BASE_DEBIAN_DISTRO sets the golang base image debian variant to use.
# It must be a valid variant in the docker.io/library/golang image repository.
ARG BASE_DEBIAN_DISTRO=bookworm
# XX_VERSION sets the version of the xx utility to use.
# It must be a valid tag in the docker.io/tonistiigi/xx image repository.
ARG XX_VERSION=1.9.0
# OSXCROSS_VERSION sets the MacOSX cross toolchain to use.
# It must be a valid tag in the docker.io/crazymax/osxcross image repository.
ARG OSXCROSS_VERSION=11.3-r8-debian
# GOLANGCI_LINT_VERSION sets the version of the golangci-lint image to use.
# It must be a valid tag in the docker.io/golangci/golangci-lint image repository.
ARG GOLANGCI_LINT_VERSION=v2.11
# PACKAGE sets the package name to print in the "--version" output.
# It sets the "github.com/docker/docker-credential-helpers/credentials.Package
# variable at compile time.
ARG PACKAGE=github.com/docker/docker-credential-helpers ARG PACKAGE=github.com/docker/docker-credential-helpers
# xx is a helper for cross-compilation # xx is a helper for cross-compilation
@@ -14,9 +31,8 @@ FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
# osxcross contains the MacOSX cross toolchain for xx # osxcross contains the MacOSX cross toolchain for xx
FROM crazymax/osxcross:${OSXCROSS_VERSION} AS osxcross FROM crazymax/osxcross:${OSXCROSS_VERSION} AS osxcross
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-bullseye AS gobase FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO} AS gobase
COPY --from=xx / / COPY --from=xx / /
ARG DEBIAN_FRONTEND
RUN apt-get update && apt-get install -y --no-install-recommends clang dpkg-dev file git lld llvm make pkg-config rsync RUN apt-get update && apt-get install -y --no-install-recommends clang dpkg-dev file git lld llvm make pkg-config rsync
ENV GOFLAGS="-mod=vendor" ENV GOFLAGS="-mod=vendor"
ENV CGO_ENABLED="1" ENV CGO_ENABLED="1"
@@ -54,8 +70,7 @@ EOT
FROM golangci/golangci-lint:${GOLANGCI_LINT_VERSION} AS golangci-lint FROM golangci/golangci-lint:${GOLANGCI_LINT_VERSION} AS golangci-lint
FROM gobase AS lint FROM gobase AS lint
ARG DEBIAN_FRONTEND RUN apt-get install -y binutils gcc libc6-dev libgcc-11-dev libsecret-1-dev pkg-config
RUN apt-get install -y binutils gcc libc6-dev libgcc-10-dev libsecret-1-dev pkg-config
RUN --mount=type=bind,target=. \ RUN --mount=type=bind,target=. \
--mount=type=cache,target=/root/.cache \ --mount=type=cache,target=/root/.cache \
--mount=from=golangci-lint,source=/usr/bin/golangci-lint,target=/usr/bin/golangci-lint \ --mount=from=golangci-lint,source=/usr/bin/golangci-lint,target=/usr/bin/golangci-lint \
@@ -63,11 +78,9 @@ RUN --mount=type=bind,target=. \
FROM gobase AS base FROM gobase AS base
ARG TARGETPLATFORM ARG TARGETPLATFORM
ARG DEBIAN_FRONTEND RUN xx-apt-get install -y binutils gcc libc6-dev libgcc-11-dev libsecret-1-dev pkg-config
RUN xx-apt-get install -y binutils gcc libc6-dev libgcc-10-dev libsecret-1-dev pkg-config
FROM base AS test FROM base AS test
ARG DEBIAN_FRONTEND
RUN xx-apt-get install -y dbus-x11 gnome-keyring gpg-agent gpgconf libsecret-1-dev pass RUN xx-apt-get install -y dbus-x11 gnome-keyring gpg-agent gpgconf libsecret-1-dev pass
RUN --mount=type=bind,target=. \ RUN --mount=type=bind,target=. \
--mount=type=cache,target=/root/.cache \ --mount=type=cache,target=/root/.cache \
@@ -97,21 +110,7 @@ FROM gobase AS version
RUN --mount=target=. \ RUN --mount=target=. \
echo -n "$(./hack/git-meta version)" | tee /tmp/.version ; echo -n "$(./hack/git-meta revision)" | tee /tmp/.revision echo -n "$(./hack/git-meta version)" | tee /tmp/.version ; echo -n "$(./hack/git-meta revision)" | tee /tmp/.revision
FROM base AS build-linux FROM base AS build
ARG PACKAGE
RUN --mount=type=bind,target=. \
--mount=type=cache,target=/root/.cache \
--mount=type=cache,target=/go/pkg/mod \
--mount=type=bind,source=/tmp/.version,target=/tmp/.version,from=version \
--mount=type=bind,source=/tmp/.revision,target=/tmp/.revision,from=version <<EOT
set -ex
xx-go --wrap
make build-pass build-secretservice PACKAGE=$PACKAGE VERSION=$(cat /tmp/.version) REVISION=$(cat /tmp/.revision) DESTDIR=/out
xx-verify /out/docker-credential-pass
xx-verify /out/docker-credential-secretservice
EOT
FROM base AS build-darwin
ARG PACKAGE ARG PACKAGE
RUN --mount=type=bind,target=. \ RUN --mount=type=bind,target=. \
--mount=type=cache,target=/root/.cache \ --mount=type=cache,target=/root/.cache \
@@ -122,28 +121,26 @@ RUN --mount=type=bind,target=. \
set -ex set -ex
export MACOSX_VERSION_MIN=$(make print-MACOSX_DEPLOYMENT_TARGET) export MACOSX_VERSION_MIN=$(make print-MACOSX_DEPLOYMENT_TARGET)
xx-go --wrap xx-go --wrap
go install std case "$(xx-info os)" in
make build-osxkeychain build-pass PACKAGE=$PACKAGE VERSION=$(cat /tmp/.version) REVISION=$(cat /tmp/.revision) DESTDIR=/out linux)
xx-verify /out/docker-credential-osxkeychain make build-pass build-secretservice PACKAGE=$PACKAGE VERSION=$(cat /tmp/.version) REVISION=$(cat /tmp/.revision) DESTDIR=/out
xx-verify /out/docker-credential-pass xx-verify /out/docker-credential-pass
xx-verify /out/docker-credential-secretservice
;;
darwin)
go install std
make build-osxkeychain build-pass PACKAGE=$PACKAGE VERSION=$(cat /tmp/.version) REVISION=$(cat /tmp/.revision) DESTDIR=/out
xx-verify /out/docker-credential-osxkeychain
xx-verify /out/docker-credential-pass
;;
windows)
make build-wincred PACKAGE=$PACKAGE VERSION=$(cat /tmp/.version) REVISION=$(cat /tmp/.revision) DESTDIR=/out
mv /out/docker-credential-wincred /out/docker-credential-wincred.exe
xx-verify /out/docker-credential-wincred.exe
;;
esac
EOT EOT
FROM base AS build-windows
ARG PACKAGE
RUN --mount=type=bind,target=. \
--mount=type=cache,target=/root/.cache \
--mount=type=cache,target=/go/pkg/mod \
--mount=type=bind,source=/tmp/.version,target=/tmp/.version,from=version \
--mount=type=bind,source=/tmp/.revision,target=/tmp/.revision,from=version <<EOT
set -ex
xx-go --wrap
make build-wincred PACKAGE=$PACKAGE VERSION=$(cat /tmp/.version) REVISION=$(cat /tmp/.revision) DESTDIR=/out
mv /out/docker-credential-wincred /out/docker-credential-wincred.exe
xx-verify /out/docker-credential-wincred.exe
EOT
FROM build-$TARGETOS AS build
FROM scratch AS binaries FROM scratch AS binaries
COPY --from=build /out / COPY --from=build /out /
+16 -1
View File
@@ -12,7 +12,22 @@ COVERAGEDIR ?= ./bin/coverage
# 10.11 is the minimum supported version for osxkeychain # 10.11 is the minimum supported version for osxkeychain
export MACOSX_DEPLOYMENT_TARGET = 10.11 export MACOSX_DEPLOYMENT_TARGET = 10.11
ifeq "$(shell go env GOOS)" "darwin" ifeq "$(shell go env GOOS)" "darwin"
export CGO_CFLAGS = -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET) export CGO_CFLAGS = -Wno-atomic-alignment -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET)
else
# prevent warnings; see https://github.com/docker/docker-credential-helpers/pull/340#issuecomment-2437593837
# gcc_libinit.c:44:8: error: large atomic operation may incur significant performance penalty; the access size (4 bytes) exceeds the max lock-free size (0 bytes) [-Werror,-Watomic-alignment]
export CGO_CFLAGS = -Wno-atomic-alignment
endif
ifeq "$(shell go env GOOS)/$(shell go env GOARCH)/$(shell go env GOARM)" "linux/arm/6"
# Neither the CGo compiler, nor the C toolchain automatically link to
# libatomic when the architecture doesn't support atomic intrinsics, as is
# the case for arm/v6.
#
# Here's the error we get when this is not done (see https://github.com/docker/docker-credential-helpers/pull/340#issuecomment-2437593837):
#
# gcc_libinit.c:44:8: error: large atomic operation may incur significant performance penalty; the access size (4 bytes) exceeds the max lock-free size (0 bytes) [-Werror,-Watomic-alignment]
export CGO_LDFLAGS=-latomic
endif endif
.PHONY: all .PHONY: all
+3 -3
View File
@@ -34,20 +34,20 @@ $ docker buildx bake
Or if the toolchain is already installed on your machine: Or if the toolchain is already installed on your machine:
1 - Download the source. 1. Download the source.
```shell ```shell
$ git clone https://github.com/docker/docker-credential-helpers.git $ git clone https://github.com/docker/docker-credential-helpers.git
$ cd docker-credential-helpers $ cd docker-credential-helpers
``` ```
2 - Use `make` to build the program you want. That will leave an executable in the `bin` directory inside the repository. 2. Use `make` to build the program you want. That will leave an executable in the `bin` directory inside the repository.
```shell ```shell
$ make osxkeychain $ make osxkeychain
``` ```
3 - Put that binary in your `$PATH`, so Docker can find it. 3. Put that binary in your `$PATH`, so Docker can find it.
```shell ```shell
$ cp bin/build/docker-credential-osxkeychain /usr/local/bin/ $ cp bin/build/docker-credential-osxkeychain /usr/local/bin/
+16 -13
View File
@@ -15,27 +15,30 @@ type Program interface {
// ProgramFunc is a type of function that initializes programs based on arguments. // ProgramFunc is a type of function that initializes programs based on arguments.
type ProgramFunc func(args ...string) Program type ProgramFunc func(args ...string) Program
// NewShellProgramFunc creates programs that are executed in a Shell. // NewShellProgramFunc creates a [ProgramFunc] to run command in a [Shell].
func NewShellProgramFunc(name string) ProgramFunc { func NewShellProgramFunc(command string) ProgramFunc {
return NewShellProgramFuncWithEnv(name, nil)
}
// NewShellProgramFuncWithEnv creates programs that are executed in a Shell with environment variables
func NewShellProgramFuncWithEnv(name string, env *map[string]string) ProgramFunc {
return func(args ...string) Program { return func(args ...string) Program {
return &Shell{cmd: createProgramCmdRedirectErr(name, args, env)} return createProgramCmdRedirectErr(command, args, nil)
} }
} }
func createProgramCmdRedirectErr(commandName string, args []string, env *map[string]string) *exec.Cmd { // NewShellProgramFuncWithEnv creates a [ProgramFunc] tu run command
programCmd := exec.Command(commandName, args...) // in a [Shell] with the given environment variables.
func NewShellProgramFuncWithEnv(command string, env *map[string]string) ProgramFunc {
return func(args ...string) Program {
return createProgramCmdRedirectErr(command, args, env)
}
}
func createProgramCmdRedirectErr(command string, args []string, env *map[string]string) *Shell {
ec := exec.Command(command, args...)
if env != nil { if env != nil {
for k, v := range *env { for k, v := range *env {
programCmd.Env = append(programCmd.Environ(), k+"="+v) ec.Env = append(ec.Environ(), k+"="+v)
} }
} }
programCmd.Stderr = os.Stderr ec.Stderr = os.Stderr
return programCmd return &Shell{cmd: ec}
} }
// Shell invokes shell commands to talk with a remote credentials-helper. // Shell invokes shell commands to talk with a remote credentials-helper.
+12 -7
View File
@@ -1,14 +1,19 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
ARG GO_VERSION=1.21.6 # GO_VERSION sets the version of the golang base image to use.
ARG DISTRO=ubuntu # It must be a valid tag in the docker.io/library/golang image repository.
ARG SUITE=focal ARG GO_VERSION=1.25.9
FROM golang:${GO_VERSION}-bullseye AS golang # BASE_DEBIAN_DISTRO sets the golang base image debian variant to use.
# It must be a valid variant in the docker.io/library/golang image repository.
ARG BASE_DEBIAN_DISTRO=bookworm
ARG DISTRO=ubuntu
ARG SUITE=jammy
FROM golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO} AS gobase
FROM ${DISTRO}:${SUITE} FROM ${DISTRO}:${SUITE}
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -yy debhelper dh-make libsecret-1-dev RUN apt-get update && apt-get install -yy debhelper dh-make libsecret-1-dev
RUN mkdir -p /build RUN mkdir -p /build
@@ -17,7 +22,7 @@ ENV GOPROXY=https://proxy.golang.org|direct
ENV GO111MODULE=off ENV GO111MODULE=off
ENV GOPATH=/build ENV GOPATH=/build
ENV PATH=$PATH:/usr/local/go/bin:$GOPATH/bin ENV PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
COPY --from=golang /usr/local/go /usr/local/go COPY --from=gobase /usr/local/go /usr/local/go
COPY Makefile . COPY Makefile .
COPY credentials credentials COPY credentials credentials
+1 -1
View File
@@ -1,5 +1,5 @@
variable "GO_VERSION" { variable "GO_VERSION" {
default = "1.21.6" default = null
} }
# Defines the output folder # Defines the output folder
+11 -3
View File
@@ -1,7 +1,15 @@
module github.com/docker/docker-credential-helpers module github.com/docker/docker-credential-helpers
go 1.19 go 1.21
require github.com/danieljoos/wincred v1.2.1 retract (
v0.9.1 // osxkeychain: a regression caused backward-incompatibility with earlier versions
v0.9.0 // osxkeychain: a regression caused backward-incompatibility with earlier versions
)
require golang.org/x/sys v0.15.0 // indirect require (
github.com/danieljoos/wincred v1.2.3
github.com/keybase/go-keychain v0.0.1
)
require golang.org/x/sys v0.20.0 // indirect
+13 -6
View File
@@ -1,9 +1,16 @@
github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs= github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ=
github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps= github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-227
View File
@@ -1,227 +0,0 @@
#include "osxkeychain.h"
#include <CoreFoundation/CoreFoundation.h>
#include <Foundation/NSValue.h>
#include <stdio.h>
#include <string.h>
char *get_error(OSStatus status) {
char *buf = malloc(128);
CFStringRef str = SecCopyErrorMessageString(status, NULL);
int success = CFStringGetCString(str, buf, 128, kCFStringEncodingUTF8);
if (!success) {
strncpy(buf, "Unknown error", 128);
}
return buf;
}
char *keychain_add(struct Server *server, char *label, char *username, char *secret) {
SecKeychainItemRef item;
OSStatus status = SecKeychainAddInternetPassword(
NULL,
strlen(server->host), server->host,
0, NULL,
strlen(username), username,
strlen(server->path), server->path,
server->port,
server->proto,
kSecAuthenticationTypeDefault,
strlen(secret), secret,
&item
);
if (status) {
return get_error(status);
}
SecKeychainAttribute attribute;
SecKeychainAttributeList attrs;
attribute.tag = kSecLabelItemAttr;
attribute.data = label;
attribute.length = strlen(label);
attrs.count = 1;
attrs.attr = &attribute;
status = SecKeychainItemModifyContent(item, &attrs, 0, NULL);
if (status) {
return get_error(status);
}
return NULL;
}
char *keychain_get(struct Server *server, unsigned int *username_l, char **username, unsigned int *secret_l, char **secret) {
char *tmp;
SecKeychainItemRef item;
OSStatus status = SecKeychainFindInternetPassword(
NULL,
strlen(server->host), server->host,
0, NULL,
0, NULL,
strlen(server->path), server->path,
server->port,
server->proto,
kSecAuthenticationTypeDefault,
secret_l, (void **)&tmp,
&item);
if (status) {
return get_error(status);
}
*secret = strdup(tmp);
SecKeychainItemFreeContent(NULL, tmp);
SecKeychainAttributeList list;
SecKeychainAttribute attr;
list.count = 1;
list.attr = &attr;
attr.tag = kSecAccountItemAttr;
status = SecKeychainItemCopyContent(item, NULL, &list, NULL, NULL);
if (status) {
return get_error(status);
}
*username = strdup(attr.data);
*username_l = attr.length;
SecKeychainItemFreeContent(&list, NULL);
return NULL;
}
char *keychain_delete(struct Server *server) {
SecKeychainItemRef item;
OSStatus status = SecKeychainFindInternetPassword(
NULL,
strlen(server->host), server->host,
0, NULL,
0, NULL,
strlen(server->path), server->path,
server->port,
server->proto,
kSecAuthenticationTypeDefault,
0, NULL,
&item);
if (status) {
return get_error(status);
}
status = SecKeychainItemDelete(item);
if (status) {
return get_error(status);
}
return NULL;
}
char * CFStringToCharArr(CFStringRef aString) {
if (aString == NULL) {
return NULL;
}
CFIndex length = CFStringGetLength(aString);
CFIndex maxSize =
CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
char *buffer = (char *)malloc(maxSize);
if (CFStringGetCString(aString, buffer, maxSize,
kCFStringEncodingUTF8)) {
return buffer;
}
return NULL;
}
char *keychain_list(char *credsLabel, char *** paths, char *** accts, unsigned int *list_l) {
CFStringRef credsLabelCF = CFStringCreateWithCString(NULL, credsLabel, kCFStringEncodingUTF8);
CFMutableDictionaryRef query = CFDictionaryCreateMutable (NULL, 1, NULL, NULL);
CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword);
CFDictionaryAddValue(query, kSecReturnAttributes, kCFBooleanTrue);
CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll);
CFDictionaryAddValue(query, kSecAttrLabel, credsLabelCF);
//Use this query dictionary
CFTypeRef result= NULL;
OSStatus status = SecItemCopyMatching(
query,
&result);
CFRelease(credsLabelCF);
//Ran a search and store the results in result
if (status) {
return get_error(status);
}
CFIndex numKeys = CFArrayGetCount(result);
*paths = (char **) malloc((int)sizeof(char *)*numKeys);
*accts = (char **) malloc((int)sizeof(char *)*numKeys);
//result is of type CFArray
for(CFIndex i=0; i<numKeys; i++) {
CFDictionaryRef currKey = CFArrayGetValueAtIndex(result,i);
CFStringRef protocolTmp = CFDictionaryGetValue(currKey, CFSTR("ptcl"));
if (protocolTmp != NULL) {
CFStringRef protocolStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), protocolTmp);
if (CFStringCompare(protocolStr, CFSTR("htps"), 0) == kCFCompareEqualTo) {
protocolTmp = CFSTR("https://");
}
else {
protocolTmp = CFSTR("http://");
}
CFRelease(protocolStr);
}
else {
char * path = "0";
char * acct = "0";
(*paths)[i] = (char *) malloc(sizeof(char)*(strlen(path)));
memcpy((*paths)[i], path, sizeof(char)*(strlen(path)));
(*accts)[i] = (char *) malloc(sizeof(char)*(strlen(acct)));
memcpy((*accts)[i], acct, sizeof(char)*(strlen(acct)));
continue;
}
CFMutableStringRef str = CFStringCreateMutableCopy(NULL, 0, protocolTmp);
CFStringRef serverTmp = CFDictionaryGetValue(currKey, CFSTR("srvr"));
if (serverTmp != NULL) {
CFStringAppend(str, serverTmp);
}
CFStringRef pathTmp = CFDictionaryGetValue(currKey, CFSTR("path"));
if (pathTmp != NULL) {
CFStringAppend(str, pathTmp);
}
const NSNumber * portTmp = CFDictionaryGetValue(currKey, CFSTR("port"));
if (portTmp != NULL && portTmp.integerValue != 0) {
CFStringRef portStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), portTmp);
CFStringAppend(str, CFSTR(":"));
CFStringAppend(str, portStr);
CFRelease(portStr);
}
CFStringRef acctTmp = CFDictionaryGetValue(currKey, CFSTR("acct"));
if (acctTmp == NULL) {
acctTmp = CFSTR("account not defined");
}
char * path = CFStringToCharArr(str);
char * acct = CFStringToCharArr(acctTmp);
//We now have all we need, username and servername. Now export this to .go
(*paths)[i] = (char *) malloc(sizeof(char)*(strlen(path)+1));
memcpy((*paths)[i], path, sizeof(char)*(strlen(path)+1));
(*accts)[i] = (char *) malloc(sizeof(char)*(strlen(acct)+1));
memcpy((*accts)[i], acct, sizeof(char)*(strlen(acct)+1));
CFRelease(str);
}
*list_l = (int)numKeys;
return NULL;
}
void freeListData(char *** data, unsigned int length) {
for(int i=0; i<length; i++) {
free((*data)[i]);
}
}
+105 -112
View File
@@ -3,30 +3,33 @@
package osxkeychain package osxkeychain
/* /*
#cgo CFLAGS: -x objective-c #cgo LDFLAGS: -framework Security -framework CoreFoundation
#cgo LDFLAGS: -framework Security -framework Foundation
#include "osxkeychain.h" #include <CoreFoundation/CoreFoundation.h>
#include <stdlib.h> #include <Security/Security.h>
*/ */
import "C" import "C"
import ( import (
"errors" "errors"
"net"
"net/url"
"strconv" "strconv"
"unsafe"
"github.com/docker/docker-credential-helpers/credentials" "github.com/docker/docker-credential-helpers/credentials"
"github.com/docker/docker-credential-helpers/registryurl" "github.com/docker/docker-credential-helpers/registryurl"
"github.com/keybase/go-keychain"
) )
// errCredentialsNotFound is the specific error message returned by OS X // https://opensource.apple.com/source/Security/Security-55471/sec/Security/SecBase.h.auto.html
// when the credentials are not in the keychain. const (
const errCredentialsNotFound = "The specified item could not be found in the keychain." // errCredentialsNotFound is the specific error message returned by OS X
// when the credentials are not in the keychain.
// errCredentialsNotFound is the specific error message returned by OS X errCredentialsNotFound = "The specified item could not be found in the keychain. (-25300)"
// when environment does not allow showing dialog to unlock keychain. // errInteractionNotAllowed is the specific error message returned by OS X
const errInteractionNotAllowed = "User interaction is not allowed." // when environment does not allow showing dialog to unlock keychain.
errInteractionNotAllowed = "User interaction is not allowed. (-25308)"
)
// ErrInteractionNotAllowed is returned if keychain password prompt can not be shown. // ErrInteractionNotAllowed is returned if keychain password prompt can not be shown.
var ErrInteractionNotAllowed = errors.New(`keychain cannot be accessed because the current session does not allow user interaction. The keychain may be locked; unlock it by running "security -v unlock-keychain ~/Library/Keychains/login.keychain-db" and try again`) var ErrInteractionNotAllowed = errors.New(`keychain cannot be accessed because the current session does not allow user interaction. The keychain may be locked; unlock it by running "security -v unlock-keychain ~/Library/Keychains/login.keychain-db" and try again`)
@@ -38,152 +41,142 @@ type Osxkeychain struct{}
func (h Osxkeychain) Add(creds *credentials.Credentials) error { func (h Osxkeychain) Add(creds *credentials.Credentials) error {
_ = h.Delete(creds.ServerURL) // ignore errors as existing credential may not exist. _ = h.Delete(creds.ServerURL) // ignore errors as existing credential may not exist.
s, err := splitServer(creds.ServerURL) item := keychain.NewItem()
if err != nil { item.SetSecClass(keychain.SecClassInternetPassword)
item.SetLabel(credentials.CredsLabel)
item.SetAccount(creds.Username)
item.SetData([]byte(creds.Secret))
// Prior to v0.9, the credential helper was searching for credentials with
// the "dflt" authentication type (see [1]). Since v0.9.0, Get doesn't use
// that attribute anymore, and v0.9.0 - v0.9.2 were not setting it here
// either.
//
// In order to keep compatibility with older versions, we need to store
// credentials with this attribute set. This way, credentials stored with
// newer versions can be retrieved by older versions.
//
// [1]: https://github.com/docker/docker-credential-helpers/blob/v0.8.2/osxkeychain/osxkeychain.c#L66
item.SetAuthenticationType("dflt")
if err := splitServer(creds.ServerURL, item); err != nil {
return err return err
} }
defer freeServer(s)
label := C.CString(credentials.CredsLabel) return keychain.AddItem(item)
defer C.free(unsafe.Pointer(label))
username := C.CString(creds.Username)
defer C.free(unsafe.Pointer(username))
secret := C.CString(creds.Secret)
defer C.free(unsafe.Pointer(secret))
errMsg := C.keychain_add(s, label, username, secret)
if errMsg != nil {
defer C.free(unsafe.Pointer(errMsg))
return errors.New(C.GoString(errMsg))
}
return nil
} }
// Delete removes credentials from the keychain. // Delete removes credentials from the keychain.
func (h Osxkeychain) Delete(serverURL string) error { func (h Osxkeychain) Delete(serverURL string) error {
s, err := splitServer(serverURL) item := keychain.NewItem()
if err != nil { item.SetSecClass(keychain.SecClassInternetPassword)
if err := splitServer(serverURL, item); err != nil {
return err return err
} }
defer freeServer(s) if err := keychain.DeleteItem(item); err != nil {
switch err.Error() {
if errMsg := C.keychain_delete(s); errMsg != nil {
defer C.free(unsafe.Pointer(errMsg))
switch goMsg := C.GoString(errMsg); goMsg {
case errCredentialsNotFound: case errCredentialsNotFound:
return credentials.NewErrCredentialsNotFound() return credentials.NewErrCredentialsNotFound()
case errInteractionNotAllowed: case errInteractionNotAllowed:
return ErrInteractionNotAllowed return ErrInteractionNotAllowed
default: default:
return errors.New(goMsg) return err
} }
} }
return nil return nil
} }
// Get returns the username and secret to use for a given registry server URL. // Get returns the username and secret to use for a given registry server URL.
func (h Osxkeychain) Get(serverURL string) (string, string, error) { func (h Osxkeychain) Get(serverURL string) (string, string, error) {
s, err := splitServer(serverURL) item := keychain.NewItem()
if err != nil { item.SetSecClass(keychain.SecClassInternetPassword)
item.SetMatchLimit(keychain.MatchLimitOne)
item.SetReturnAttributes(true)
item.SetReturnData(true)
if err := splitServer(serverURL, item); err != nil {
return "", "", err return "", "", err
} }
defer freeServer(s)
var usernameLen C.uint res, err := keychain.QueryItem(item)
var username *C.char if err != nil {
var secretLen C.uint switch err.Error() {
var secret *C.char
defer C.free(unsafe.Pointer(username))
defer C.free(unsafe.Pointer(secret))
errMsg := C.keychain_get(s, &usernameLen, &username, &secretLen, &secret)
if errMsg != nil {
defer C.free(unsafe.Pointer(errMsg))
switch goMsg := C.GoString(errMsg); goMsg {
case errCredentialsNotFound: case errCredentialsNotFound:
return "", "", credentials.NewErrCredentialsNotFound() return "", "", credentials.NewErrCredentialsNotFound()
case errInteractionNotAllowed: case errInteractionNotAllowed:
return "", "", ErrInteractionNotAllowed return "", "", ErrInteractionNotAllowed
default: default:
return "", "", errors.New(goMsg) return "", "", err
} }
} else if len(res) == 0 {
return "", "", credentials.NewErrCredentialsNotFound()
} }
user := C.GoStringN(username, C.int(usernameLen)) return res[0].Account, string(res[0].Data), nil
pass := C.GoStringN(secret, C.int(secretLen))
return user, pass, nil
} }
// List returns the stored URLs and corresponding usernames. // List returns the stored URLs and corresponding usernames.
func (h Osxkeychain) List() (map[string]string, error) { func (h Osxkeychain) List() (map[string]string, error) {
credsLabelC := C.CString(credentials.CredsLabel) item := keychain.NewItem()
defer C.free(unsafe.Pointer(credsLabelC)) item.SetSecClass(keychain.SecClassInternetPassword)
item.SetMatchLimit(keychain.MatchLimitAll)
item.SetReturnAttributes(true)
item.SetLabel(credentials.CredsLabel)
var pathsC **C.char res, err := keychain.QueryItem(item)
defer C.free(unsafe.Pointer(pathsC)) if err != nil {
var acctsC **C.char switch err.Error() {
defer C.free(unsafe.Pointer(acctsC))
var listLenC C.uint
errMsg := C.keychain_list(credsLabelC, &pathsC, &acctsC, &listLenC)
defer C.freeListData(&pathsC, listLenC)
defer C.freeListData(&acctsC, listLenC)
if errMsg != nil {
defer C.free(unsafe.Pointer(errMsg))
switch goMsg := C.GoString(errMsg); goMsg {
case errCredentialsNotFound: case errCredentialsNotFound:
return make(map[string]string), nil return make(map[string]string), nil
case errInteractionNotAllowed: case errInteractionNotAllowed:
return nil, ErrInteractionNotAllowed return nil, ErrInteractionNotAllowed
default: default:
return nil, errors.New(goMsg)
}
}
var listLen int
listLen = int(listLenC)
pathTmp := (*[1 << 30]*C.char)(unsafe.Pointer(pathsC))[:listLen:listLen]
acctTmp := (*[1 << 30]*C.char)(unsafe.Pointer(acctsC))[:listLen:listLen]
// taking the array of c strings into go while ignoring all the stuff irrelevant to credentials-helper
resp := make(map[string]string)
for i := 0; i < listLen; i++ {
if C.GoString(pathTmp[i]) == "0" {
continue
}
resp[C.GoString(pathTmp[i])] = C.GoString(acctTmp[i])
}
return resp, nil
}
func splitServer(serverURL string) (*C.struct_Server, error) {
u, err := registryurl.Parse(serverURL)
if err != nil {
return nil, err
}
proto := C.kSecProtocolTypeHTTPS
if u.Scheme == "http" {
proto = C.kSecProtocolTypeHTTP
}
var port int
p := u.Port()
if p != "" {
port, err = strconv.Atoi(p)
if err != nil {
return nil, err return nil, err
} }
} }
return &C.struct_Server{ resp := make(map[string]string)
proto: C.SecProtocolType(proto), for _, r := range res {
host: C.CString(u.Hostname()), proto := "http"
port: C.uint(port), if r.Protocol == kSecProtocolTypeHTTPS {
path: C.CString(u.Path), proto = "https"
}, nil }
host := r.Server
if r.Port != 0 {
host = net.JoinHostPort(host, strconv.Itoa(int(r.Port)))
}
u := url.URL{
Scheme: proto,
Host: host,
Path: r.Path,
}
resp[u.String()] = r.Account
}
return resp, nil
} }
func freeServer(s *C.struct_Server) { const (
C.free(unsafe.Pointer(s.host)) // Hardcoded protocol types matching their Objective-C equivalents.
C.free(unsafe.Pointer(s.path)) // https://developer.apple.com/documentation/security/ksecattrprotocolhttps?language=objc
kSecProtocolTypeHTTPS = "htps" // This is NOT a typo.
// https://developer.apple.com/documentation/security/ksecattrprotocolhttp?language=objc
kSecProtocolTypeHTTP = "http"
)
func splitServer(serverURL string, item keychain.Item) error {
u, err := registryurl.Parse(serverURL)
if err != nil {
return err
}
item.SetProtocol(kSecProtocolTypeHTTPS)
if u.Scheme == "http" {
item.SetProtocol(kSecProtocolTypeHTTP)
}
item.SetServer(u.Hostname())
if p := u.Port(); p != "" {
port, err := strconv.Atoi(p)
if err != nil {
return err
}
item.SetPort(int32(port))
}
item.SetPath(u.Path)
return nil
} }
-14
View File
@@ -1,14 +0,0 @@
#include <Security/Security.h>
struct Server {
SecProtocolType proto;
char *host;
char *path;
unsigned int port;
};
char *keychain_add(struct Server *server, char *label, char *username, char *secret);
char *keychain_get(struct Server *server, unsigned int *username_l, char **username, unsigned int *secret_l, char **secret);
char *keychain_delete(struct Server *server);
char *keychain_list(char *credsLabel, char *** data, char *** accts, unsigned int *list_l);
void freeListData(char *** data, unsigned int length);
+72 -14
View File
@@ -15,11 +15,6 @@ func TestOSXKeychainHelper(t *testing.T) {
Username: "foobar", Username: "foobar",
Secret: "foobarbaz", Secret: "foobarbaz",
} }
creds1 := &credentials.Credentials{
ServerURL: "https://foobar.example.com:2376/v2",
Username: "foobarbaz",
Secret: "foobar",
}
helper := Osxkeychain{} helper := Osxkeychain{}
if err := helper.Add(creds); err != nil { if err := helper.Add(creds); err != nil {
t.Fatal(err) t.Fatal(err)
@@ -43,19 +38,49 @@ func TestOSXKeychainHelper(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
helper.Add(creds1) if _, ok := auths[creds.ServerURL]; !ok {
defer helper.Delete(creds1.ServerURL) t.Fatalf("server %s not found in list, got: %+v", creds.ServerURL, auths)
newauths, err := helper.List()
if len(newauths)-len(auths) != 1 {
if err == nil {
t.Fatalf("Error: len(newauths): %d, len(auths): %d", len(newauths), len(auths))
}
t.Fatalf("Error: len(newauths): %d, len(auths): %d\n Error= %v", len(newauths), len(auths), err)
} }
// Insert another token and check if it is in the list
creds1 := &credentials.Credentials{
ServerURL: "https://foobar.example.com:2376/v2",
Username: "foobarbaz",
Secret: "foobar",
}
helper.Add(creds1)
defer helper.Delete(creds1.ServerURL)
auths, err = helper.List()
if err != nil {
t.Fatalf("operation List failed: %+v", err)
}
if _, ok := auths[creds.ServerURL]; !ok {
t.Fatalf("server %s not found in list, got: %+v", creds.ServerURL, auths)
}
if _, ok := auths[creds1.ServerURL]; !ok {
t.Fatalf("server %s not found in list, got: %+v", creds1.ServerURL, auths)
}
// Delete the 1st token inserted
if err := helper.Delete(creds.ServerURL); err != nil { if err := helper.Delete(creds.ServerURL); err != nil {
t.Fatal(err) t.Fatal(err)
} }
auths, err = helper.List()
if err != nil {
t.Fatalf("operation List failed: %+v", err)
}
// First token should have been deleted
if _, ok := auths[creds.ServerURL]; ok {
t.Fatalf("server %s was not deleted, got: %+v", creds.ServerURL, auths)
}
// Second token should still be there
if _, ok := auths[creds1.ServerURL]; !ok {
t.Fatalf("server %s not found in list, got: %+v", creds1.ServerURL, auths)
}
} }
// TestOSXKeychainHelperRetrieveAliases verifies that secrets can be accessed // TestOSXKeychainHelperRetrieveAliases verifies that secrets can be accessed
@@ -107,7 +132,7 @@ func TestOSXKeychainHelperRetrieveAliases(t *testing.T) {
t.Fatalf("Error: failed to store secret for URL %q: %s", tc.storeURL, err) t.Fatalf("Error: failed to store secret for URL %q: %s", tc.storeURL, err)
} }
if _, _, err := helper.Get(tc.readURL); err != nil { if _, _, err := helper.Get(tc.readURL); err != nil {
t.Errorf("Error: failed to read secret for URL %q using %q", tc.storeURL, tc.readURL) t.Errorf("Error: failed to read secret for URL %q using %q: %s", tc.storeURL, tc.readURL, err)
} }
if err := helper.Delete(tc.storeURL); err != nil { if err := helper.Delete(tc.storeURL); err != nil {
t.Error(err) t.Error(err)
@@ -116,6 +141,39 @@ func TestOSXKeychainHelperRetrieveAliases(t *testing.T) {
} }
} }
func TestOSXKeychainHelperStoreWithUncleanPath(t *testing.T) {
helper := Osxkeychain{}
creds := &credentials.Credentials{
ServerURL: "https://::1:8080//////location/../../hello",
Username: "testuser",
Secret: "testsecret",
}
// Clean store before and after the test.
defer helper.Delete(creds.ServerURL)
if err := helper.Delete(creds.ServerURL); err != nil && !credentials.IsErrCredentialsNotFound(err) {
t.Errorf("prepare: failed to delete '%s': %v", creds.ServerURL, err)
}
// Store the credentials
if err := helper.Add(creds); err != nil {
t.Fatalf("Error: failed to store credentials with unclean path %q: %s", creds.ServerURL, err)
}
// Retrieve and verify credentials
username, secret, err := helper.Get(creds.ServerURL)
if err != nil {
t.Fatalf("Error: failed to retrieve credentials with unclean path %q: %s", creds.ServerURL, err)
}
if username != creds.Username {
t.Errorf("Error: expected username %s, got %s", creds.Username, username)
}
if secret != creds.Secret {
t.Errorf("Error: expected secret %s, got %s", creds.Secret, secret)
}
}
// TestOSXKeychainHelperRetrieveStrict verifies that only matching secrets are // TestOSXKeychainHelperRetrieveStrict verifies that only matching secrets are
// returned. // returned.
func TestOSXKeychainHelperRetrieveStrict(t *testing.T) { func TestOSXKeychainHelperRetrieveStrict(t *testing.T) {
+23 -17
View File
@@ -87,8 +87,7 @@ func (p Pass) Add(creds *credentials.Credentials) error {
return errors.New("missing credentials") return errors.New("missing credentials")
} }
encoded := base64.URLEncoding.EncodeToString([]byte(creds.ServerURL)) encoded := encodeServerURL(creds.ServerURL)
_, err := p.runPass(creds.Secret, "insert", "-f", "-m", path.Join(PASS_FOLDER, encoded, creds.Username)) _, err := p.runPass(creds.Secret, "insert", "-f", "-m", path.Join(PASS_FOLDER, encoded, creds.Username))
return err return err
} }
@@ -99,7 +98,7 @@ func (p Pass) Delete(serverURL string) error {
return errors.New("missing server url") return errors.New("missing server url")
} }
encoded := base64.URLEncoding.EncodeToString([]byte(serverURL)) encoded := encodeServerURL(serverURL)
_, err := p.runPass("", "rm", "-rf", path.Join(PASS_FOLDER, encoded)) _, err := p.runPass("", "rm", "-rf", path.Join(PASS_FOLDER, encoded))
return err return err
} }
@@ -142,23 +141,14 @@ func (p Pass) Get(serverURL string) (string, string, error) {
return "", "", errors.New("missing server url") return "", "", errors.New("missing server url")
} }
encoded := base64.URLEncoding.EncodeToString([]byte(serverURL)) encoded := encodeServerURL(serverURL)
if _, err := os.Stat(path.Join(getPassDir(), PASS_FOLDER, encoded)); err != nil {
if os.IsNotExist(err) {
return "", "", credentials.NewErrCredentialsNotFound()
}
return "", "", err
}
usernames, err := listPassDir(encoded) usernames, err := listPassDir(encoded)
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
if len(usernames) < 1 { if len(usernames) < 1 {
return "", "", fmt.Errorf("no usernames for %s", serverURL) return "", "", credentials.NewErrCredentialsNotFound()
} }
actual := strings.TrimSuffix(usernames[0].Name(), ".gpg") actual := strings.TrimSuffix(usernames[0].Name(), ".gpg")
@@ -180,7 +170,7 @@ func (p Pass) List() (map[string]string, error) {
continue continue
} }
serverURL, err := base64.URLEncoding.DecodeString(server.Name()) serverURL, err := decodeServerURL(server.Name())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -191,11 +181,27 @@ func (p Pass) List() (map[string]string, error) {
} }
if len(usernames) < 1 { if len(usernames) < 1 {
return nil, fmt.Errorf("no usernames for %s", serverURL) continue
} }
resp[string(serverURL)] = strings.TrimSuffix(usernames[0].Name(), ".gpg") resp[serverURL] = strings.TrimSuffix(usernames[0].Name(), ".gpg")
} }
return resp, nil return resp, nil
} }
// encodeServerURL returns the serverURL in base64-URL encoding to use
// as directory-name in pass storage.
func encodeServerURL(serverURL string) string {
return base64.URLEncoding.EncodeToString([]byte(serverURL))
}
// decodeServerURL decodes base64-URL encoded serverURL. ServerURLs are
// used in encoded format for directory-names in pass storage.
func decodeServerURL(encodedServerURL string) (string, error) {
serverURL, err := base64.URLEncoding.DecodeString(encodedServerURL)
if err != nil {
return "", err
}
return string(serverURL), nil
}
+73 -2
View File
@@ -3,6 +3,8 @@
package pass package pass
import ( import (
"os"
"path"
"strings" "strings"
"testing" "testing"
@@ -81,10 +83,10 @@ func TestPassHelperList(t *testing.T) {
t.Error(err) t.Error(err)
} }
for server, username := range credsList { for server, username := range credsList {
if !(strings.HasSuffix(server, "2376/v1") || strings.HasSuffix(server, "2375/v1")) { if !strings.HasSuffix(server, "2376/v1") && !strings.HasSuffix(server, "2375/v1") {
t.Errorf("invalid url: %s", server) t.Errorf("invalid url: %s", server)
} }
if !(username == "foo" || username == "bar") { if username != "foo" && username != "bar" {
t.Errorf("invalid username: %v", username) t.Errorf("invalid username: %v", username)
} }
@@ -116,6 +118,75 @@ func TestPassHelperList(t *testing.T) {
} }
} }
// TestPassHelperWithEmptyServer verifies that empty directories (servers
// without credentials) are ignored, but still returns credentials for other
// servers.
func TestPassHelperWithEmptyServer(t *testing.T) {
helper := Pass{}
if err := helper.checkInitialized(); err != nil {
t.Error(err)
}
creds := []*credentials.Credentials{
{
ServerURL: "https://myreqistry.example.com:2375/v1",
Username: "foo",
Secret: "isthebestmeshuggahalbum",
},
{
ServerURL: "https://index.example.com/v1//access-token",
},
}
t.Cleanup(func() {
for _, cred := range creds {
_ = helper.Delete(cred.ServerURL)
}
})
for _, cred := range creds {
if cred.Username != "" {
if err := helper.Add(cred); err != nil {
t.Error(err)
}
} else {
// No credentials; create an empty directory for this server.
serverURL := encodeServerURL(cred.ServerURL)
p := path.Join(getPassDir(), PASS_FOLDER, serverURL)
if err := os.Mkdir(p, 0o755); err != nil {
t.Error(err)
}
}
}
credsList, err := helper.List()
if err != nil {
t.Error(err)
}
if len(credsList) == 0 {
t.Error("expected credentials to be returned, but got none")
}
for _, cred := range creds {
if cred.Username != "" {
userName, secret, err := helper.Get(cred.ServerURL)
if err != nil {
t.Error(err)
}
if userName != cred.Username {
t.Errorf("expected username %q, actual: %q", cred.Username, userName)
}
if secret != cred.Secret {
t.Errorf("expected secret %q, actual: %q", cred.Secret, secret)
}
} else {
_, _, err := helper.Get(cred.ServerURL)
if !credentials.IsErrCredentialsNotFound(err) {
t.Errorf("expected credentials not found, actual: %v", err)
}
}
}
}
func TestMissingCred(t *testing.T) { func TestMissingCred(t *testing.T) {
helper := Pass{} helper := Pass{}
if _, _, err := helper.Get("garbage"); !credentials.IsErrCredentialsNotFound(err) { if _, _, err := helper.Get("garbage"); !credentials.IsErrCredentialsNotFound(err) {
+5 -2
View File
@@ -17,11 +17,11 @@ const SecretSchema *docker_get_schema(void)
return &docker_schema; return &docker_schema;
} }
GError *add(char *label, char *server, char *username, char *secret) { GError *add(char *label, char *server, char *username, char *secret, char *displaylabel) {
GError *err = NULL; GError *err = NULL;
secret_password_store_sync (DOCKER_SCHEMA, SECRET_COLLECTION_DEFAULT, secret_password_store_sync (DOCKER_SCHEMA, SECRET_COLLECTION_DEFAULT,
server, secret, NULL, &err, displaylabel, secret, NULL, &err,
"label", label, "label", label,
"server", server, "server", server,
"username", username, "username", username,
@@ -83,6 +83,9 @@ GError *get(char *server, char **username, char **secret) {
} }
g_free(value); g_free(value);
secretValue = secret_item_get_secret(l->data); secretValue = secret_item_get_secret(l->data);
if (secretValue == NULL) {
continue;
}
if (secret != NULL) { if (secret != NULL) {
*secret = strdup(secret_value_get(secretValue, &length)); *secret = strdup(secret_value_get(secretValue, &length));
secret_value_unref(secretValue); secret_value_unref(secretValue);
+3 -1
View File
@@ -33,8 +33,10 @@ func (h Secretservice) Add(creds *credentials.Credentials) error {
defer C.free(unsafe.Pointer(username)) defer C.free(unsafe.Pointer(username))
secret := C.CString(creds.Secret) secret := C.CString(creds.Secret)
defer C.free(unsafe.Pointer(secret)) defer C.free(unsafe.Pointer(secret))
displayLabel := C.CString("Registry credentials for " + creds.ServerURL)
defer C.free(unsafe.Pointer(displayLabel))
if err := C.add(credsLabel, server, username, secret); err != nil { if err := C.add(credsLabel, server, username, secret, displayLabel); err != nil {
defer C.g_error_free(err) defer C.g_error_free(err)
errMsg := (*C.char)(unsafe.Pointer(err.message)) errMsg := (*C.char)(unsafe.Pointer(err.message))
return errors.New(C.GoString(errMsg)) return errors.New(C.GoString(errMsg))
+1 -1
View File
@@ -6,7 +6,7 @@ const SecretSchema *docker_get_schema(void) G_GNUC_CONST;
#define DOCKER_SCHEMA docker_get_schema() #define DOCKER_SCHEMA docker_get_schema()
GError *add(char *label, char *server, char *username, char *secret); GError *add(char *label, char *server, char *username, char *secret, char *displaylabel);
GError *delete(char *server); GError *delete(char *server);
GError *get(char *server, char **username, char **secret); GError *get(char *server, char **username, char **secret);
GError *list(char *label, char *** paths, char *** accts, unsigned int *list_l); GError *list(char *label, char *** paths, char *** accts, unsigned int *list_l);
+7 -13
View File
@@ -31,13 +31,13 @@ func utf16FromString(str string) []uint16 {
// goBytes copies the given C byte array to a Go byte array (see `C.GoBytes`). // goBytes copies the given C byte array to a Go byte array (see `C.GoBytes`).
// This function avoids having cgo as dependency. // This function avoids having cgo as dependency.
func goBytes(src uintptr, len uint32) []byte { func goBytes(src *byte, len uint32) []byte {
if src == uintptr(0) { if src == nil || len == 0 {
return []byte{} return []byte{}
} }
rv := make([]byte, len) rv := make([]byte, len)
copy(rv, *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ copy(rv, *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
Data: src, Data: uintptr(unsafe.Pointer(src)),
Len: int(len), Len: int(len),
Cap: int(len), Cap: int(len),
}))) })))
@@ -59,7 +59,7 @@ func sysToCredential(cred *sysCREDENTIAL) (result *Credential) {
result.CredentialBlob = goBytes(cred.CredentialBlob, cred.CredentialBlobSize) result.CredentialBlob = goBytes(cred.CredentialBlob, cred.CredentialBlobSize)
result.Attributes = make([]CredentialAttribute, cred.AttributeCount) result.Attributes = make([]CredentialAttribute, cred.AttributeCount)
attrSlice := *(*[]sysCREDENTIAL_ATTRIBUTE)(unsafe.Pointer(&reflect.SliceHeader{ attrSlice := *(*[]sysCREDENTIAL_ATTRIBUTE)(unsafe.Pointer(&reflect.SliceHeader{
Data: cred.Attributes, Data: uintptr(unsafe.Pointer(cred.Attributes)),
Len: int(cred.AttributeCount), Len: int(cred.AttributeCount),
Cap: int(cred.AttributeCount), Cap: int(cred.AttributeCount),
})) }))
@@ -85,17 +85,13 @@ func sysFromCredential(cred *Credential) (result *sysCREDENTIAL) {
result.LastWritten = syscall.NsecToFiletime(cred.LastWritten.UnixNano()) result.LastWritten = syscall.NsecToFiletime(cred.LastWritten.UnixNano())
result.CredentialBlobSize = uint32(len(cred.CredentialBlob)) result.CredentialBlobSize = uint32(len(cred.CredentialBlob))
if len(cred.CredentialBlob) > 0 { if len(cred.CredentialBlob) > 0 {
result.CredentialBlob = uintptr(unsafe.Pointer(&cred.CredentialBlob[0])) result.CredentialBlob = &cred.CredentialBlob[0]
} else {
result.CredentialBlob = 0
} }
result.Persist = uint32(cred.Persist) result.Persist = uint32(cred.Persist)
result.AttributeCount = uint32(len(cred.Attributes)) result.AttributeCount = uint32(len(cred.Attributes))
attributes := make([]sysCREDENTIAL_ATTRIBUTE, len(cred.Attributes)) attributes := make([]sysCREDENTIAL_ATTRIBUTE, len(cred.Attributes))
if len(attributes) > 0 { if len(attributes) > 0 {
result.Attributes = uintptr(unsafe.Pointer(&attributes[0])) result.Attributes = &attributes[0]
} else {
result.Attributes = 0
} }
for i := range cred.Attributes { for i := range cred.Attributes {
inAttr := &cred.Attributes[i] inAttr := &cred.Attributes[i]
@@ -104,9 +100,7 @@ func sysFromCredential(cred *Credential) (result *sysCREDENTIAL) {
outAttr.Flags = 0 outAttr.Flags = 0
outAttr.ValueSize = uint32(len(inAttr.Value)) outAttr.ValueSize = uint32(len(inAttr.Value))
if len(inAttr.Value) > 0 { if len(inAttr.Value) > 0 {
outAttr.Value = uintptr(unsafe.Pointer(&inAttr.Value[0])) outAttr.Value = &inAttr.Value[0]
} else {
outAttr.Value = 0
} }
} }
result.TargetAlias, _ = syscall.UTF16PtrFromString(cred.TargetAlias) result.TargetAlias, _ = syscall.UTF16PtrFromString(cred.TargetAlias)
+6 -3
View File
@@ -5,6 +5,7 @@ package wincred
import ( import (
"reflect" "reflect"
"runtime"
"syscall" "syscall"
"unsafe" "unsafe"
@@ -33,10 +34,10 @@ type sysCREDENTIAL struct {
Comment *uint16 Comment *uint16
LastWritten windows.Filetime LastWritten windows.Filetime
CredentialBlobSize uint32 CredentialBlobSize uint32
CredentialBlob uintptr CredentialBlob *byte
Persist uint32 Persist uint32
AttributeCount uint32 AttributeCount uint32
Attributes uintptr Attributes *sysCREDENTIAL_ATTRIBUTE
TargetAlias *uint16 TargetAlias *uint16
UserName *uint16 UserName *uint16
} }
@@ -46,7 +47,7 @@ type sysCREDENTIAL_ATTRIBUTE struct {
Keyword *uint16 Keyword *uint16
Flags uint32 Flags uint32
ValueSize uint32 ValueSize uint32
Value uintptr Value *byte
} }
// https://docs.microsoft.com/en-us/windows/desktop/api/wincred/ns-wincred-_credentialw // https://docs.microsoft.com/en-us/windows/desktop/api/wincred/ns-wincred-_credentialw
@@ -93,6 +94,8 @@ func sysCredWrite(cred *Credential, typ sysCRED_TYPE) error {
uintptr(unsafe.Pointer(ncred)), uintptr(unsafe.Pointer(ncred)),
0, 0,
) )
// Make sure everything reachable from ncred stays alive through the call.
runtime.KeepAlive(ncred)
if ret == 0 { if ret == 0 {
return err return err
} }
+2
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows // +build !windows
package wincred package wincred
@@ -17,6 +18,7 @@ const (
sysERROR_NOT_FOUND = syscall.Errno(1) sysERROR_NOT_FOUND = syscall.Errno(1)
sysERROR_INVALID_PARAMETER = syscall.Errno(1) sysERROR_INVALID_PARAMETER = syscall.Errno(1)
sysERROR_BAD_USERNAME = syscall.Errno(1)
) )
func sysCredRead(...interface{}) (*Credential, error) { func sysCredRead(...interface{}) (*Credential, error) {
+26
View File
@@ -0,0 +1,26 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
vendor
+13
View File
@@ -0,0 +1,13 @@
linters-settings:
gocritic:
disabled-checks:
- ifElseChain
- elseif
linters:
enable:
- gofmt
- gocritic
- unconvert
- revive
- govet
+22
View File
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Keybase
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+126
View File
@@ -0,0 +1,126 @@
# Go Keychain
[![Build Status](https://github.com/keybase/go-keychain/actions/workflows/ci.yml/badge.svg)](https://github.com/keybase/go-keychain/actions)
A library for accessing the Keychain for macOS, iOS, and Linux in Go (golang).
Requires macOS 10.9 or greater and iOS 8 or greater. On Linux, communicates to
a provider of the DBUS SecretService spec like gnome-keyring or ksecretservice.
```go
import "github.com/keybase/go-keychain"
```
## Mac/iOS Usage
The API is meant to mirror the macOS/iOS Keychain API and is not necessarily idiomatic go.
#### Add Item
```go
item := keychain.NewItem()
item.SetSecClass(keychain.SecClassGenericPassword)
item.SetService("MyService")
item.SetAccount("gabriel")
item.SetLabel("A label")
item.SetAccessGroup("A123456789.group.com.mycorp")
item.SetData([]byte("toomanysecrets"))
item.SetSynchronizable(keychain.SynchronizableNo)
item.SetAccessible(keychain.AccessibleWhenUnlocked)
err := keychain.AddItem(item)
if err == keychain.ErrorDuplicateItem {
// Duplicate
}
```
#### Query Item
Query for multiple results, returning attributes:
```go
query := keychain.NewItem()
query.SetSecClass(keychain.SecClassGenericPassword)
query.SetService(service)
query.SetAccount(account)
query.SetAccessGroup(accessGroup)
query.SetMatchLimit(keychain.MatchLimitAll)
query.SetReturnAttributes(true)
results, err := keychain.QueryItem(query)
if err != nil {
// Error
} else {
for _, r := range results {
fmt.Printf("%#v\n", r)
}
}
```
Query for a single result, returning data:
```go
query := keychain.NewItem()
query.SetSecClass(keychain.SecClassGenericPassword)
query.SetService(service)
query.SetAccount(account)
query.SetAccessGroup(accessGroup)
query.SetMatchLimit(keychain.MatchLimitOne)
query.SetReturnData(true)
results, err := keychain.QueryItem(query)
if err != nil {
// Error
} else if len(results) != 1 {
// Not found
} else {
password := string(results[0].Data)
}
```
#### Delete Item
Delete a generic password item with service and account:
```go
item := keychain.NewItem()
item.SetSecClass(keychain.SecClassGenericPassword)
item.SetService(service)
item.SetAccount(account)
err := keychain.DeleteItem(item)
```
### Other
There are some convenience methods for generic password:
```go
// Create generic password item with service, account, label, password, access group
item := keychain.NewGenericPassword("MyService", "gabriel", "A label", []byte("toomanysecrets"), "A123456789.group.com.mycorp")
item.SetSynchronizable(keychain.SynchronizableNo)
item.SetAccessible(keychain.AccessibleWhenUnlocked)
err := keychain.AddItem(item)
if err == keychain.ErrorDuplicateItem {
// Duplicate
}
password, err := keychain.GetGenericPassword("MyService", "gabriel", "A label", "A123456789.group.com.mycorp")
accounts, err := keychain.GetGenericPasswordAccounts("MyService")
// Should have 1 account == "gabriel"
err := keychain.DeleteGenericPasswordItem("MyService", "gabriel")
if err == keychain.ErrorItemNotFound {
// Not found
}
```
## iOS
Bindable package in `bind`. iOS project in `ios`. Run that project to test iOS.
To re-generate framework:
```
(cd bind && gomobile bind -target=ios -tags=ios -o ../ios/bind.framework)
```
Post issues to: https://github.com/keybase/keybase-issues
+370
View File
@@ -0,0 +1,370 @@
//go:build darwin || ios
// +build darwin ios
package keychain
/*
#cgo LDFLAGS: -framework CoreFoundation
#include <CoreFoundation/CoreFoundation.h>
// Can't cast a *uintptr to *unsafe.Pointer in Go, and casting
// C.CFTypeRef to unsafe.Pointer is unsafe in Go, so have shim functions to
// do the casting in C (where it's safe).
// We add a suffix to the C functions below, because we copied this
// file from go-kext, which means that any project that depends on this
// package and go-kext would run into duplicate symbol errors otherwise.
//
// TODO: Move this file into its own package depended on by go-kext
// and this package.
CFDictionaryRef CFDictionaryCreateSafe2(CFAllocatorRef allocator, const uintptr_t *keys, const uintptr_t *values, CFIndex numValues, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks) {
return CFDictionaryCreate(allocator, (const void **)keys, (const void **)values, numValues, keyCallBacks, valueCallBacks);
}
CFArrayRef CFArrayCreateSafe2(CFAllocatorRef allocator, const uintptr_t *values, CFIndex numValues, const CFArrayCallBacks *callBacks) {
return CFArrayCreate(allocator, (const void **)values, numValues, callBacks);
}
*/
import "C"
import (
"errors"
"fmt"
"math"
"reflect"
"unicode/utf8"
"unsafe"
)
// Release releases memory pointed to by a CFTypeRef.
func Release(ref C.CFTypeRef) {
C.CFRelease(ref)
}
// BytesToCFData will return a CFDataRef and if non-nil, must be released with
// Release(ref).
func BytesToCFData(b []byte) (C.CFDataRef, error) {
if uint64(len(b)) > math.MaxUint32 {
return 0, errors.New("Data is too large")
}
var p *C.UInt8
if len(b) > 0 {
p = (*C.UInt8)(&b[0])
}
cfData := C.CFDataCreate(C.kCFAllocatorDefault, p, C.CFIndex(len(b)))
if cfData == 0 {
return 0, fmt.Errorf("CFDataCreate failed")
}
return cfData, nil
}
// CFDataToBytes converts CFData to bytes.
func CFDataToBytes(cfData C.CFDataRef) ([]byte, error) {
return C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(cfData)), C.int(C.CFDataGetLength(cfData))), nil
}
// MapToCFDictionary will return a CFDictionaryRef and if non-nil, must be
// released with Release(ref).
func MapToCFDictionary(m map[C.CFTypeRef]C.CFTypeRef) (C.CFDictionaryRef, error) {
var keys, values []C.uintptr_t
for key, value := range m {
keys = append(keys, C.uintptr_t(key))
values = append(values, C.uintptr_t(value))
}
numValues := len(values)
var keysPointer, valuesPointer *C.uintptr_t
if numValues > 0 {
keysPointer = &keys[0]
valuesPointer = &values[0]
}
cfDict := C.CFDictionaryCreateSafe2(C.kCFAllocatorDefault, keysPointer, valuesPointer, C.CFIndex(numValues),
&C.kCFTypeDictionaryKeyCallBacks, &C.kCFTypeDictionaryValueCallBacks) //nolint
if cfDict == 0 {
return 0, fmt.Errorf("CFDictionaryCreate failed")
}
return cfDict, nil
}
// CFDictionaryToMap converts CFDictionaryRef to a map.
func CFDictionaryToMap(cfDict C.CFDictionaryRef) (m map[C.CFTypeRef]C.CFTypeRef) {
count := C.CFDictionaryGetCount(cfDict)
if count > 0 {
keys := make([]C.CFTypeRef, count)
values := make([]C.CFTypeRef, count)
C.CFDictionaryGetKeysAndValues(cfDict, (*unsafe.Pointer)(unsafe.Pointer(&keys[0])), (*unsafe.Pointer)(unsafe.Pointer(&values[0])))
m = make(map[C.CFTypeRef]C.CFTypeRef, count)
for i := C.CFIndex(0); i < count; i++ {
m[keys[i]] = values[i]
}
}
return
}
// Int32ToCFNumber will return a CFNumberRef, must be released with Release(ref).
func Int32ToCFNumber(u int32) C.CFNumberRef {
sint := C.SInt32(u)
p := unsafe.Pointer(&sint)
return C.CFNumberCreate(C.kCFAllocatorDefault, C.kCFNumberSInt32Type, p)
}
// StringToCFString will return a CFStringRef and if non-nil, must be released with
// Release(ref).
func StringToCFString(s string) (C.CFStringRef, error) {
if !utf8.ValidString(s) {
return 0, errors.New("Invalid UTF-8 string")
}
if uint64(len(s)) > math.MaxUint32 {
return 0, errors.New("String is too large")
}
bytes := []byte(s)
var p *C.UInt8
if len(bytes) > 0 {
p = (*C.UInt8)(&bytes[0])
}
return C.CFStringCreateWithBytes(C.kCFAllocatorDefault, p, C.CFIndex(len(s)), C.kCFStringEncodingUTF8, C.false), nil
}
// CFStringToString converts a CFStringRef to a string.
func CFStringToString(s C.CFStringRef) string {
p := C.CFStringGetCStringPtr(s, C.kCFStringEncodingUTF8)
if p != nil {
return C.GoString(p)
}
length := C.CFStringGetLength(s)
if length == 0 {
return ""
}
maxBufLen := C.CFStringGetMaximumSizeForEncoding(length, C.kCFStringEncodingUTF8)
if maxBufLen == 0 {
return ""
}
buf := make([]byte, maxBufLen)
var usedBufLen C.CFIndex
_ = C.CFStringGetBytes(s, C.CFRange{0, length}, C.kCFStringEncodingUTF8, C.UInt8(0), C.false, (*C.UInt8)(&buf[0]), maxBufLen, &usedBufLen)
return string(buf[:usedBufLen])
}
// ArrayToCFArray will return a CFArrayRef and if non-nil, must be released with
// Release(ref).
func ArrayToCFArray(a []C.CFTypeRef) C.CFArrayRef {
var values []C.uintptr_t
for _, value := range a {
values = append(values, C.uintptr_t(value))
}
numValues := len(values)
var valuesPointer *C.uintptr_t
if numValues > 0 {
valuesPointer = &values[0]
}
return C.CFArrayCreateSafe2(C.kCFAllocatorDefault, valuesPointer, C.CFIndex(numValues), &C.kCFTypeArrayCallBacks) //nolint
}
// CFArrayToArray converts a CFArrayRef to an array of CFTypes.
func CFArrayToArray(cfArray C.CFArrayRef) (a []C.CFTypeRef) {
count := C.CFArrayGetCount(cfArray)
if count > 0 {
a = make([]C.CFTypeRef, count)
C.CFArrayGetValues(cfArray, C.CFRange{0, count}, (*unsafe.Pointer)(unsafe.Pointer(&a[0])))
}
return
}
// Convertable knows how to convert an instance to a CFTypeRef.
type Convertable interface {
Convert() (C.CFTypeRef, error)
}
// ConvertMapToCFDictionary converts a map to a CFDictionary and if non-nil,
// must be released with Release(ref).
func ConvertMapToCFDictionary(attr map[string]interface{}) (C.CFDictionaryRef, error) {
m := make(map[C.CFTypeRef]C.CFTypeRef)
for key, i := range attr {
var valueRef C.CFTypeRef
switch val := i.(type) {
default:
return 0, fmt.Errorf("Unsupported value type: %v", reflect.TypeOf(i))
case C.CFTypeRef:
valueRef = val
case bool:
if val {
valueRef = C.CFTypeRef(C.kCFBooleanTrue)
} else {
valueRef = C.CFTypeRef(C.kCFBooleanFalse)
}
case int32:
valueRef = C.CFTypeRef(Int32ToCFNumber(val))
defer Release(valueRef)
case []byte:
bytesRef, err := BytesToCFData(val)
if err != nil {
return 0, err
}
valueRef = C.CFTypeRef(bytesRef)
defer Release(valueRef)
case string:
stringRef, err := StringToCFString(val)
if err != nil {
return 0, err
}
valueRef = C.CFTypeRef(stringRef)
defer Release(valueRef)
case Convertable:
convertedRef, err := val.Convert()
if err != nil {
return 0, err
}
valueRef = convertedRef
defer Release(valueRef)
}
keyRef, err := StringToCFString(key)
if err != nil {
return 0, err
}
m[C.CFTypeRef(keyRef)] = valueRef
defer Release(C.CFTypeRef(keyRef))
}
cfDict, err := MapToCFDictionary(m)
if err != nil {
return 0, err
}
return cfDict, nil
}
// CFTypeDescription returns type string for CFTypeRef.
func CFTypeDescription(ref C.CFTypeRef) string {
typeID := C.CFGetTypeID(ref)
typeDesc := C.CFCopyTypeIDDescription(typeID)
defer Release(C.CFTypeRef(typeDesc))
return CFStringToString(typeDesc)
}
// Convert converts a CFTypeRef to a go instance.
func Convert(ref C.CFTypeRef) (interface{}, error) {
typeID := C.CFGetTypeID(ref)
if typeID == C.CFStringGetTypeID() {
return CFStringToString(C.CFStringRef(ref)), nil
} else if typeID == C.CFDictionaryGetTypeID() {
return ConvertCFDictionary(C.CFDictionaryRef(ref))
} else if typeID == C.CFArrayGetTypeID() {
arr := CFArrayToArray(C.CFArrayRef(ref))
results := make([]interface{}, 0, len(arr))
for _, ref := range arr {
v, err := Convert(ref)
if err != nil {
return nil, err
}
results = append(results, v)
}
return results, nil
} else if typeID == C.CFDataGetTypeID() {
b, err := CFDataToBytes(C.CFDataRef(ref))
if err != nil {
return nil, err
}
return b, nil
} else if typeID == C.CFNumberGetTypeID() {
return CFNumberToInterface(C.CFNumberRef(ref)), nil
} else if typeID == C.CFBooleanGetTypeID() {
if C.CFBooleanGetValue(C.CFBooleanRef(ref)) != 0 {
return true, nil
}
return false, nil
}
return nil, fmt.Errorf("Invalid type: %s", CFTypeDescription(ref))
}
// ConvertCFDictionary converts a CFDictionary to map (deep).
func ConvertCFDictionary(d C.CFDictionaryRef) (map[interface{}]interface{}, error) {
m := CFDictionaryToMap(d)
result := make(map[interface{}]interface{})
for k, v := range m {
gk, err := Convert(k)
if err != nil {
return nil, err
}
gv, err := Convert(v)
if err != nil {
return nil, err
}
result[gk] = gv
}
return result, nil
}
// CFNumberToInterface converts the CFNumberRef to the most appropriate numeric
// type.
// This code is from github.com/kballard/go-osx-plist.
func CFNumberToInterface(cfNumber C.CFNumberRef) interface{} {
typ := C.CFNumberGetType(cfNumber)
switch typ {
case C.kCFNumberSInt8Type:
var sint C.SInt8
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&sint)) //nolint
return int8(sint)
case C.kCFNumberSInt16Type:
var sint C.SInt16
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&sint)) //nolint
return int16(sint)
case C.kCFNumberSInt32Type:
var sint C.SInt32
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&sint)) //nolint
return int32(sint)
case C.kCFNumberSInt64Type:
var sint C.SInt64
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&sint)) //nolint
return int64(sint)
case C.kCFNumberFloat32Type:
var float C.Float32
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&float)) //nolint
return float32(float)
case C.kCFNumberFloat64Type:
var float C.Float64
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&float)) //nolint
return float64(float)
case C.kCFNumberCharType:
var char C.char
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&char)) //nolint
return byte(char)
case C.kCFNumberShortType:
var short C.short
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&short)) //nolint
return int16(short)
case C.kCFNumberIntType:
var i C.int
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&i)) //nolint
return int32(i)
case C.kCFNumberLongType:
var long C.long
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&long)) //nolint
return int(long)
case C.kCFNumberLongLongType:
// This is the only type that may actually overflow us
var longlong C.longlong
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&longlong)) //nolint
return int64(longlong)
case C.kCFNumberFloatType:
var float C.float
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&float)) //nolint
return float32(float)
case C.kCFNumberDoubleType:
var double C.double
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&double)) //nolint
return float64(double)
case C.kCFNumberCFIndexType:
// CFIndex is a long
var index C.CFIndex
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&index)) //nolint
return int(index)
case C.kCFNumberNSIntegerType:
// We don't have a definition of NSInteger, but we know it's either an int or a long
var nsInt C.long
C.CFNumberGetValue(cfNumber, typ, unsafe.Pointer(&nsInt)) //nolint
return int(nsInt)
}
panic("Unknown CFNumber type")
}
+69
View File
@@ -0,0 +1,69 @@
//go:build darwin || ios
// +build darwin ios
package keychain
/*
#cgo LDFLAGS: -framework CoreFoundation
#include <CoreFoundation/CoreFoundation.h>
*/
import "C"
import (
"math"
"time"
)
const nsPerSec = 1000 * 1000 * 1000
// absoluteTimeIntervalSince1970() returns the number of seconds from
// the Unix epoch (1970-01-01T00:00:00+00:00) to the Core Foundation
// absolute reference date (2001-01-01T00:00:00+00:00). It should be
// exactly 978307200.
func absoluteTimeIntervalSince1970() int64 {
return int64(C.kCFAbsoluteTimeIntervalSince1970)
}
func unixToAbsoluteTime(s int64, ns int64) C.CFAbsoluteTime {
// Subtract as int64s first before converting to floating
// point to minimize precision loss (assuming the given time
// isn't much earlier than the Core Foundation absolute
// reference date).
abs := s - absoluteTimeIntervalSince1970()
return C.CFAbsoluteTime(abs) + C.CFTimeInterval(ns)/nsPerSec
}
func absoluteTimeToUnix(abs C.CFAbsoluteTime) (int64, int64) {
i, frac := math.Modf(float64(abs))
return int64(i) + absoluteTimeIntervalSince1970(), int64(frac * nsPerSec)
}
// TimeToCFDate will convert the given time.Time to a CFDateRef, which
// must be released with Release(ref).
func TimeToCFDate(t time.Time) C.CFDateRef {
s := t.Unix()
ns := int64(t.Nanosecond())
abs := unixToAbsoluteTime(s, ns)
return C.CFDateCreate(C.kCFAllocatorDefault, abs)
}
// CFDateToTime will convert the given CFDateRef to a time.Time.
func CFDateToTime(d C.CFDateRef) time.Time {
abs := C.CFDateGetAbsoluteTime(d)
s, ns := absoluteTimeToUnix(abs)
return time.Unix(s, ns)
}
// Wrappers around C functions for testing.
func cfDateToAbsoluteTime(d C.CFDateRef) C.CFAbsoluteTime {
return C.CFDateGetAbsoluteTime(d)
}
func absoluteTimeToCFDate(abs C.CFAbsoluteTime) C.CFDateRef {
return C.CFDateCreate(C.kCFAllocatorDefault, abs)
}
func releaseCFDate(d C.CFDateRef) {
Release(C.CFTypeRef(d))
}
+23
View File
@@ -0,0 +1,23 @@
//go:build darwin && ios
// +build darwin,ios
package keychain
/*
#cgo LDFLAGS: -framework CoreFoundation -framework Security
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
*/
import "C"
var AccessibleKey = attrKey(C.CFTypeRef(C.kSecAttrAccessible))
var accessibleTypeRef = map[Accessible]C.CFTypeRef{
AccessibleWhenUnlocked: C.CFTypeRef(C.kSecAttrAccessibleWhenUnlocked),
AccessibleAfterFirstUnlock: C.CFTypeRef(C.kSecAttrAccessibleAfterFirstUnlock),
AccessibleAlways: C.CFTypeRef(C.kSecAttrAccessibleAlways),
AccessibleWhenPasscodeSetThisDeviceOnly: C.CFTypeRef(C.kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly),
AccessibleWhenUnlockedThisDeviceOnly: C.CFTypeRef(C.kSecAttrAccessibleWhenUnlockedThisDeviceOnly),
AccessibleAfterFirstUnlockThisDeviceOnly: C.CFTypeRef(C.kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly),
AccessibleAccessibleAlwaysThisDeviceOnly: C.CFTypeRef(C.kSecAttrAccessibleAlwaysThisDeviceOnly),
}
+653
View File
@@ -0,0 +1,653 @@
//go:build darwin
// +build darwin
package keychain
// See https://developer.apple.com/library/ios/documentation/Security/Reference/keychainservices/index.html for the APIs used below.
// Also see https://developer.apple.com/library/ios/documentation/Security/Conceptual/keychainServConcepts/01introduction/introduction.html .
/*
#cgo LDFLAGS: -framework CoreFoundation -framework Security
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
*/
import "C"
import (
"fmt"
"time"
)
// Error defines keychain errors
type Error int
var (
// ErrorUnimplemented corresponds to errSecUnimplemented result code
ErrorUnimplemented = Error(C.errSecUnimplemented)
// ErrorParam corresponds to errSecParam result code
ErrorParam = Error(C.errSecParam)
// ErrorAllocate corresponds to errSecAllocate result code
ErrorAllocate = Error(C.errSecAllocate)
// ErrorNotAvailable corresponds to errSecNotAvailable result code
ErrorNotAvailable = Error(C.errSecNotAvailable)
// ErrorAuthFailed corresponds to errSecAuthFailed result code
ErrorAuthFailed = Error(C.errSecAuthFailed)
// ErrorDuplicateItem corresponds to errSecDuplicateItem result code
ErrorDuplicateItem = Error(C.errSecDuplicateItem)
// ErrorItemNotFound corresponds to errSecItemNotFound result code
ErrorItemNotFound = Error(C.errSecItemNotFound)
// ErrorInteractionNotAllowed corresponds to errSecInteractionNotAllowed result code
ErrorInteractionNotAllowed = Error(C.errSecInteractionNotAllowed)
// ErrorDecode corresponds to errSecDecode result code
ErrorDecode = Error(C.errSecDecode)
// ErrorNoSuchKeychain corresponds to errSecNoSuchKeychain result code
ErrorNoSuchKeychain = Error(C.errSecNoSuchKeychain)
// ErrorNoAccessForItem corresponds to errSecNoAccessForItem result code
ErrorNoAccessForItem = Error(C.errSecNoAccessForItem)
// ErrorReadOnly corresponds to errSecReadOnly result code
ErrorReadOnly = Error(C.errSecReadOnly)
// ErrorInvalidKeychain corresponds to errSecInvalidKeychain result code
ErrorInvalidKeychain = Error(C.errSecInvalidKeychain)
// ErrorDuplicateKeyChain corresponds to errSecDuplicateKeychain result code
ErrorDuplicateKeyChain = Error(C.errSecDuplicateKeychain)
// ErrorWrongVersion corresponds to errSecWrongSecVersion result code
ErrorWrongVersion = Error(C.errSecWrongSecVersion)
// ErrorReadonlyAttribute corresponds to errSecReadOnlyAttr result code
ErrorReadonlyAttribute = Error(C.errSecReadOnlyAttr)
// ErrorInvalidSearchRef corresponds to errSecInvalidSearchRef result code
ErrorInvalidSearchRef = Error(C.errSecInvalidSearchRef)
// ErrorInvalidItemRef corresponds to errSecInvalidItemRef result code
ErrorInvalidItemRef = Error(C.errSecInvalidItemRef)
// ErrorDataNotAvailable corresponds to errSecDataNotAvailable result code
ErrorDataNotAvailable = Error(C.errSecDataNotAvailable)
// ErrorDataNotModifiable corresponds to errSecDataNotModifiable result code
ErrorDataNotModifiable = Error(C.errSecDataNotModifiable)
// ErrorInvalidOwnerEdit corresponds to errSecInvalidOwnerEdit result code
ErrorInvalidOwnerEdit = Error(C.errSecInvalidOwnerEdit)
// ErrorUserCanceled corresponds to errSecUserCanceled result code
ErrorUserCanceled = Error(C.errSecUserCanceled)
)
func checkError(errCode C.OSStatus) error {
if errCode == C.errSecSuccess {
return nil
}
return Error(errCode)
}
func (k Error) Error() (msg string) {
// SecCopyErrorMessageString is only available on OSX, so derive manually.
// Messages derived from `$ security error $errcode`.
switch k {
case ErrorUnimplemented:
msg = "Function or operation not implemented."
case ErrorParam:
msg = "One or more parameters passed to the function were not valid."
case ErrorAllocate:
msg = "Failed to allocate memory."
case ErrorNotAvailable:
msg = "No keychain is available. You may need to restart your computer."
case ErrorAuthFailed:
msg = "The user name or passphrase you entered is not correct."
case ErrorDuplicateItem:
msg = "The specified item already exists in the keychain."
case ErrorItemNotFound:
msg = "The specified item could not be found in the keychain."
case ErrorInteractionNotAllowed:
msg = "User interaction is not allowed."
case ErrorDecode:
msg = "Unable to decode the provided data."
case ErrorNoSuchKeychain:
msg = "The specified keychain could not be found."
case ErrorNoAccessForItem:
msg = "The specified item has no access control."
case ErrorReadOnly:
msg = "Read-only error."
case ErrorReadonlyAttribute:
msg = "The attribute is read-only."
case ErrorInvalidKeychain:
msg = "The keychain is not valid."
case ErrorDuplicateKeyChain:
msg = "A keychain with the same name already exists."
case ErrorWrongVersion:
msg = "The version is incorrect."
case ErrorInvalidItemRef:
msg = "The item reference is invalid."
case ErrorInvalidSearchRef:
msg = "The search reference is invalid."
case ErrorDataNotAvailable:
msg = "The data is not available."
case ErrorDataNotModifiable:
msg = "The data is not modifiable."
case ErrorInvalidOwnerEdit:
msg = "An invalid attempt to change the owner of an item."
case ErrorUserCanceled:
msg = "User canceled the operation."
default:
msg = "Keychain Error."
}
return fmt.Sprintf("%s (%d)", msg, k)
}
// SecClass is the items class code
type SecClass int
// Keychain Item Classes
var (
/*
kSecClassGenericPassword item attributes:
kSecAttrAccess (OS X only)
kSecAttrAccessGroup (iOS; also OS X if kSecAttrSynchronizable specified)
kSecAttrAccessible (iOS; also OS X if kSecAttrSynchronizable specified)
kSecAttrAccount
kSecAttrService
*/
SecClassGenericPassword SecClass = 1
SecClassInternetPassword SecClass = 2
)
// SecClassKey is the key type for SecClass
var SecClassKey = attrKey(C.CFTypeRef(C.kSecClass))
var secClassTypeRef = map[SecClass]C.CFTypeRef{
SecClassGenericPassword: C.CFTypeRef(C.kSecClassGenericPassword),
SecClassInternetPassword: C.CFTypeRef(C.kSecClassInternetPassword),
}
var (
// ServiceKey is for kSecAttrService
ServiceKey = attrKey(C.CFTypeRef(C.kSecAttrService))
// ServerKey is for kSecAttrServer
ServerKey = attrKey(C.CFTypeRef(C.kSecAttrServer))
// ProtocolKey is for kSecAttrProtocol
ProtocolKey = attrKey(C.CFTypeRef(C.kSecAttrProtocol))
// AuthenticationTypeKey is for kSecAttrAuthenticationType
AuthenticationTypeKey = attrKey(C.CFTypeRef(C.kSecAttrAuthenticationType))
// PortKey is for kSecAttrPort
PortKey = attrKey(C.CFTypeRef(C.kSecAttrPort))
// PathKey is for kSecAttrPath
PathKey = attrKey(C.CFTypeRef(C.kSecAttrPath))
// LabelKey is for kSecAttrLabel
LabelKey = attrKey(C.CFTypeRef(C.kSecAttrLabel))
// AccountKey is for kSecAttrAccount
AccountKey = attrKey(C.CFTypeRef(C.kSecAttrAccount))
// AccessGroupKey is for kSecAttrAccessGroup
AccessGroupKey = attrKey(C.CFTypeRef(C.kSecAttrAccessGroup))
// DataKey is for kSecValueData
DataKey = attrKey(C.CFTypeRef(C.kSecValueData))
// DescriptionKey is for kSecAttrDescription
DescriptionKey = attrKey(C.CFTypeRef(C.kSecAttrDescription))
// CommentKey is for kSecAttrComment
CommentKey = attrKey(C.CFTypeRef(C.kSecAttrComment))
// CreationDateKey is for kSecAttrCreationDate
CreationDateKey = attrKey(C.CFTypeRef(C.kSecAttrCreationDate))
// ModificationDateKey is for kSecAttrModificationDate
ModificationDateKey = attrKey(C.CFTypeRef(C.kSecAttrModificationDate))
)
// Synchronizable is the items synchronizable status
type Synchronizable int
const (
// SynchronizableDefault is the default setting
SynchronizableDefault Synchronizable = 0
// SynchronizableAny is for kSecAttrSynchronizableAny
SynchronizableAny = 1
// SynchronizableYes enables synchronization
SynchronizableYes = 2
// SynchronizableNo disables synchronization
SynchronizableNo = 3
)
// SynchronizableKey is the key type for Synchronizable
var SynchronizableKey = attrKey(C.CFTypeRef(C.kSecAttrSynchronizable))
var syncTypeRef = map[Synchronizable]C.CFTypeRef{
SynchronizableAny: C.CFTypeRef(C.kSecAttrSynchronizableAny),
SynchronizableYes: C.CFTypeRef(C.kCFBooleanTrue),
SynchronizableNo: C.CFTypeRef(C.kCFBooleanFalse),
}
// Accessible is the items accessibility
type Accessible int
const (
// AccessibleDefault is the default
AccessibleDefault Accessible = 0
// AccessibleWhenUnlocked is when unlocked
AccessibleWhenUnlocked = 1
// AccessibleAfterFirstUnlock is after first unlock
AccessibleAfterFirstUnlock = 2
// AccessibleAlways is always
AccessibleAlways = 3
// AccessibleWhenPasscodeSetThisDeviceOnly is when passcode is set
AccessibleWhenPasscodeSetThisDeviceOnly = 4
// AccessibleWhenUnlockedThisDeviceOnly is when unlocked for this device only
AccessibleWhenUnlockedThisDeviceOnly = 5
// AccessibleAfterFirstUnlockThisDeviceOnly is after first unlock for this device only
AccessibleAfterFirstUnlockThisDeviceOnly = 6
// AccessibleAccessibleAlwaysThisDeviceOnly is always for this device only
AccessibleAccessibleAlwaysThisDeviceOnly = 7
)
// MatchLimit is whether to limit results on query
type MatchLimit int
const (
// MatchLimitDefault is the default
MatchLimitDefault MatchLimit = 0
// MatchLimitOne limits to one result
MatchLimitOne = 1
// MatchLimitAll is no limit
MatchLimitAll = 2
)
// MatchLimitKey is key type for MatchLimit
var MatchLimitKey = attrKey(C.CFTypeRef(C.kSecMatchLimit))
var matchTypeRef = map[MatchLimit]C.CFTypeRef{
MatchLimitOne: C.CFTypeRef(C.kSecMatchLimitOne),
MatchLimitAll: C.CFTypeRef(C.kSecMatchLimitAll),
}
// ReturnAttributesKey is key type for kSecReturnAttributes
var ReturnAttributesKey = attrKey(C.CFTypeRef(C.kSecReturnAttributes))
// ReturnDataKey is key type for kSecReturnData
var ReturnDataKey = attrKey(C.CFTypeRef(C.kSecReturnData))
// ReturnRefKey is key type for kSecReturnRef
var ReturnRefKey = attrKey(C.CFTypeRef(C.kSecReturnRef))
// Item for adding, querying or deleting.
type Item struct {
// Values can be string, []byte, Convertable or CFTypeRef (constant).
attr map[string]interface{}
}
// SetSecClass sets the security class
func (k *Item) SetSecClass(sc SecClass) {
k.attr[SecClassKey] = secClassTypeRef[sc]
}
// SetInt32 sets an int32 attribute for a string key
func (k *Item) SetInt32(key string, v int32) {
if v != 0 {
k.attr[key] = v
} else {
delete(k.attr, key)
}
}
// SetString sets a string attibute for a string key
func (k *Item) SetString(key string, s string) {
if s != "" {
k.attr[key] = s
} else {
delete(k.attr, key)
}
}
// SetService sets the service attribute (for generic application items)
func (k *Item) SetService(s string) {
k.SetString(ServiceKey, s)
}
// SetServer sets the server attribute (for internet password items)
func (k *Item) SetServer(s string) {
k.SetString(ServerKey, s)
}
// SetProtocol sets the protocol attribute (for internet password items)
// Example values are: "htps", "http", "smb "
func (k *Item) SetProtocol(s string) {
k.SetString(ProtocolKey, s)
}
// SetAuthenticationType sets the authentication type attribute (for internet password items)
func (k *Item) SetAuthenticationType(s string) {
k.SetString(AuthenticationTypeKey, s)
}
// SetPort sets the port attribute (for internet password items)
func (k *Item) SetPort(v int32) {
k.SetInt32(PortKey, v)
}
// SetPath sets the path attribute (for internet password items)
func (k *Item) SetPath(s string) {
k.SetString(PathKey, s)
}
// SetAccount sets the account attribute
func (k *Item) SetAccount(a string) {
k.SetString(AccountKey, a)
}
// SetLabel sets the label attribute
func (k *Item) SetLabel(l string) {
k.SetString(LabelKey, l)
}
// SetDescription sets the description attribute
func (k *Item) SetDescription(s string) {
k.SetString(DescriptionKey, s)
}
// SetComment sets the comment attribute
func (k *Item) SetComment(s string) {
k.SetString(CommentKey, s)
}
// SetData sets the data attribute
func (k *Item) SetData(b []byte) {
if b != nil {
k.attr[DataKey] = b
} else {
delete(k.attr, DataKey)
}
}
// SetAccessGroup sets the access group attribute
func (k *Item) SetAccessGroup(ag string) {
k.SetString(AccessGroupKey, ag)
}
// SetSynchronizable sets the synchronizable attribute
func (k *Item) SetSynchronizable(sync Synchronizable) {
if sync != SynchronizableDefault {
k.attr[SynchronizableKey] = syncTypeRef[sync]
} else {
delete(k.attr, SynchronizableKey)
}
}
// SetAccessible sets the accessible attribute
func (k *Item) SetAccessible(accessible Accessible) {
if accessible != AccessibleDefault {
k.attr[AccessibleKey] = accessibleTypeRef[accessible]
} else {
delete(k.attr, AccessibleKey)
}
}
// SetMatchLimit sets the match limit
func (k *Item) SetMatchLimit(matchLimit MatchLimit) {
if matchLimit != MatchLimitDefault {
k.attr[MatchLimitKey] = matchTypeRef[matchLimit]
} else {
delete(k.attr, MatchLimitKey)
}
}
// SetReturnAttributes sets the return value type on query
func (k *Item) SetReturnAttributes(b bool) {
k.attr[ReturnAttributesKey] = b
}
// SetReturnData enables returning data on query
func (k *Item) SetReturnData(b bool) {
k.attr[ReturnDataKey] = b
}
// SetReturnRef enables returning references on query
func (k *Item) SetReturnRef(b bool) {
k.attr[ReturnRefKey] = b
}
// NewItem is a new empty keychain item
func NewItem() Item {
return Item{make(map[string]interface{})}
}
// NewGenericPassword creates a generic password item with the default keychain. This is a convenience method.
func NewGenericPassword(service string, account string, label string, data []byte, accessGroup string) Item {
item := NewItem()
item.SetSecClass(SecClassGenericPassword)
item.SetService(service)
item.SetAccount(account)
item.SetLabel(label)
item.SetData(data)
item.SetAccessGroup(accessGroup)
return item
}
// AddItem adds a Item to a Keychain
func AddItem(item Item) error {
cfDict, err := ConvertMapToCFDictionary(item.attr)
if err != nil {
return err
}
defer Release(C.CFTypeRef(cfDict))
errCode := C.SecItemAdd(cfDict, nil)
err = checkError(errCode)
return err
}
// UpdateItem updates the queryItem with the parameters from updateItem
func UpdateItem(queryItem Item, updateItem Item) error {
cfDict, err := ConvertMapToCFDictionary(queryItem.attr)
if err != nil {
return err
}
defer Release(C.CFTypeRef(cfDict))
cfDictUpdate, err := ConvertMapToCFDictionary(updateItem.attr)
if err != nil {
return err
}
defer Release(C.CFTypeRef(cfDictUpdate))
errCode := C.SecItemUpdate(cfDict, cfDictUpdate)
err = checkError(errCode)
return err
}
// QueryResult stores all possible results from queries.
// Not all fields are applicable all the time. Results depend on query.
type QueryResult struct {
// For generic application items
Service string
// For internet password items
Server string
Protocol string
AuthenticationType string
Port int32
Path string
Account string
AccessGroup string
Label string
Description string
Comment string
Data []byte
CreationDate time.Time
ModificationDate time.Time
}
// QueryItemRef returns query result as CFTypeRef. You must release it when you are done.
func QueryItemRef(item Item) (C.CFTypeRef, error) {
cfDict, err := ConvertMapToCFDictionary(item.attr)
if err != nil {
return 0, err
}
defer Release(C.CFTypeRef(cfDict))
var resultsRef C.CFTypeRef
errCode := C.SecItemCopyMatching(cfDict, &resultsRef) //nolint
if Error(errCode) == ErrorItemNotFound {
return 0, nil
}
err = checkError(errCode)
if err != nil {
return 0, err
}
return resultsRef, nil
}
// QueryItem returns a list of query results.
func QueryItem(item Item) ([]QueryResult, error) {
resultsRef, err := QueryItemRef(item)
if err != nil {
return nil, err
}
if resultsRef == 0 {
return nil, nil
}
defer Release(resultsRef)
results := make([]QueryResult, 0, 1)
typeID := C.CFGetTypeID(resultsRef)
if typeID == C.CFArrayGetTypeID() {
arr := CFArrayToArray(C.CFArrayRef(resultsRef))
for _, ref := range arr {
elementTypeID := C.CFGetTypeID(ref)
if elementTypeID == C.CFDictionaryGetTypeID() {
item, err := convertResult(C.CFDictionaryRef(ref))
if err != nil {
return nil, err
}
results = append(results, *item)
} else {
return nil, fmt.Errorf("invalid result type (If you SetReturnRef(true) you should use QueryItemRef directly)")
}
}
} else if typeID == C.CFDictionaryGetTypeID() {
item, err := convertResult(C.CFDictionaryRef(resultsRef))
if err != nil {
return nil, err
}
results = append(results, *item)
} else if typeID == C.CFDataGetTypeID() {
b, err := CFDataToBytes(C.CFDataRef(resultsRef))
if err != nil {
return nil, err
}
item := QueryResult{Data: b}
results = append(results, item)
} else {
return nil, fmt.Errorf("Invalid result type: %s", CFTypeDescription(resultsRef))
}
return results, nil
}
func attrKey(ref C.CFTypeRef) string {
return CFStringToString(C.CFStringRef(ref))
}
func convertResult(d C.CFDictionaryRef) (*QueryResult, error) {
m := CFDictionaryToMap(d)
result := QueryResult{}
for k, v := range m {
switch attrKey(k) {
case ServiceKey:
result.Service = CFStringToString(C.CFStringRef(v))
case ServerKey:
result.Server = CFStringToString(C.CFStringRef(v))
case ProtocolKey:
result.Protocol = CFStringToString(C.CFStringRef(v))
case AuthenticationTypeKey:
result.AuthenticationType = CFStringToString(C.CFStringRef(v))
case PortKey:
val := CFNumberToInterface(C.CFNumberRef(v))
result.Port = val.(int32)
case PathKey:
result.Path = CFStringToString(C.CFStringRef(v))
case AccountKey:
result.Account = CFStringToString(C.CFStringRef(v))
case AccessGroupKey:
result.AccessGroup = CFStringToString(C.CFStringRef(v))
case LabelKey:
result.Label = CFStringToString(C.CFStringRef(v))
case DescriptionKey:
result.Description = CFStringToString(C.CFStringRef(v))
case CommentKey:
result.Comment = CFStringToString(C.CFStringRef(v))
case DataKey:
b, err := CFDataToBytes(C.CFDataRef(v))
if err != nil {
return nil, err
}
result.Data = b
case CreationDateKey:
result.CreationDate = CFDateToTime(C.CFDateRef(v))
case ModificationDateKey:
result.ModificationDate = CFDateToTime(C.CFDateRef(v))
// default:
// fmt.Printf("Unhandled key in conversion: %v = %v\n", cfTypeValue(k), cfTypeValue(v))
}
}
return &result, nil
}
// DeleteGenericPasswordItem removes a generic password item.
func DeleteGenericPasswordItem(service string, account string) error {
item := NewItem()
item.SetSecClass(SecClassGenericPassword)
item.SetService(service)
item.SetAccount(account)
return DeleteItem(item)
}
// DeleteItem removes a Item
func DeleteItem(item Item) error {
cfDict, err := ConvertMapToCFDictionary(item.attr)
if err != nil {
return err
}
defer Release(C.CFTypeRef(cfDict))
errCode := C.SecItemDelete(cfDict)
return checkError(errCode)
}
// GetAccountsForService is deprecated
func GetAccountsForService(service string) ([]string, error) {
return GetGenericPasswordAccounts(service)
}
// GetGenericPasswordAccounts returns generic password accounts for service. This is a convenience method.
func GetGenericPasswordAccounts(service string) ([]string, error) {
query := NewItem()
query.SetSecClass(SecClassGenericPassword)
query.SetService(service)
query.SetMatchLimit(MatchLimitAll)
query.SetReturnAttributes(true)
results, err := QueryItem(query)
if err != nil {
return nil, err
}
accounts := make([]string, 0, len(results))
for _, r := range results {
accounts = append(accounts, r.Account)
}
return accounts, nil
}
// GetGenericPassword returns password data for service and account. This is a convenience method.
// If item is not found returns nil, nil.
func GetGenericPassword(service string, account string, label string, accessGroup string) ([]byte, error) {
query := NewItem()
query.SetSecClass(SecClassGenericPassword)
query.SetService(service)
query.SetAccount(account)
query.SetLabel(label)
query.SetAccessGroup(accessGroup)
query.SetMatchLimit(MatchLimitOne)
query.SetReturnData(true)
results, err := QueryItem(query)
if err != nil {
return nil, err
}
if len(results) > 1 {
return nil, fmt.Errorf("Too many results")
}
if len(results) == 1 {
return results[0].Data, nil
}
return nil, nil
}
+25
View File
@@ -0,0 +1,25 @@
//go:build darwin && !ios
// +build darwin,!ios
package keychain
/*
#cgo LDFLAGS: -framework CoreFoundation -framework Security
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
*/
import "C"
// AccessibleKey is key for kSecAttrAccessible
var AccessibleKey = attrKey(C.CFTypeRef(C.kSecAttrAccessible))
var accessibleTypeRef = map[Accessible]C.CFTypeRef{
AccessibleWhenUnlocked: C.CFTypeRef(C.kSecAttrAccessibleWhenUnlocked),
AccessibleAfterFirstUnlock: C.CFTypeRef(C.kSecAttrAccessibleAfterFirstUnlock),
AccessibleAlways: C.CFTypeRef(C.kSecAttrAccessibleAlways),
AccessibleWhenUnlockedThisDeviceOnly: C.CFTypeRef(C.kSecAttrAccessibleWhenUnlockedThisDeviceOnly),
AccessibleAfterFirstUnlockThisDeviceOnly: C.CFTypeRef(C.kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly),
AccessibleAccessibleAlwaysThisDeviceOnly: C.CFTypeRef(C.kSecAttrAccessibleAlwaysThisDeviceOnly),
// Only available in 10.10
//AccessibleWhenPasscodeSetThisDeviceOnly: C.CFTypeRef(C.kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly),
}
+31
View File
@@ -0,0 +1,31 @@
package keychain
import (
"crypto/rand"
"encoding/base32"
"strings"
)
var randRead = rand.Read
// RandomID returns random ID (base32) string with prefix, using 256 bits as
// recommended by tptacek: https://gist.github.com/tqbf/be58d2d39690c3b366ad
func RandomID(prefix string) (string, error) {
buf, err := RandBytes(32)
if err != nil {
return "", err
}
str := base32.StdEncoding.EncodeToString(buf)
str = strings.ReplaceAll(str, "=", "")
str = prefix + str
return str, nil
}
// RandBytes returns random bytes of length
func RandBytes(length int) ([]byte, error) {
buf := make([]byte, length)
if _, err := randRead(buf); err != nil {
return nil, err
}
return buf, nil
}
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build windows && go1.9 //go:build windows
package windows package windows
-8
View File
@@ -1,8 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !go1.12
// This file is here to allow bodyless functions with go:linkname for Go 1.11
// and earlier (see https://golang.org/issue/23311).
+10 -7
View File
@@ -37,14 +37,17 @@ func (token Token) Environ(inheritExisting bool) (env []string, err error) {
return nil, err return nil, err
} }
defer DestroyEnvironmentBlock(block) defer DestroyEnvironmentBlock(block)
blockp := unsafe.Pointer(block) size := unsafe.Sizeof(*block)
for { for *block != 0 {
entry := UTF16PtrToString((*uint16)(blockp)) // find NUL terminator
if len(entry) == 0 { end := unsafe.Pointer(block)
break for *(*uint16)(end) != 0 {
end = unsafe.Add(end, size)
} }
env = append(env, entry)
blockp = unsafe.Add(blockp, 2*(len(entry)+1)) entry := unsafe.Slice(block, (uintptr(end)-uintptr(unsafe.Pointer(block)))/size)
env = append(env, UTF16ToString(entry))
block = (*uint16)(unsafe.Add(end, size))
} }
return env, nil return env, nil
} }
+84 -2
View File
@@ -125,8 +125,7 @@ func UTF16PtrToString(p *uint16) string {
for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ { for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ {
ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p)) ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p))
} }
return UTF16ToString(unsafe.Slice(p, n))
return string(utf16.Decode(unsafe.Slice(p, n)))
} }
func Getpagesize() int { return 4096 } func Getpagesize() int { return 4096 }
@@ -166,6 +165,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile Handle) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW //sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile Handle) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
//sys CreateNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *SecurityAttributes) (handle Handle, err error) [failretval==InvalidHandle] = CreateNamedPipeW //sys CreateNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *SecurityAttributes) (handle Handle, err error) [failretval==InvalidHandle] = CreateNamedPipeW
//sys ConnectNamedPipe(pipe Handle, overlapped *Overlapped) (err error) //sys ConnectNamedPipe(pipe Handle, overlapped *Overlapped) (err error)
//sys DisconnectNamedPipe(pipe Handle) (err error)
//sys GetNamedPipeInfo(pipe Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) //sys GetNamedPipeInfo(pipe Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error)
//sys GetNamedPipeHandleState(pipe Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW //sys GetNamedPipeHandleState(pipe Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
//sys SetNamedPipeHandleState(pipe Handle, state *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32) (err error) = SetNamedPipeHandleState //sys SetNamedPipeHandleState(pipe Handle, state *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32) (err error) = SetNamedPipeHandleState
@@ -194,6 +194,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW //sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW //sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
//sys SetEndOfFile(handle Handle) (err error) //sys SetEndOfFile(handle Handle) (err error)
//sys SetFileValidData(handle Handle, validDataLength int64) (err error)
//sys GetSystemTimeAsFileTime(time *Filetime) //sys GetSystemTimeAsFileTime(time *Filetime)
//sys GetSystemTimePreciseAsFileTime(time *Filetime) //sys GetSystemTimePreciseAsFileTime(time *Filetime)
//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] //sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]
@@ -348,8 +349,19 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys SetProcessPriorityBoost(process Handle, disable bool) (err error) = kernel32.SetProcessPriorityBoost //sys SetProcessPriorityBoost(process Handle, disable bool) (err error) = kernel32.SetProcessPriorityBoost
//sys GetProcessWorkingSetSizeEx(hProcess Handle, lpMinimumWorkingSetSize *uintptr, lpMaximumWorkingSetSize *uintptr, flags *uint32) //sys GetProcessWorkingSetSizeEx(hProcess Handle, lpMinimumWorkingSetSize *uintptr, lpMaximumWorkingSetSize *uintptr, flags *uint32)
//sys SetProcessWorkingSetSizeEx(hProcess Handle, dwMinimumWorkingSetSize uintptr, dwMaximumWorkingSetSize uintptr, flags uint32) (err error) //sys SetProcessWorkingSetSizeEx(hProcess Handle, dwMinimumWorkingSetSize uintptr, dwMaximumWorkingSetSize uintptr, flags uint32) (err error)
//sys ClearCommBreak(handle Handle) (err error)
//sys ClearCommError(handle Handle, lpErrors *uint32, lpStat *ComStat) (err error)
//sys EscapeCommFunction(handle Handle, dwFunc uint32) (err error)
//sys GetCommState(handle Handle, lpDCB *DCB) (err error)
//sys GetCommModemStatus(handle Handle, lpModemStat *uint32) (err error)
//sys GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) //sys GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error)
//sys PurgeComm(handle Handle, dwFlags uint32) (err error)
//sys SetCommBreak(handle Handle) (err error)
//sys SetCommMask(handle Handle, dwEvtMask uint32) (err error)
//sys SetCommState(handle Handle, lpDCB *DCB) (err error)
//sys SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) //sys SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error)
//sys SetupComm(handle Handle, dwInQueue uint32, dwOutQueue uint32) (err error)
//sys WaitCommEvent(handle Handle, lpEvtMask *uint32, lpOverlapped *Overlapped) (err error)
//sys GetActiveProcessorCount(groupNumber uint16) (ret uint32) //sys GetActiveProcessorCount(groupNumber uint16) (ret uint32)
//sys GetMaximumProcessorCount(groupNumber uint16) (ret uint32) //sys GetMaximumProcessorCount(groupNumber uint16) (ret uint32)
//sys EnumWindows(enumFunc uintptr, param unsafe.Pointer) (err error) = user32.EnumWindows //sys EnumWindows(enumFunc uintptr, param unsafe.Pointer) (err error) = user32.EnumWindows
@@ -1834,3 +1846,73 @@ func ResizePseudoConsole(pconsole Handle, size Coord) error {
// accept arguments that can be casted to uintptr, and Coord can't. // accept arguments that can be casted to uintptr, and Coord can't.
return resizePseudoConsole(pconsole, *((*uint32)(unsafe.Pointer(&size)))) return resizePseudoConsole(pconsole, *((*uint32)(unsafe.Pointer(&size))))
} }
// DCB constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-dcb.
const (
CBR_110 = 110
CBR_300 = 300
CBR_600 = 600
CBR_1200 = 1200
CBR_2400 = 2400
CBR_4800 = 4800
CBR_9600 = 9600
CBR_14400 = 14400
CBR_19200 = 19200
CBR_38400 = 38400
CBR_57600 = 57600
CBR_115200 = 115200
CBR_128000 = 128000
CBR_256000 = 256000
DTR_CONTROL_DISABLE = 0x00000000
DTR_CONTROL_ENABLE = 0x00000010
DTR_CONTROL_HANDSHAKE = 0x00000020
RTS_CONTROL_DISABLE = 0x00000000
RTS_CONTROL_ENABLE = 0x00001000
RTS_CONTROL_HANDSHAKE = 0x00002000
RTS_CONTROL_TOGGLE = 0x00003000
NOPARITY = 0
ODDPARITY = 1
EVENPARITY = 2
MARKPARITY = 3
SPACEPARITY = 4
ONESTOPBIT = 0
ONE5STOPBITS = 1
TWOSTOPBITS = 2
)
// EscapeCommFunction constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-escapecommfunction.
const (
SETXOFF = 1
SETXON = 2
SETRTS = 3
CLRRTS = 4
SETDTR = 5
CLRDTR = 6
SETBREAK = 8
CLRBREAK = 9
)
// PurgeComm constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-purgecomm.
const (
PURGE_TXABORT = 0x0001
PURGE_RXABORT = 0x0002
PURGE_TXCLEAR = 0x0004
PURGE_RXCLEAR = 0x0008
)
// SetCommMask constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setcommmask.
const (
EV_RXCHAR = 0x0001
EV_RXFLAG = 0x0002
EV_TXEMPTY = 0x0004
EV_CTS = 0x0008
EV_DSR = 0x0010
EV_RLSD = 0x0020
EV_BREAK = 0x0040
EV_ERR = 0x0080
EV_RING = 0x0100
)
+24
View File
@@ -3380,3 +3380,27 @@ type BLOB struct {
Size uint32 Size uint32
BlobData *byte BlobData *byte
} }
type ComStat struct {
Flags uint32
CBInQue uint32
CBOutQue uint32
}
type DCB struct {
DCBlength uint32
BaudRate uint32
Flags uint32
wReserved uint16
XonLim uint16
XoffLim uint16
ByteSize uint8
Parity uint8
StopBits uint8
XonChar byte
XoffChar byte
ErrorChar byte
EofChar byte
EvtChar byte
wReserved1 uint16
}
+117
View File
@@ -188,6 +188,8 @@ var (
procAssignProcessToJobObject = modkernel32.NewProc("AssignProcessToJobObject") procAssignProcessToJobObject = modkernel32.NewProc("AssignProcessToJobObject")
procCancelIo = modkernel32.NewProc("CancelIo") procCancelIo = modkernel32.NewProc("CancelIo")
procCancelIoEx = modkernel32.NewProc("CancelIoEx") procCancelIoEx = modkernel32.NewProc("CancelIoEx")
procClearCommBreak = modkernel32.NewProc("ClearCommBreak")
procClearCommError = modkernel32.NewProc("ClearCommError")
procCloseHandle = modkernel32.NewProc("CloseHandle") procCloseHandle = modkernel32.NewProc("CloseHandle")
procClosePseudoConsole = modkernel32.NewProc("ClosePseudoConsole") procClosePseudoConsole = modkernel32.NewProc("ClosePseudoConsole")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe") procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
@@ -212,7 +214,9 @@ var (
procDeleteProcThreadAttributeList = modkernel32.NewProc("DeleteProcThreadAttributeList") procDeleteProcThreadAttributeList = modkernel32.NewProc("DeleteProcThreadAttributeList")
procDeleteVolumeMountPointW = modkernel32.NewProc("DeleteVolumeMountPointW") procDeleteVolumeMountPointW = modkernel32.NewProc("DeleteVolumeMountPointW")
procDeviceIoControl = modkernel32.NewProc("DeviceIoControl") procDeviceIoControl = modkernel32.NewProc("DeviceIoControl")
procDisconnectNamedPipe = modkernel32.NewProc("DisconnectNamedPipe")
procDuplicateHandle = modkernel32.NewProc("DuplicateHandle") procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
procEscapeCommFunction = modkernel32.NewProc("EscapeCommFunction")
procExitProcess = modkernel32.NewProc("ExitProcess") procExitProcess = modkernel32.NewProc("ExitProcess")
procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW") procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW")
procFindClose = modkernel32.NewProc("FindClose") procFindClose = modkernel32.NewProc("FindClose")
@@ -236,6 +240,8 @@ var (
procGenerateConsoleCtrlEvent = modkernel32.NewProc("GenerateConsoleCtrlEvent") procGenerateConsoleCtrlEvent = modkernel32.NewProc("GenerateConsoleCtrlEvent")
procGetACP = modkernel32.NewProc("GetACP") procGetACP = modkernel32.NewProc("GetACP")
procGetActiveProcessorCount = modkernel32.NewProc("GetActiveProcessorCount") procGetActiveProcessorCount = modkernel32.NewProc("GetActiveProcessorCount")
procGetCommModemStatus = modkernel32.NewProc("GetCommModemStatus")
procGetCommState = modkernel32.NewProc("GetCommState")
procGetCommTimeouts = modkernel32.NewProc("GetCommTimeouts") procGetCommTimeouts = modkernel32.NewProc("GetCommTimeouts")
procGetCommandLineW = modkernel32.NewProc("GetCommandLineW") procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW")
@@ -322,6 +328,7 @@ var (
procProcess32NextW = modkernel32.NewProc("Process32NextW") procProcess32NextW = modkernel32.NewProc("Process32NextW")
procProcessIdToSessionId = modkernel32.NewProc("ProcessIdToSessionId") procProcessIdToSessionId = modkernel32.NewProc("ProcessIdToSessionId")
procPulseEvent = modkernel32.NewProc("PulseEvent") procPulseEvent = modkernel32.NewProc("PulseEvent")
procPurgeComm = modkernel32.NewProc("PurgeComm")
procQueryDosDeviceW = modkernel32.NewProc("QueryDosDeviceW") procQueryDosDeviceW = modkernel32.NewProc("QueryDosDeviceW")
procQueryFullProcessImageNameW = modkernel32.NewProc("QueryFullProcessImageNameW") procQueryFullProcessImageNameW = modkernel32.NewProc("QueryFullProcessImageNameW")
procQueryInformationJobObject = modkernel32.NewProc("QueryInformationJobObject") procQueryInformationJobObject = modkernel32.NewProc("QueryInformationJobObject")
@@ -335,6 +342,9 @@ var (
procResetEvent = modkernel32.NewProc("ResetEvent") procResetEvent = modkernel32.NewProc("ResetEvent")
procResizePseudoConsole = modkernel32.NewProc("ResizePseudoConsole") procResizePseudoConsole = modkernel32.NewProc("ResizePseudoConsole")
procResumeThread = modkernel32.NewProc("ResumeThread") procResumeThread = modkernel32.NewProc("ResumeThread")
procSetCommBreak = modkernel32.NewProc("SetCommBreak")
procSetCommMask = modkernel32.NewProc("SetCommMask")
procSetCommState = modkernel32.NewProc("SetCommState")
procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts") procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts")
procSetConsoleCursorPosition = modkernel32.NewProc("SetConsoleCursorPosition") procSetConsoleCursorPosition = modkernel32.NewProc("SetConsoleCursorPosition")
procSetConsoleMode = modkernel32.NewProc("SetConsoleMode") procSetConsoleMode = modkernel32.NewProc("SetConsoleMode")
@@ -350,6 +360,7 @@ var (
procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle") procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle")
procSetFilePointer = modkernel32.NewProc("SetFilePointer") procSetFilePointer = modkernel32.NewProc("SetFilePointer")
procSetFileTime = modkernel32.NewProc("SetFileTime") procSetFileTime = modkernel32.NewProc("SetFileTime")
procSetFileValidData = modkernel32.NewProc("SetFileValidData")
procSetHandleInformation = modkernel32.NewProc("SetHandleInformation") procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
procSetInformationJobObject = modkernel32.NewProc("SetInformationJobObject") procSetInformationJobObject = modkernel32.NewProc("SetInformationJobObject")
procSetNamedPipeHandleState = modkernel32.NewProc("SetNamedPipeHandleState") procSetNamedPipeHandleState = modkernel32.NewProc("SetNamedPipeHandleState")
@@ -360,6 +371,7 @@ var (
procSetStdHandle = modkernel32.NewProc("SetStdHandle") procSetStdHandle = modkernel32.NewProc("SetStdHandle")
procSetVolumeLabelW = modkernel32.NewProc("SetVolumeLabelW") procSetVolumeLabelW = modkernel32.NewProc("SetVolumeLabelW")
procSetVolumeMountPointW = modkernel32.NewProc("SetVolumeMountPointW") procSetVolumeMountPointW = modkernel32.NewProc("SetVolumeMountPointW")
procSetupComm = modkernel32.NewProc("SetupComm")
procSizeofResource = modkernel32.NewProc("SizeofResource") procSizeofResource = modkernel32.NewProc("SizeofResource")
procSleepEx = modkernel32.NewProc("SleepEx") procSleepEx = modkernel32.NewProc("SleepEx")
procTerminateJobObject = modkernel32.NewProc("TerminateJobObject") procTerminateJobObject = modkernel32.NewProc("TerminateJobObject")
@@ -378,6 +390,7 @@ var (
procVirtualQueryEx = modkernel32.NewProc("VirtualQueryEx") procVirtualQueryEx = modkernel32.NewProc("VirtualQueryEx")
procVirtualUnlock = modkernel32.NewProc("VirtualUnlock") procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
procWTSGetActiveConsoleSessionId = modkernel32.NewProc("WTSGetActiveConsoleSessionId") procWTSGetActiveConsoleSessionId = modkernel32.NewProc("WTSGetActiveConsoleSessionId")
procWaitCommEvent = modkernel32.NewProc("WaitCommEvent")
procWaitForMultipleObjects = modkernel32.NewProc("WaitForMultipleObjects") procWaitForMultipleObjects = modkernel32.NewProc("WaitForMultipleObjects")
procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject") procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
procWriteConsoleW = modkernel32.NewProc("WriteConsoleW") procWriteConsoleW = modkernel32.NewProc("WriteConsoleW")
@@ -1640,6 +1653,22 @@ func CancelIoEx(s Handle, o *Overlapped) (err error) {
return return
} }
func ClearCommBreak(handle Handle) (err error) {
r1, _, e1 := syscall.Syscall(procClearCommBreak.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func ClearCommError(handle Handle, lpErrors *uint32, lpStat *ComStat) (err error) {
r1, _, e1 := syscall.Syscall(procClearCommError.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(lpErrors)), uintptr(unsafe.Pointer(lpStat)))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func CloseHandle(handle Handle) (err error) { func CloseHandle(handle Handle) (err error) {
r1, _, e1 := syscall.Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0) r1, _, e1 := syscall.Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 { if r1 == 0 {
@@ -1844,6 +1873,14 @@ func DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBuff
return return
} }
func DisconnectNamedPipe(pipe Handle) (err error) {
r1, _, e1 := syscall.Syscall(procDisconnectNamedPipe.Addr(), 1, uintptr(pipe), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) { func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) {
var _p0 uint32 var _p0 uint32
if bInheritHandle { if bInheritHandle {
@@ -1856,6 +1893,14 @@ func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetP
return return
} }
func EscapeCommFunction(handle Handle, dwFunc uint32) (err error) {
r1, _, e1 := syscall.Syscall(procEscapeCommFunction.Addr(), 2, uintptr(handle), uintptr(dwFunc), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func ExitProcess(exitcode uint32) { func ExitProcess(exitcode uint32) {
syscall.Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0) syscall.Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0)
return return
@@ -2057,6 +2102,22 @@ func GetActiveProcessorCount(groupNumber uint16) (ret uint32) {
return return
} }
func GetCommModemStatus(handle Handle, lpModemStat *uint32) (err error) {
r1, _, e1 := syscall.Syscall(procGetCommModemStatus.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpModemStat)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func GetCommState(handle Handle, lpDCB *DCB) (err error) {
r1, _, e1 := syscall.Syscall(procGetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpDCB)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { func GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) {
r1, _, e1 := syscall.Syscall(procGetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) r1, _, e1 := syscall.Syscall(procGetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0)
if r1 == 0 { if r1 == 0 {
@@ -2809,6 +2870,14 @@ func PulseEvent(event Handle) (err error) {
return return
} }
func PurgeComm(handle Handle, dwFlags uint32) (err error) {
r1, _, e1 := syscall.Syscall(procPurgeComm.Addr(), 2, uintptr(handle), uintptr(dwFlags), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func QueryDosDevice(deviceName *uint16, targetPath *uint16, max uint32) (n uint32, err error) { func QueryDosDevice(deviceName *uint16, targetPath *uint16, max uint32) (n uint32, err error) {
r0, _, e1 := syscall.Syscall(procQueryDosDeviceW.Addr(), 3, uintptr(unsafe.Pointer(deviceName)), uintptr(unsafe.Pointer(targetPath)), uintptr(max)) r0, _, e1 := syscall.Syscall(procQueryDosDeviceW.Addr(), 3, uintptr(unsafe.Pointer(deviceName)), uintptr(unsafe.Pointer(targetPath)), uintptr(max))
n = uint32(r0) n = uint32(r0)
@@ -2923,6 +2992,30 @@ func ResumeThread(thread Handle) (ret uint32, err error) {
return return
} }
func SetCommBreak(handle Handle) (err error) {
r1, _, e1 := syscall.Syscall(procSetCommBreak.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SetCommMask(handle Handle, dwEvtMask uint32) (err error) {
r1, _, e1 := syscall.Syscall(procSetCommMask.Addr(), 2, uintptr(handle), uintptr(dwEvtMask), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SetCommState(handle Handle, lpDCB *DCB) (err error) {
r1, _, e1 := syscall.Syscall(procSetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpDCB)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { func SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) {
r1, _, e1 := syscall.Syscall(procSetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) r1, _, e1 := syscall.Syscall(procSetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0)
if r1 == 0 { if r1 == 0 {
@@ -3051,6 +3144,14 @@ func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetim
return return
} }
func SetFileValidData(handle Handle, validDataLength int64) (err error) {
r1, _, e1 := syscall.Syscall(procSetFileValidData.Addr(), 2, uintptr(handle), uintptr(validDataLength), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) { func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) {
r1, _, e1 := syscall.Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags)) r1, _, e1 := syscall.Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags))
if r1 == 0 { if r1 == 0 {
@@ -3136,6 +3237,14 @@ func SetVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16) (err erro
return return
} }
func SetupComm(handle Handle, dwInQueue uint32, dwOutQueue uint32) (err error) {
r1, _, e1 := syscall.Syscall(procSetupComm.Addr(), 3, uintptr(handle), uintptr(dwInQueue), uintptr(dwOutQueue))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SizeofResource(module Handle, resInfo Handle) (size uint32, err error) { func SizeofResource(module Handle, resInfo Handle) (size uint32, err error) {
r0, _, e1 := syscall.Syscall(procSizeofResource.Addr(), 2, uintptr(module), uintptr(resInfo), 0) r0, _, e1 := syscall.Syscall(procSizeofResource.Addr(), 2, uintptr(module), uintptr(resInfo), 0)
size = uint32(r0) size = uint32(r0)
@@ -3282,6 +3391,14 @@ func WTSGetActiveConsoleSessionId() (sessionID uint32) {
return return
} }
func WaitCommEvent(handle Handle, lpEvtMask *uint32, lpOverlapped *Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procWaitCommEvent.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(lpEvtMask)), uintptr(unsafe.Pointer(lpOverlapped)))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMilliseconds uint32) (event uint32, err error) { func waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMilliseconds uint32) (event uint32, err error) {
var _p0 uint32 var _p0 uint32
if waitAll { if waitAll {
+5 -2
View File
@@ -1,6 +1,9 @@
# github.com/danieljoos/wincred v1.2.1 # github.com/danieljoos/wincred v1.2.3
## explicit; go 1.18 ## explicit; go 1.18
github.com/danieljoos/wincred github.com/danieljoos/wincred
# golang.org/x/sys v0.15.0 # github.com/keybase/go-keychain v0.0.1
## explicit; go 1.21
github.com/keybase/go-keychain
# golang.org/x/sys v0.20.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/sys/windows golang.org/x/sys/windows