diff --git a/pass/pass.go b/pass/pass.go index 80af37dd..e734cce5 100644 --- a/pass/pass.go +++ b/pass/pass.go @@ -87,9 +87,9 @@ func (p Pass) Add(creds *credentials.Credentials) error { return errors.New("missing credentials") } - encoded := base64.URLEncoding.EncodeToString([]byte(creds.ServerURL)) - - _, err := p.runPass(creds.Secret, "insert", "-f", "-m", path.Join(PASS_FOLDER, encoded, creds.Username)) + encodedServerURL := base64.URLEncoding.EncodeToString([]byte(creds.ServerURL)) + encodedUsername := base64.URLEncoding.EncodeToString([]byte(creds.Username)) + _, err := p.runPass(creds.Secret, "insert", "-f", "-m", path.Join(PASS_FOLDER, encodedServerURL, encodedUsername)) return err } @@ -99,8 +99,8 @@ func (p Pass) Delete(serverURL string) error { return errors.New("missing server url") } - encoded := base64.URLEncoding.EncodeToString([]byte(serverURL)) - _, err := p.runPass("", "rm", "-rf", path.Join(PASS_FOLDER, encoded)) + encodedServerURL := base64.URLEncoding.EncodeToString([]byte(serverURL)) + _, err := p.runPass("", "rm", "-rf", path.Join(PASS_FOLDER, encodedServerURL)) return err } @@ -142,9 +142,8 @@ func (p Pass) Get(serverURL string) (string, string, error) { return "", "", errors.New("missing server url") } - encoded := base64.URLEncoding.EncodeToString([]byte(serverURL)) - - if _, err := os.Stat(path.Join(getPassDir(), PASS_FOLDER, encoded)); err != nil { + encodedServerURL := base64.URLEncoding.EncodeToString([]byte(serverURL)) + if _, err := os.Stat(path.Join(getPassDir(), PASS_FOLDER, encodedServerURL)); err != nil { if os.IsNotExist(err) { return "", "", credentials.NewErrCredentialsNotFound() } @@ -152,7 +151,7 @@ func (p Pass) Get(serverURL string) (string, string, error) { return "", "", err } - usernames, err := listPassDir(encoded) + usernames, err := listPassDir(encodedServerURL) if err != nil { return "", "", err } @@ -162,8 +161,12 @@ func (p Pass) Get(serverURL string) (string, string, error) { } actual := strings.TrimSuffix(usernames[0].Name(), ".gpg") - secret, err := p.runPass("", "show", path.Join(PASS_FOLDER, encoded, actual)) - return actual, secret, err + username := actual + if decodedUsername, err := base64.URLEncoding.DecodeString(actual); err == nil { + username = string(decodedUsername) + } + secret, err := p.runPass("", "show", path.Join(PASS_FOLDER, encodedServerURL, actual)) + return username, secret, err } // List returns the stored URLs and corresponding usernames for a given credentials label @@ -194,7 +197,11 @@ func (p Pass) List() (map[string]string, error) { return nil, fmt.Errorf("no usernames for %s", serverURL) } - resp[string(serverURL)] = strings.TrimSuffix(usernames[0].Name(), ".gpg") + username := strings.TrimSuffix(usernames[0].Name(), ".gpg") + resp[string(serverURL)] = username + if decodedUsername, err := base64.URLEncoding.DecodeString(username); err == nil { + resp[string(serverURL)] = string(decodedUsername) + } } return resp, nil diff --git a/pass/pass_test.go b/pass/pass_test.go index 8ab10f59..ecbd7935 100644 --- a/pass/pass_test.go +++ b/pass/pass_test.go @@ -3,13 +3,76 @@ package pass import ( + "encoding/base64" + "path" "strings" "testing" "github.com/docker/docker-credential-helpers/credentials" ) +func TestPassHelperCheckInit(t *testing.T) { + helper := Pass{} + if v := helper.CheckInitialized(); !v { + t.Errorf("expected true, actual: %v", v) + } +} + func TestPassHelper(t *testing.T) { + tests := []struct { + name string + creds *credentials.Credentials + }{ + { + name: "create nothing", + creds: &credentials.Credentials{ + ServerURL: "https://foobar.docker.io:2376/v1", + Username: "nothing", + Secret: "isthebestmeshuggahalbum", + }, + }, + { + name: "create foo/bar", + creds: &credentials.Credentials{ + ServerURL: "https://foobar.docker.io:2376/v1", + Username: "foo/bar", + Secret: "foobarbaz", + }, + }, + } + + helper := Pass{} + if err := helper.checkInitialized(); err != nil { + t.Error(err) + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + if err := helper.Add(tc.creds); err != nil { + t.Error(err) + } + u, s, err := helper.Get(tc.creds.ServerURL) + if err != nil { + t.Error(err) + } + if u != tc.creds.Username { + t.Errorf("invalid username %s", u) + } + if s != tc.creds.Secret { + t.Errorf("invalid secret: %s", s) + } + if err := helper.Delete(tc.creds.ServerURL); err != nil { + t.Error(err) + } + if _, _, err := helper.Get(tc.creds.ServerURL); !credentials.IsErrCredentialsNotFound(err) { + t.Errorf("expected credentials not found, actual: %v", err) + } + }) + } +} + +func TestPassHelperBackwardCompat(t *testing.T) { creds := &credentials.Credentials{ ServerURL: "https://foobar.docker.io:2376/v1", Username: "nothing", @@ -21,7 +84,9 @@ func TestPassHelper(t *testing.T) { t.Error(err) } - if err := helper.Add(creds); err != nil { + // add a credential with the old format + encodedServerURL := base64.URLEncoding.EncodeToString([]byte(creds.ServerURL)) + if _, err := helper.runPass(creds.Secret, "insert", "-f", "-m", path.Join(PASS_FOLDER, encodedServerURL, creds.Username)); err != nil { t.Error(err) } @@ -44,13 +109,6 @@ func TestPassHelper(t *testing.T) { } } -func TestPassHelperCheckInit(t *testing.T) { - helper := Pass{} - if v := helper.CheckInitialized(); !v { - t.Errorf("expected true, actual: %v", v) - } -} - func TestPassHelperList(t *testing.T) { creds := []*credentials.Credentials{ {