package main import ( "encoding/json" "errors" "fmt" "os" "path/filepath" "strings" ) type AuthenticationConfig struct { CurrentAccount string `json:"currentAccount"` Authentications map[string]Authentication `json:"authentications"` } type Authentication struct { Instance string `json:"instance"` ClientID string `json:"clientId"` ClientSecret string `json:"clientSecret"` AccessToken string `json:"accessToken"` } func saveAuthenticationConfig(username string, authentication Authentication) error { if err := ensureConfigDir(); err != nil { return fmt.Errorf("unable to ensure the configuration directory; %w", err) } var config AuthenticationConfig filepath := authenticationConfigFile() if _, err := os.Stat(filepath); err != nil { if !errors.Is(err, os.ErrNotExist) { return fmt.Errorf("unknown error received when running stat on %s; %w", filepath, err) } config.Authentications = make(map[string]Authentication) } else { config, err = newAuthenticationConfigFromFile() if err != nil { return fmt.Errorf("unable to retrieve the existing authentication configuration; %w", err) } } instance := "" if strings.HasPrefix(authentication.Instance, "https://") { instance = strings.TrimPrefix(authentication.Instance, "https://") } else if strings.HasPrefix(authentication.Instance, "http://") { instance = strings.TrimPrefix(authentication.Instance, "http://") } authenticationName := username + "@" + instance config.CurrentAccount = authenticationName config.Authentications[authenticationName] = authentication file, err := os.Create(authenticationConfigFile()) if err != nil { return fmt.Errorf("unable to open the config file; %w", err) } if err := json.NewEncoder(file).Encode(config); err != nil { return fmt.Errorf("unable to save the JSON data to the authentication config file; %w", err) } return nil } func newAuthenticationConfigFromFile() (AuthenticationConfig, error) { path := authenticationConfigFile() file, err := os.Open(path) if err != nil { return AuthenticationConfig{}, fmt.Errorf("unable to open %s, %w", path, err) } defer file.Close() var config AuthenticationConfig if err := json.NewDecoder(file).Decode(&config); err != nil { return AuthenticationConfig{}, fmt.Errorf("unable to decode the JSON data; %w", err) } return config, nil } func authenticationConfigFile() string { return filepath.Join(configDir(), "authentications.json") } func configDir() string { rootDir, err := os.UserConfigDir() if err != nil { rootDir = "." } return filepath.Join(rootDir, applicationName) } func ensureConfigDir() error { dir := configDir() if _, err := os.Stat(dir); err != nil { if errors.Is(err, os.ErrNotExist) { if err := os.MkdirAll(dir, 0o750); err != nil { return fmt.Errorf("unable to create %s; %w", dir, err) } } else { return fmt.Errorf("unknown error received when running stat on %s; %w", dir, err) } } return nil }