@@ -4,6 +4,8 @@ package wincred
44
55import (
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+
167196func tryDecodeUTF16LE (blob []byte ) (string , bool ) {
168197 if len (blob )% 2 != 0 {
169198 return "" , false
0 commit comments