Skip to content

Commit 6bed3ec

Browse files
committed
wincred: store encoding used as attribute
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent c16684b commit 6bed3ec

1 file changed

Lines changed: 39 additions & 10 deletions

File tree

wincred/wincred.go

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ package wincred
44

55
import (
66
"bytes"
7+
"errors"
8+
"fmt"
79
"net/url"
810

911
winc "github.com/danieljoos/wincred"
@@ -24,7 +26,10 @@ func (h Wincred) Add(creds *credentials.Credentials) error {
2426
g := winc.NewGenericCredential(creds.ServerURL)
2527
g.UserName = creds.Username
2628
g.Persist = winc.PersistLocalMachine
27-
g.Attributes = []winc.CredentialAttribute{{Keyword: "label", Value: credsLabel}}
29+
g.Attributes = []winc.CredentialAttribute{
30+
{Keyword: "label", Value: credsLabel},
31+
{Keyword: "encoding", Value: []byte("utf16le")},
32+
}
2833

2934
blob, err := encodeUTF16LE(creds.Secret)
3035
if err != nil {
@@ -64,16 +69,31 @@ func (h Wincred) Get(serverURL string) (string, string, error) {
6469

6570
for _, attr := range g.Attributes {
6671
if attr.Keyword == "label" && bytes.Equal(attr.Value, credsLabel) {
67-
// Older versions of the wincred credential-helper stored the password blob
68-
// as raw string bytes. Newer versions store it as UTF-16LE. Try decoding from
69-
// UTF-16LE, otherwise assume creds were stored as raw bytes.
70-
//
71-
// See https://github.com/docker/docker-credential-helpers/pull/335
72-
creds := string(g.CredentialBlob)
73-
if p, ok := tryDecodeUTF16LE(g.CredentialBlob); ok {
74-
creds = p
72+
switch enc := credentialEncoding(g.Attributes); enc {
73+
case "utf16le":
74+
// Encoding was stored; only accept UTF-16LE or error otherwise.
75+
creds, err := decodeUTF16LE(g.CredentialBlob)
76+
if err != nil {
77+
return "", "", fmt.Errorf("decoding credentials: %w", err)
78+
}
79+
return g.UserName, string(creds), nil
80+
case "":
81+
// Older versions of the wincred credential-helper stored the password blob
82+
// as raw string bytes. Newer versions store it as UTF-16LE. Try decoding from
83+
// UTF-16LE, otherwise assume creds were stored as raw bytes.
84+
//
85+
// This could also be the case if an external tool stored the credentials and
86+
// did not set the "encoding" attribute.
87+
//
88+
// See https://github.com/docker/docker-credential-helpers/pull/335
89+
creds := string(g.CredentialBlob)
90+
if c, ok := tryDecodeUTF16LE(g.CredentialBlob); ok {
91+
creds = c
92+
}
93+
return g.UserName, creds, nil
94+
default:
95+
return "", "", errors.New("unsupported credential encoding: " + enc)
7596
}
76-
return g.UserName, creds, nil
7797
}
7898
}
7999
return "", "", credentials.NewErrCredentialsNotFound()
@@ -164,6 +184,15 @@ func (h Wincred) List() (map[string]string, error) {
164184
return resp, nil
165185
}
166186

187+
func credentialEncoding(attrs []winc.CredentialAttribute) string {
188+
for _, attr := range attrs {
189+
if attr.Keyword == "encoding" {
190+
return string(attr.Value)
191+
}
192+
}
193+
return ""
194+
}
195+
167196
func tryDecodeUTF16LE(blob []byte) (string, bool) {
168197
if len(blob)%2 != 0 {
169198
return "", false

0 commit comments

Comments
 (0)