11package credentials
22
33import (
4+ "bytes"
5+ "encoding/json"
46 "errors"
7+ "fmt"
58 "net/url"
69 "regexp"
710 "strings"
@@ -13,8 +16,9 @@ import (
1316)
1417
1518type toolCredentialStore struct {
16- file credentials.Store
17- program client.ProgramFunc
19+ file credentials.Store
20+ program client.ProgramFunc
21+ contexts []string
1822}
1923
2024func (h * toolCredentialStore ) Erase (serverAddress string ) error {
@@ -43,7 +47,16 @@ func (h *toolCredentialStore) Get(serverAddress string) (types.AuthConfig, error
4347}
4448
4549func (h * toolCredentialStore ) GetAll () (map [string ]types.AuthConfig , error ) {
46- serverAddresses , err := client .List (h .program )
50+ var (
51+ serverAddresses map [string ]string
52+ err error
53+ )
54+ if len (h .contexts ) == 0 {
55+ serverAddresses , err = client .List (h .program )
56+ } else {
57+ serverAddresses , err = listWithContexts (h .program , h .contexts )
58+ }
59+
4760 if err != nil {
4861 return nil , err
4962 }
@@ -94,3 +107,44 @@ func (h *toolCredentialStore) Store(authConfig types.AuthConfig) error {
94107 Secret : authConfig .Password ,
95108 })
96109}
110+
111+ // listWithContexts is almost an exact copy of the List function in Docker's libraries,
112+ // the only difference being that we pass the context through as input to the program.
113+ // This will allow some credential stores, like Postgres, to do an optimized list.
114+ func listWithContexts (program client.ProgramFunc , contexts []string ) (map [string ]string , error ) {
115+ cmd := program (credentials2 .ActionList )
116+
117+ contextsJSON , err := json .Marshal (contexts )
118+ if err != nil {
119+ return nil , err
120+ }
121+
122+ cmd .Input (bytes .NewReader (contextsJSON ))
123+ out , err := cmd .Output ()
124+ if err != nil {
125+ t := strings .TrimSpace (string (out ))
126+
127+ if isValidErr := isValidCredsMessage (t ); isValidErr != nil {
128+ err = isValidErr
129+ }
130+
131+ return nil , fmt .Errorf ("error listing credentials - err: %v, out: `%s`" , err , t )
132+ }
133+
134+ var resp map [string ]string
135+ if err = json .NewDecoder (bytes .NewReader (out )).Decode (& resp ); err != nil {
136+ return nil , err
137+ }
138+
139+ return resp , nil
140+ }
141+
142+ func isValidCredsMessage (msg string ) error {
143+ if credentials2 .IsCredentialsMissingServerURLMessage (msg ) {
144+ return credentials2 .NewErrCredentialsMissingServerURL ()
145+ }
146+ if credentials2 .IsCredentialsMissingUsernameMessage (msg ) {
147+ return credentials2 .NewErrCredentialsMissingUsername ()
148+ }
149+ return nil
150+ }
0 commit comments