1
0
mirror of https://github.com/docker/docker-credential-helpers.git synced 2026-06-28 07:11:36 +05:30

Compare commits

..

36 Commits

Author SHA1 Message Date
Nassim Eddequiouaq 5241b46610 Merge pull request #110 from euank/lazy-init
pass: only init on run, and do so lazily
2018-06-27 14:33:29 +02:00
Vincent Demeester 3cba3913ea pass: add IsInitialized helper
This will be useful for the cli where they check initialization:
https://github.com/docker/cli/blob/be8dab26a3ab589b96788fdb95f3d07378e57b9b/cli/config/credentials/default_store_linux.go#L8-L10

Signed-off-by: Euan Kemp <euank@euank.com>
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2018-06-27 14:28:47 +02:00
Vincent Demeester 8502b53592 Merge pull request #108 from euank/pass-trim‮‮‮‮‮‮‮‮trim-pass
pass: trim pass show output
2018-06-27 14:24:08 +02:00
Euan Kemp 5da09fd251 pass: only init on run, and do so lazily
This also fixes the following issues:

1. Safe for concurrent initialization still (it was before in 'init',
   but the alternative to this PR is not)
2. Uses the same password directory during init as it does during
   runtime (the change to getPassDir in initialization logic.
3. Prints significantly better errors if initialization fails
4. Has slightly cleaner abstractions by hiding the initialization check
   in 'runPass'

The 4th item there does mean there are a few cases where more work is
done before erroring, but that amount of work is trivial and my manual
audit didn't reveal anything that seemed worrying.

Fixes #96, alternative to #106

Signed-off-by: Euan Kemp <euank@euank.com>
2018-06-27 14:23:22 +02:00
Euan Kemp dd27c246bd pass: trim pass show output
As of 8446a40, pass show will include a newline when showing a password.
This causes the pass helper here to reliably fail to initialize since a
password doesn't round-trip.

Before making this change, the pass test would fail if the installed
password-store version was v1.7.1+, and after this change it passes
again.

Fixes #107

Signed-off-by: Euan Kemp <euank@euank.com>
2018-06-27 14:21:52 +02:00
Vincent Demeester 26deb2937d Merge pull request #109 from euank/better-exec
pass: simplify some code
2018-06-27 14:19:27 +02:00
Euan Kemp a13ff50017 pass: simplify some code
The exec.Command code and os.Getenv implementation were both needlessly
verbose. This replaces them with simpler variations.

Signed-off-by: Euan Kemp <euank@euank.com>
2018-06-27 14:15:36 +02:00
Vincent Demeester 1c295f7de8 Merge pull request #115 from n4ss/fix-appveyor
Fix Windows CI
2018-06-27 14:14:13 +02:00
Nassim 'Nass' Eddequiouaq 093af814ee fix go vet complaining on composite literales
Signed-off-by: Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
2018-06-27 14:02:28 +02:00
Vincent Demeester d499cf5cb9 Merge pull request #114 from n4ss/fix-travisci-osxkeychain
fix osxkeychain ci
2018-06-27 13:52:26 +02:00
Nassim 'Nass' Eddequiouaq b049338a6b Fix appveyor windows ci
Signed-off-by: Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
2018-06-27 13:45:32 +02:00
Nassim 'Nass' Eddequiouaq 91fc39d57a install yarn on osx for travisci
Signed-off-by: Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
2018-06-27 13:22:53 +02:00
Nassim 'Nass' Eddequiouaq 317219f3a6 Fix yarn complaint in travisci
Signed-off-by: Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
2018-06-27 12:13:18 +02:00
Nassim 'Nass' Eddequiouaq 21f4937ebc fix osxkeychain ci
Signed-off-by: Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
2018-06-27 11:58:22 +02:00
Vincent Demeester 19b711cc92 Merge pull request #100 from vdemeester/update-maintainers
Update MAINTAINERS file with current maintainers
2018-02-14 08:13:21 +01:00
Vincent Demeester 1f635a73ad Update MAINTAINERS file with current maintainers
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2018-02-12 14:39:43 +01:00
Jean-Laurent de Morlhon d68f9aeca3 Merge pull request #88 from n4ss/add-pass-config-notice
Add instructions for pass helper configuration
2017-08-30 14:17:07 +02:00
Vincent Demeester 05a9d4c50d Merge pull request #89 from tych0/better-initialization-check
pass: better initialization check
2017-08-29 21:46:31 +02:00
Tycho Andersen c2eec534ee pass: better initialization check
See comment for details, but basically, let's actually use pass to check
that it works.

Signed-off-by: Tycho Andersen <tycho@docker.com>
2017-08-29 08:25:08 -07:00
Nassim 'Nass' Eddequiouaq 5be80ca212 Add instructions for pass helper configuration
Signed-off-by: Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
2017-08-28 18:11:27 +02:00
Vincent Demeester f00de1b72f Merge pull request #87 from n4ss/bump-0.6.0
Bump 0.6.0
2017-08-28 14:18:12 +02:00
Nassim 'Nass' Eddequiouaq 72f0375e37 Bump 0.6.0
Signed-off-by: Nassim 'Nass' Eddequiouaq <eddequiouaq.nassim@gmail.com>
2017-08-25 19:37:31 +02:00
Nassim Eddequiouaq 3cce61446f Merge pull request #85 from promiseofcake/ljk-fix-makefile
Fix Makefile issues
2017-08-25 18:50:05 +02:00
Lucas Kacher ec0d036273 Fix Makefile issues
* mkdir fails when `bin` exists
* obtaining golint fails if previously installed (w/out the -u flag)

Signed-off-by: Lucas Kacher <lucas@vsco.co>
2017-08-23 11:08:54 -04:00
Vincent Demeester d3d9934897 Merge pull request #84 from tych0/fix-helpers-protocol
return "" instead of an error when pass isn't present
2017-08-22 20:10:46 +02:00
Tycho Andersen f212ea17df fix test
Signed-off-by: Tycho Andersen <tycho@docker.com>
2017-08-17 10:36:48 -06:00
Tycho Andersen 09e536a128 return "" instead of an error when pass isn't present
It turns out the cred helpers protocol is to return "" and not an error
when a credential isn't present, so let's do that.

Signed-off-by: Tycho Andersen <tycho@docker.com>
2017-08-17 09:19:19 -06:00
Vincent Demeester 3c90bd29a4 Merge pull request #83 from tych0/expose-pass-initialized
pass backend: expose pass initialized flag
2017-08-16 11:06:21 +02:00
Tycho Andersen b8fb9690c8 pass backend: expose pass initialized flag
This way clients don't have to run their own checks, they can just use the
library's detection.

Signed-off-by: Tycho Andersen <tycho@docker.com>
2017-08-14 08:56:59 -06:00
Vincent Demeester 7efaffb4c4 Merge pull request #81 from tych0/pass-backend-and-package
Add `pass` backend and debian packaging for both -secretservice and -pass backends
2017-08-14 16:00:25 +02:00
Nassim Eddequiouaq 6338c06ba4 Merge pull request #69 from shhsu/command_env
A new entry point for calling the cred helpers that allow passing environment variables
2017-08-14 11:15:13 +02:00
Tycho Andersen 86c94d3e30 add a deb package for pass/secret service backends
Note that this single source package produces two binary packages: one for
-pass, and one for -secretservice, so that users can install whichever
password backend (and thus deps) that they want.

Signed-off-by: Tycho Andersen <tycho@docker.com>
2017-08-11 08:15:29 -06:00
Tycho Andersen 1ab1037707 add a pass credential helper backend
Signed-off-by: Tycho Andersen <tycho@docker.com>
2017-08-11 08:15:29 -06:00
Peter Hsu c69c0725bb A new entry point for calling the cred helpers that allow passing environment variables
Signed-off-by: Peter Hsu <shhsu@microsoft.com>
2017-06-30 10:45:22 -07:00
Nassim Eddequiouaq a8de4f6e8a Merge pull request #77 from jeanlaurent/win-release
Adding winrelease target
2017-06-15 12:39:03 +02:00
Jean-Laurent de Morlhon 4fbc86d7d0 Adding winrelease target
Signed-off-by: Jean-Laurent de Morlhon <jeanlaurent@morlhon.net>
2017-06-15 12:03:00 +02:00
20 changed files with 474 additions and 46 deletions
+9 -2
View File
@@ -3,19 +3,26 @@
sudo: required
language: go
dist: trusty
osx_image: xcode9
os:
- linux
- osx
notifications:
email: false
go:
- 1.8
install: make deps
- 1.8.1
before_install:
# work-around for issue https://github.com/travis-ci/travis-ci/issues/6307
# might not be necessary in the future
- command curl -sSL https://rvm.io/mpapis.asc | gpg --import -
- rvm get stable
addons:
apt:
packages:
- libsecret-1-dev
- pass
before_script:
- make deps
- "export DISPLAY=:99.0"
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sh ci/before_script_linux.sh; fi
- make validate
+11
View File
@@ -4,6 +4,17 @@ This changelog tracks the releases of docker-credential-helpers.
This project includes different binaries per platform.
The platform released is identified after the tag name.
## v0.6.0 (Go client, Linux)
- New credential helper on Linux using `pass`
- New entry point for passing environment variables when calling a credential helper
- Add a Makefile rule generating a Windows release binary
### Note
`pass` needs to be configured for `docker-credential-pass` to work properly.
It must be initialized with a `gpg2` key ID. Make sure your GPG key exists is in `gpg2` keyring as `pass` uses `gpg2` instead of the regular `gpg`.
## v0.5.2 (Mac OS X, Windows, Linux)
- Add a `version` command to output the version
-30
View File
@@ -11,18 +11,13 @@
[Org]
[Org."Core maintainers"]
people = [
"aaronlehmann",
"calavera",
"coolljt0725",
"cpuguy83",
"crosbymichael",
"dnephin",
"dongluochen",
"duglin",
"estesp",
"icecrime",
"jhowardmsft",
"lk4d4",
"mavenugo",
"mhbauer",
"n4ss",
@@ -45,16 +40,6 @@
# ADD YOURSELF HERE IN ALPHABETICAL ORDER
[people.aaronlehmann]
Name = "Aaron Lehmann"
Email = "aaron.lehmann@docker.com"
GitHub = "aaronlehmann"
[people.calavera]
Name = "David Calavera"
Email = "david.calavera@gmail.com"
GitHub = "calavera"
[people.coolljt0725]
Name = "Lei Jitang"
Email = "leijitang@huawei.com"
@@ -75,11 +60,6 @@
Email = "dnephin@gmail.com"
GitHub = "dnephin"
[people.dongluochen]
Name = "Dongluo Chen"
Email = "dongluo.chen@docker.com"
GitHub = "dongluochen"
[people.duglin]
Name = "Doug Davis"
Email = "dug@us.ibm.com"
@@ -90,21 +70,11 @@
Email = "estesp@linux.vnet.ibm.com"
GitHub = "estesp"
[people.icecrime]
Name = "Arnaud Porterie"
Email = "arnaud@docker.com"
GitHub = "icecrime"
[people.jhowardmsft]
Name = "John Howard"
Email = "jhoward@microsoft.com"
GitHub = "jhowardmsft"
[people.lk4d4]
Name = "Alexander Morozov"
Email = "lk4d4@docker.com"
GitHub = "lk4d4"
[people.mavenugo]
Name = "Madhu Venugopal"
Email = "madhu@docker.com"
+26 -5
View File
@@ -1,4 +1,4 @@
.PHONY: all deps osxkeychain secretservice test validate wincred
.PHONY: all deps osxkeychain secretservice test validate wincred pass deb
TRAVIS_OS_NAME ?= linux
VERSION := $(shell grep 'const Version' credentials/version.go | awk -F'"' '{ print $$2 }')
@@ -6,14 +6,14 @@ VERSION := $(shell grep 'const Version' credentials/version.go | awk -F'"' '{ pr
all: test
deps:
go get github.com/golang/lint/golint
go get -u github.com/golang/lint/golint
clean:
rm -rf bin
rm -rf release
osxkeychain:
mkdir bin
mkdir -p bin
go build -ldflags -s -o bin/docker-credential-osxkeychain osxkeychain/cmd/main_darwin.go
osxcodesign: osxkeychain
@@ -27,13 +27,22 @@ osxrelease: clean vet_osx lint fmt test osxcodesign
cd bin && tar cvfz ../release/docker-credential-osxkeychain-v$(VERSION)-amd64.tar.gz docker-credential-osxkeychain
secretservice:
mkdir bin
mkdir -p bin
go build -o bin/docker-credential-secretservice secretservice/cmd/main_linux.go
pass:
mkdir -p bin
go build -o bin/docker-credential-pass pass/cmd/main_linux.go
wincred:
mkdir bin
mkdir -p bin
go build -o bin/docker-credential-wincred.exe wincred/cmd/main_windows.go
winrelease: clean vet_win lint fmt test wincred
mkdir -p release
@echo "\nPackaging version ${VERSION}\n"
cd bin && zip ../release/docker-credential-wincred-v$(VERSION)-amd64.zip docker-credential-wincred.exe
test:
# tests all packages except vendor
go test -v `go list ./... | grep -v /vendor/`
@@ -59,3 +68,15 @@ fmt:
gofmt -s -l `ls **/*.go | grep -v vendor`
validate: vet lint fmt
BUILDIMG:=docker-credential-secretservice-$(VERSION)
deb:
mkdir -p release
docker build -f deb/Dockerfile \
--build-arg VERSION=$(VERSION) \
--build-arg DISTRO=xenial \
--tag $(BUILDIMG) \
.
docker run --rm --net=none $(BUILDIMG) tar cf - /release | tar xf -
docker rmi $(BUILDIMG)
+6
View File
@@ -55,6 +55,12 @@ You can see examples of each function in the [client](https://godoc.org/github.c
1. osxkeychain: Provides a helper to use the OS X keychain as credentials store.
2. secretservice: Provides a helper to use the D-Bus secret service as credentials store.
3. wincred: Provides a helper to use Windows credentials manager as store.
4. pass: Provides a helper to use `pass` as credentials store.
#### Note
`pass` needs to be configured for `docker-credential-pass` to work properly.
It must be initialized with a `gpg2` key ID. Make sure your GPG key exists is in `gpg2` keyring as `pass` uses `gpg2` instead of the regular `gpg`.
## Development
+2 -2
View File
@@ -2,13 +2,13 @@ image: Visual Studio 2015
environment:
GOPATH: c:\gopath
stack: go 1.8.7
clone_folder: c:\gopath\src\github.com\docker\docker-credential-helpers
clone_depth: 10
before_build:
- set PATH=%PATH%;C:\MinGW\bin;
- set PATH=%PATH%;C:\go18\bin;
- set GOROOT=C:\go18
build_script:
- mingw32-make vet_win wincred
+18
View File
@@ -2,3 +2,21 @@ set -ex
sh -e /etc/init.d/xvfb start
sleep 3 # give xvfb some time to start
# init key for pass
gpg --batch --gen-key <<-EOF
%echo Generating a standard key
Key-Type: DSA
Key-Length: 1024
Subkey-Type: ELG-E
Subkey-Length: 1024
Name-Real: Meshuggah Rocks
Name-Email: meshuggah@example.com
Expire-Date: 0
# Do a commit here, so that we can later print "done" :-)
%commit
%echo done
EOF
key=$(gpg --no-auto-check-trustdb --list-secret-keys | grep ^sec | cut -d/ -f2 | cut -d" " -f1)
pass init $key
+17 -5
View File
@@ -1,6 +1,7 @@
package client
import (
"fmt"
"io"
"os"
"os/exec"
@@ -17,15 +18,26 @@ type ProgramFunc func(args ...string) Program
// NewShellProgramFunc creates programs that are executed in a Shell.
func NewShellProgramFunc(name 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 &Shell{cmd: newCmdRedirectErr(name, args)}
return &Shell{cmd: createProgramCmdRedirectErr(name, args, env)}
}
}
func newCmdRedirectErr(name string, args []string) *exec.Cmd {
newCmd := exec.Command(name, args...)
newCmd.Stderr = os.Stderr
return newCmd
func createProgramCmdRedirectErr(commandName string, args []string, env *map[string]string) *exec.Cmd {
programCmd := exec.Command(commandName, args...)
programCmd.Env = os.Environ()
if env != nil {
for k, v := range *env {
programCmd.Env = append(programCmd.Env, fmt.Sprintf("%s=%s", k, v))
}
}
programCmd.Stderr = os.Stderr
return programCmd
}
// Shell invokes shell commands to talk with a remote credentials helper.
+1 -1
View File
@@ -1,4 +1,4 @@
package credentials
// Version holds a string describing the current version
const Version = "0.5.2"
const Version = "0.6.0"
+19
View File
@@ -0,0 +1,19 @@
FROM ubuntu:xenial
ARG VERSION
ARG DISTRO
RUN apt-get update && apt-get install -yy debhelper dh-make golang-go libsecret-1-dev
RUN mkdir -p /build
WORKDIR /build
ENV GOPATH /build
COPY Makefile .
COPY credentials credentials
COPY secretservice secretservice
COPY pass pass
COPY deb/debian ./debian
COPY deb/build-deb .
RUN /build/build-deb ${VERSION} ${DISTRO}
Executable
+26
View File
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -x
set -e
version=$1
distro=$2
maintainer=$(awk -F ': ' '$1 == "Maintainer" { print $2; exit }' debian/control)
cat > "debian/changelog" <<-EOF
docker-credential-helpers ($version) $DISTRO; urgency=low
* New upstream version
-- $maintainer $(date --rfc-2822)
EOF
mkdir -p src/github.com/docker/docker-credential-helpers
ln -s /build/credentials /build/src/github.com/docker/docker-credential-helpers/credentials
ln -s /build/secretservice /build/src/github.com/docker/docker-credential-helpers/secretservice
ln -s /build/pass /build/src/github.com/docker/docker-credential-helpers/pass
dpkg-buildpackage -us -uc
mkdir /release
mv /docker-credential-* /release
+1
View File
@@ -0,0 +1 @@
9
+25
View File
@@ -0,0 +1,25 @@
Source: docker-credential-helpers
Section: admin
Priority: optional
Maintainer: Docker <support@docker.com>
Homepage: https://dockerproject.org
Standards-Version: 3.9.6
Vcs-Browser: https://github.com/docker/docker-credential-helpers
Vcs-Git: git://github.com/docker/docker-credential-helpers.git
Build-Depends: debhelper
, dh-make
, libsecret-1-dev
Package: docker-credential-secretservice
Architecture: any
Depends: libsecret-1-0
, ${misc:Depends}
Description: docker-credential-secretservice is a credential helper backend
which uses libsecret to keep Docker credentials safe.
Package: docker-credential-pass
Architecture: any
Depends: pass
, ${misc:Depends}
Description: docker-credential-secretservice is a credential helper backend
which uses the pass utility to keep Docker credentials safe.
@@ -0,0 +1 @@
debian/tmp/usr/bin/docker-credential-pass
@@ -0,0 +1 @@
debian/tmp/usr/bin/docker-credential-secretservice
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/make -f
DESTDIR := $(CURDIR)/debian/tmp
override_dh_auto_build:
make secretservice pass
override_dh_auto_install:
install -D bin/docker-credential-secretservice $(DESTDIR)/usr/bin/docker-credential-secretservice
install -D bin/docker-credential-pass $(DESTDIR)/usr/bin/docker-credential-pass
%:
dh $@
override_dh_auto_test:
# no tests
+10
View File
@@ -0,0 +1,10 @@
package main
import (
"github.com/docker/docker-credential-helpers/credentials"
"github.com/docker/docker-credential-helpers/pass"
)
func main() {
credentials.Serve(pass.Pass{})
}
+207
View File
@@ -0,0 +1,207 @@
// A `pass` based credential helper. Passwords are stored as arguments to pass
// of the form: "$PASS_FOLDER/base64-url(serverURL)/username". We base64-url
// encode the serverURL, because under the hood pass uses files and folders, so
// /s will get translated into additional folders.
package pass
import (
"bytes"
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"strings"
"sync"
"github.com/docker/docker-credential-helpers/credentials"
)
const PASS_FOLDER = "docker-credential-helpers"
// Pass handles secrets using Linux secret-service as a store.
type Pass struct{}
// Ideally these would be stored as members of Pass, but since all of Pass's
// methods have value receivers, not pointer receivers, and changing that is
// backwards incompatible, we assume that all Pass instances share the same configuration
// initializationMutex is held while initializing so that only one 'pass'
// round-tripping is done to check pass is functioning.
var initializationMutex sync.Mutex
var passInitialized bool
// CheckInitialized checks whether the password helper can be used. It
// internally caches and so may be safely called multiple times with no impact
// on performance, though the first call may take longer.
func (p Pass) CheckInitialized() bool {
return p.checkInitialized() == nil
}
func (p Pass) checkInitialized() error {
initializationMutex.Lock()
defer initializationMutex.Unlock()
if passInitialized {
return nil
}
// In principle, we could just run `pass init`. However, pass has a bug
// where if gpg fails, it doesn't always exit 1. Additionally, pass
// uses gpg2, but gpg is the default, which may be confusing. So let's
// just explictily check that pass actually can store and retreive a
// password.
password := "pass is initialized"
name := path.Join(getPassDir(), "docker-pass-initialized-check")
_, err := p.runPassHelper(password, "insert", "-f", "-m", name)
if err != nil {
return fmt.Errorf("error initializing pass: %v", err)
}
stored, err := p.runPassHelper("", "show", name)
if err != nil {
return fmt.Errorf("error fetching password during initialization: %v", err)
}
if stored != password {
return fmt.Errorf("error round-tripping password during initialization: %q != %q", password, stored)
}
passInitialized = true
return nil
}
func (p Pass) runPass(stdinContent string, args ...string) (string, error) {
if err := p.checkInitialized(); err != nil {
return "", err
}
return p.runPassHelper(stdinContent, args...)
}
func (p Pass) runPassHelper(stdinContent string, args ...string) (string, error) {
var stdout, stderr bytes.Buffer
cmd := exec.Command("pass", args...)
cmd.Stdin = strings.NewReader(stdinContent)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
return "", fmt.Errorf("%s: %s", err, stderr.String())
}
// trim newlines; pass v1.7.1+ includes a newline at the end of `show` output
return strings.TrimRight(stdout.String(), "\n\r"), nil
}
// Add adds new credentials to the keychain.
func (h Pass) Add(creds *credentials.Credentials) error {
if creds == nil {
return errors.New("missing credentials")
}
encoded := base64.URLEncoding.EncodeToString([]byte(creds.ServerURL))
_, err := h.runPass(creds.Secret, "insert", "-f", "-m", path.Join(PASS_FOLDER, encoded, creds.Username))
return err
}
// Delete removes credentials from the store.
func (h Pass) Delete(serverURL string) error {
if serverURL == "" {
return errors.New("missing server url")
}
encoded := base64.URLEncoding.EncodeToString([]byte(serverURL))
_, err := h.runPass("", "rm", "-rf", path.Join(PASS_FOLDER, encoded))
return err
}
func getPassDir() string {
passDir := "$HOME/.password-store"
if envDir := os.Getenv("PASSWORD_STORE_DIR"); envDir != "" {
passDir = envDir
}
return os.ExpandEnv(passDir)
}
// listPassDir lists all the contents of a directory in the password store.
// Pass uses fancy unicode to emit stuff to stdout, so rather than try
// and parse this, let's just look at the directory structure instead.
func listPassDir(args ...string) ([]os.FileInfo, error) {
passDir := getPassDir()
p := path.Join(append([]string{passDir, PASS_FOLDER}, args...)...)
contents, err := ioutil.ReadDir(p)
if err != nil {
if os.IsNotExist(err) {
return []os.FileInfo{}, nil
}
return nil, err
}
return contents, nil
}
// Get returns the username and secret to use for a given registry server URL.
func (h Pass) Get(serverURL string) (string, string, error) {
if serverURL == "" {
return "", "", errors.New("missing server url")
}
encoded := base64.URLEncoding.EncodeToString([]byte(serverURL))
if _, err := os.Stat(path.Join(getPassDir(), PASS_FOLDER, encoded)); err != nil {
if os.IsNotExist(err) {
return "", "", nil
}
return "", "", err
}
usernames, err := listPassDir(encoded)
if err != nil {
return "", "", err
}
if len(usernames) < 1 {
return "", "", fmt.Errorf("no usernames for %s", serverURL)
}
actual := strings.TrimSuffix(usernames[0].Name(), ".gpg")
secret, err := h.runPass("", "show", path.Join(PASS_FOLDER, encoded, actual))
return actual, secret, err
}
// List returns the stored URLs and corresponding usernames for a given credentials label
func (h Pass) List() (map[string]string, error) {
servers, err := listPassDir()
if err != nil {
return nil, err
}
resp := map[string]string{}
for _, server := range servers {
if !server.IsDir() {
continue
}
serverURL, err := base64.URLEncoding.DecodeString(server.Name())
if err != nil {
return nil, err
}
usernames, err := listPassDir(server.Name())
if err != nil {
return nil, err
}
if len(usernames) < 1 {
return nil, fmt.Errorf("no usernames for %s", serverURL)
}
resp[string(serverURL)] = strings.TrimSuffix(usernames[0].Name(), ".gpg")
}
return resp, nil
}
+75
View File
@@ -0,0 +1,75 @@
package pass
import (
"strings"
"testing"
"github.com/docker/docker-credential-helpers/credentials"
)
func TestPassHelper(t *testing.T) {
helper := Pass{}
creds := &credentials.Credentials{
ServerURL: "https://foobar.docker.io:2376/v1",
Username: "nothing",
Secret: "isthebestmeshuggahalbum",
}
helper.Add(creds)
creds.ServerURL = "https://foobar.docker.io:9999/v2"
helper.Add(creds)
credsList, err := helper.List()
if err != nil {
t.Fatal(err)
}
for server, username := range credsList {
if !(strings.Contains(server, "2376") ||
strings.Contains(server, "9999")) {
t.Fatalf("invalid url: %s", creds.ServerURL)
}
if username != "nothing" {
t.Fatalf("invalid username: %v", username)
}
u, s, err := helper.Get(server)
if err != nil {
t.Fatal(err)
}
if u != username {
t.Fatalf("invalid username %s", u)
}
if s != "isthebestmeshuggahalbum" {
t.Fatalf("invalid secret: %s", s)
}
err = helper.Delete(server)
if err != nil {
t.Fatal(err)
}
username, _, err = helper.Get(server)
if err != nil {
t.Fatal(err)
}
if username != "" {
t.Fatalf("%s shouldn't exist any more", username)
}
}
credsList, err = helper.List()
if err != nil {
t.Fatal(err)
}
if len(credsList) != 0 {
t.Fatal("didn't delete all creds?")
}
}
+2 -1
View File
@@ -13,11 +13,12 @@ type Wincred struct{}
// Add adds new credentials to the windows credentials manager.
func (h Wincred) Add(creds *credentials.Credentials) error {
credsLabels := []byte(credentials.CredsLabel)
g := winc.NewGenericCredential(creds.ServerURL)
g.UserName = creds.Username
g.CredentialBlob = []byte(creds.Secret)
g.Persist = winc.PersistLocalMachine
g.Attributes = []winc.CredentialAttribute{{"label", []byte(credentials.CredsLabel)}}
g.Attributes = []winc.CredentialAttribute{{Keyword: "label", Value: credsLabels}}
return g.Write()
}