-
Notifications
You must be signed in to change notification settings - Fork 34
/
store.go
118 lines (105 loc) · 3.04 KB
/
store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package oras
import (
"context"
"fmt"
"os"
"github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/config/credentials"
"github.com/docker/cli/cli/config/types"
"oras.land/oras-go/v2/registry/remote/auth"
)
// Store provides credential CRUD operations.
type Store struct {
configs []*configfile.ConfigFile
}
// NewStore generates a store based on the passed in config file path.
func NewStore(configPaths ...string) (*Store, error) {
if len(configPaths) == 0 {
// No config path passed, load default docker config file.
cfg, err := config.Load(config.Dir())
if err != nil {
return nil, err
}
if !cfg.ContainsAuth() {
cfg.CredentialsStore = credentials.DetectDefaultStore(cfg.CredentialsStore)
}
return &Store{
configs: []*configfile.ConfigFile{cfg},
}, nil
}
var configs []*configfile.ConfigFile
for _, path := range configPaths {
cfg, err := loadConfigFile(path)
if err != nil {
return nil, fmt.Errorf("%s: %w", path, err)
}
configs = append(configs, cfg)
}
return &Store{
configs: configs,
}, nil
}
// loadConfigFile reads the credential-related configurationfrom the given path.
func loadConfigFile(path string) (*configfile.ConfigFile, error) {
var cfg *configfile.ConfigFile
if _, err := os.Stat(path); err != nil {
if os.IsNotExist(err) {
cfg = configfile.New(path)
} else {
return nil, err
}
} else {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
cfg = configfile.New(path)
if err := cfg.LoadFromReader(file); err != nil {
return nil, err
}
}
if !cfg.ContainsAuth() {
cfg.CredentialsStore = credentials.DetectDefaultStore(cfg.CredentialsStore)
}
return cfg, nil
}
// Store stores a credential for a given registry.
func (s *Store) Store(registry string, cred auth.Credential) error {
authConf := types.AuthConfig{
Username: cred.Username,
Password: cred.Password,
ServerAddress: registry,
IdentityToken: cred.RefreshToken,
RegistryToken: cred.AccessToken,
}
return s.configs[0].GetCredentialsStore(registry).Store(authConf)
}
// Erase erases a credential for a given registry.
func (s *Store) Erase(registry string) error {
return s.configs[0].GetCredentialsStore(registry).Erase(registry)
}
// Credential iterates all the config files, returns the first non-empty
// credential in a best-effort way.
// `EmptyCredential` is a valid return value and should not be considered as
// an error.
// If nil, the credential is always resolved to `EmptyCredential`.
func (s *Store) Credential(_ context.Context, registry string) (auth.Credential, error) {
for _, c := range s.configs {
authConf, err := c.GetCredentialsStore(registry).Get(registry)
if err != nil {
return auth.EmptyCredential, err
}
cred := auth.Credential{
Username: authConf.Username,
Password: authConf.Password,
AccessToken: authConf.RegistryToken,
RefreshToken: authConf.IdentityToken,
}
if cred != auth.EmptyCredential {
return cred, nil
}
}
return auth.EmptyCredential, nil
}