github.com/argoproj/argo-cd@v1.8.7/util/localconfig/localconfig.go (about) 1 package localconfig 2 3 import ( 4 "fmt" 5 "os" 6 "os/user" 7 "path" 8 9 "github.com/dgrijalva/jwt-go/v4" 10 11 configUtil "github.com/argoproj/argo-cd/util/config" 12 ) 13 14 // LocalConfig is a local Argo CD config file 15 type LocalConfig struct { 16 CurrentContext string `json:"current-context"` 17 Contexts []ContextRef `json:"contexts"` 18 Servers []Server `json:"servers"` 19 Users []User `json:"users"` 20 } 21 22 // ContextRef is a reference to a Server and User for an API client 23 type ContextRef struct { 24 Name string `json:"name"` 25 Server string `json:"server"` 26 User string `json:"user"` 27 } 28 29 // Context is the resolved Server and User objects resolved 30 type Context struct { 31 Name string 32 Server Server 33 User User 34 } 35 36 // Server contains Argo CD server information 37 type Server struct { 38 // Server is the Argo CD server address 39 Server string `json:"server"` 40 // Insecure indicates to connect to the server over TLS insecurely 41 Insecure bool `json:"insecure,omitempty"` 42 // GRPCWeb indicates to connect to the server using gRPC Web protocol 43 GRPCWeb bool `json:"grpc-web,omitempty"` 44 // GRPCWebRootPath indicates to connect to the server using gRPC Web protocol with this root path 45 GRPCWebRootPath string `json:"grpc-web-root-path"` 46 // CACertificateAuthorityData is the base64 string of a PEM encoded certificate 47 // TODO: not yet implemented 48 CACertificateAuthorityData string `json:"certificate-authority-data,omitempty"` 49 // ClientCertificateData is the base64 string of a PEM encoded certificate used to authenticate the client 50 ClientCertificateData string `json:"client-certificate-data,omitempty"` 51 // ClientCertificateKeyData is the base64 string of a PEM encoded private key of the client certificate 52 ClientCertificateKeyData string `json:"client-certificate-key-data,omitempty"` 53 // PlainText indicates to connect with TLS disabled 54 PlainText bool `json:"plain-text,omitempty"` 55 } 56 57 // User contains user authentication information 58 type User struct { 59 Name string `json:"name"` 60 AuthToken string `json:"auth-token,omitempty"` 61 RefreshToken string `json:"refresh-token,omitempty"` 62 } 63 64 // Claims returns the standard claims from the JWT claims 65 func (u *User) Claims() (*jwt.StandardClaims, error) { 66 parser := &jwt.Parser{ 67 ValidationHelper: jwt.NewValidationHelper(jwt.WithoutClaimsValidation(), jwt.WithoutAudienceValidation()), 68 } 69 claims := jwt.StandardClaims{} 70 _, _, err := parser.ParseUnverified(u.AuthToken, &claims) 71 if err != nil { 72 return nil, err 73 } 74 return &claims, nil 75 } 76 77 // ReadLocalConfig loads up the local configuration file. Returns nil if config does not exist 78 func ReadLocalConfig(path string) (*LocalConfig, error) { 79 var err error 80 var config LocalConfig 81 err = configUtil.UnmarshalLocalFile(path, &config) 82 if os.IsNotExist(err) { 83 return nil, nil 84 } 85 err = ValidateLocalConfig(config) 86 if err != nil { 87 return nil, err 88 } 89 return &config, nil 90 } 91 92 func ValidateLocalConfig(config LocalConfig) error { 93 if config.CurrentContext == "" { 94 return nil 95 } 96 if _, err := config.ResolveContext(config.CurrentContext); err != nil { 97 return fmt.Errorf("Local config invalid: %s", err) 98 } 99 return nil 100 } 101 102 // WriteLocalConfig writes a new local configuration file. 103 func WriteLocalConfig(config LocalConfig, configPath string) error { 104 err := os.MkdirAll(path.Dir(configPath), os.ModePerm) 105 if err != nil { 106 return err 107 } 108 return configUtil.MarshalLocalYAMLFile(configPath, config) 109 } 110 111 func DeleteLocalConfig(configPath string) error { 112 _, err := os.Stat(configPath) 113 if os.IsNotExist(err) { 114 return err 115 } 116 return os.Remove(configPath) 117 } 118 119 // ResolveContext resolves the specified context. If unspecified, resolves the current context 120 func (l *LocalConfig) ResolveContext(name string) (*Context, error) { 121 if name == "" { 122 if l.CurrentContext == "" { 123 return nil, fmt.Errorf("Local config: current-context unset") 124 } 125 name = l.CurrentContext 126 } 127 for _, ctx := range l.Contexts { 128 if ctx.Name == name { 129 server, err := l.GetServer(ctx.Server) 130 if err != nil { 131 return nil, err 132 } 133 user, err := l.GetUser(ctx.User) 134 if err != nil { 135 return nil, err 136 } 137 return &Context{ 138 Name: ctx.Name, 139 Server: *server, 140 User: *user, 141 }, nil 142 } 143 } 144 return nil, fmt.Errorf("Context '%s' undefined", name) 145 } 146 147 func (l *LocalConfig) GetServer(name string) (*Server, error) { 148 for _, s := range l.Servers { 149 if s.Server == name { 150 return &s, nil 151 } 152 } 153 return nil, fmt.Errorf("Server '%s' undefined", name) 154 } 155 156 func (l *LocalConfig) UpsertServer(server Server) { 157 for i, s := range l.Servers { 158 if s.Server == server.Server { 159 l.Servers[i] = server 160 return 161 } 162 } 163 l.Servers = append(l.Servers, server) 164 } 165 166 // Returns true if server was removed successfully 167 func (l *LocalConfig) RemoveServer(serverName string) bool { 168 for i, s := range l.Servers { 169 if s.Server == serverName { 170 l.Servers = append(l.Servers[:i], l.Servers[i+1:]...) 171 return true 172 } 173 } 174 return false 175 } 176 177 func (l *LocalConfig) GetUser(name string) (*User, error) { 178 for _, u := range l.Users { 179 if u.Name == name { 180 return &u, nil 181 } 182 } 183 return nil, fmt.Errorf("User '%s' undefined", name) 184 } 185 186 func (l *LocalConfig) UpsertUser(user User) { 187 for i, u := range l.Users { 188 if u.Name == user.Name { 189 l.Users[i] = user 190 return 191 } 192 } 193 l.Users = append(l.Users, user) 194 } 195 196 // Returns true if user was removed successfully 197 func (l *LocalConfig) RemoveUser(serverName string) bool { 198 for i, u := range l.Users { 199 if u.Name == serverName { 200 l.Users = append(l.Users[:i], l.Users[i+1:]...) 201 return true 202 } 203 } 204 return false 205 } 206 207 // Returns true if user was removed successfully 208 func (l *LocalConfig) RemoveToken(serverName string) bool { 209 for i, u := range l.Users { 210 if u.Name == serverName { 211 l.Users[i].RefreshToken = "" 212 l.Users[i].AuthToken = "" 213 return true 214 } 215 } 216 return false 217 } 218 219 func (l *LocalConfig) UpsertContext(context ContextRef) { 220 for i, c := range l.Contexts { 221 if c.Name == context.Name { 222 l.Contexts[i] = context 223 return 224 } 225 } 226 l.Contexts = append(l.Contexts, context) 227 } 228 229 // Returns true if context was removed successfully 230 func (l *LocalConfig) RemoveContext(serverName string) (string, bool) { 231 for i, c := range l.Contexts { 232 if c.Name == serverName { 233 l.Contexts = append(l.Contexts[:i], l.Contexts[i+1:]...) 234 return c.Server, true 235 } 236 } 237 return "", false 238 } 239 240 func (l *LocalConfig) IsEmpty() bool { 241 return len(l.Servers) == 0 242 } 243 244 // DefaultConfigDir returns the local configuration path for settings such as cached authentication tokens. 245 func DefaultConfigDir() (string, error) { 246 homeDir := os.Getenv("HOME") 247 if homeDir == "" { 248 usr, err := user.Current() 249 if err != nil { 250 return "", err 251 } 252 homeDir = usr.HomeDir 253 } 254 return path.Join(homeDir, ".argocd"), nil 255 } 256 257 // DefaultLocalConfigPath returns the local configuration path for settings such as cached authentication tokens. 258 func DefaultLocalConfigPath() (string, error) { 259 dir, err := DefaultConfigDir() 260 if err != nil { 261 return "", err 262 } 263 return path.Join(dir, "config"), nil 264 }