5
5
"fmt"
6
6
"regexp"
7
7
"slices"
8
+ "sync"
8
9
9
10
"github.com/docker/cli/cli/config/credentials"
10
11
"github.com/docker/cli/cli/config/types"
@@ -24,15 +25,20 @@ type CredentialStore interface {
24
25
Refresh (ctx context.Context , cred Credential ) error
25
26
Remove (ctx context.Context , toolName string ) error
26
27
List (ctx context.Context ) ([]Credential , error )
28
+ RecreateAll (ctx context.Context ) error
27
29
}
28
30
29
31
type Store struct {
30
- credCtxs []string
31
- cfg * config.CLIConfig
32
- program client.ProgramFunc
32
+ credCtxs []string
33
+ cfg * config.CLIConfig
34
+ program client.ProgramFunc
35
+ recreateAllLock sync.RWMutex
33
36
}
34
37
35
- func (s Store ) Get (_ context.Context , toolName string ) (* Credential , bool , error ) {
38
+ func (s * Store ) Get (_ context.Context , toolName string ) (* Credential , bool , error ) {
39
+ s .recreateAllLock .RLock ()
40
+ defer s .recreateAllLock .RUnlock ()
41
+
36
42
if len (s .credCtxs ) > 0 && s .credCtxs [0 ] == AllCredentialContexts {
37
43
return nil , false , fmt .Errorf ("cannot get a credential with context %q" , AllCredentialContexts )
38
44
}
@@ -80,7 +86,10 @@ func (s Store) Get(_ context.Context, toolName string) (*Credential, bool, error
80
86
81
87
// Add adds a new credential to the credential store.
82
88
// Any context set on the credential object will be overwritten with the first context of the credential store.
83
- func (s Store ) Add (_ context.Context , cred Credential ) error {
89
+ func (s * Store ) Add (_ context.Context , cred Credential ) error {
90
+ s .recreateAllLock .RLock ()
91
+ defer s .recreateAllLock .RUnlock ()
92
+
84
93
first := first (s .credCtxs )
85
94
if first == AllCredentialContexts {
86
95
return fmt .Errorf ("cannot add a credential with context %q" , AllCredentialContexts )
@@ -99,7 +108,10 @@ func (s Store) Add(_ context.Context, cred Credential) error {
99
108
}
100
109
101
110
// Refresh updates an existing credential in the credential store.
102
- func (s Store ) Refresh (_ context.Context , cred Credential ) error {
111
+ func (s * Store ) Refresh (_ context.Context , cred Credential ) error {
112
+ s .recreateAllLock .RLock ()
113
+ defer s .recreateAllLock .RUnlock ()
114
+
103
115
if ! slices .Contains (s .credCtxs , cred .Context ) {
104
116
return fmt .Errorf ("context %q not in list of valid contexts for this credential store" , cred .Context )
105
117
}
@@ -115,7 +127,10 @@ func (s Store) Refresh(_ context.Context, cred Credential) error {
115
127
return store .Store (auth )
116
128
}
117
129
118
- func (s Store ) Remove (_ context.Context , toolName string ) error {
130
+ func (s * Store ) Remove (_ context.Context , toolName string ) error {
131
+ s .recreateAllLock .RLock ()
132
+ defer s .recreateAllLock .RUnlock ()
133
+
119
134
first := first (s .credCtxs )
120
135
if len (s .credCtxs ) > 1 || first == AllCredentialContexts {
121
136
return fmt .Errorf ("error: credential deletion is not supported when multiple credential contexts are provided" )
@@ -129,7 +144,10 @@ func (s Store) Remove(_ context.Context, toolName string) error {
129
144
return store .Erase (toolNameWithCtx (toolName , first ))
130
145
}
131
146
132
- func (s Store ) List (_ context.Context ) ([]Credential , error ) {
147
+ func (s * Store ) List (_ context.Context ) ([]Credential , error ) {
148
+ s .recreateAllLock .RLock ()
149
+ defer s .recreateAllLock .RUnlock ()
150
+
133
151
store , err := s .getStore ()
134
152
if err != nil {
135
153
return nil , err
@@ -199,6 +217,39 @@ func (s Store) List(_ context.Context) ([]Credential, error) {
199
217
return maps .Values (credsByName ), nil
200
218
}
201
219
220
+ func (s * Store ) RecreateAll (_ context.Context ) error {
221
+ s .recreateAllLock .Lock ()
222
+ defer s .recreateAllLock .Unlock ()
223
+
224
+ store , err := s .getStore ()
225
+ if err != nil {
226
+ return err
227
+ }
228
+
229
+ all , err := store .GetAll ()
230
+ if err != nil {
231
+ return err
232
+ }
233
+
234
+ // Loop through and recreate each individual credential.
235
+ for serverAddress := range all {
236
+ authConfig , err := store .Get (serverAddress )
237
+ if err != nil {
238
+ return err
239
+ }
240
+
241
+ if err := store .Erase (serverAddress ); err != nil {
242
+ return err
243
+ }
244
+
245
+ if err := store .Store (authConfig ); err != nil {
246
+ return err
247
+ }
248
+ }
249
+
250
+ return nil
251
+ }
252
+
202
253
func (s * Store ) getStore () (credentials.Store , error ) {
203
254
if s .program != nil {
204
255
return & toolCredentialStore {
0 commit comments