enbas/internal/config/credentials.go

134 lines
3.9 KiB
Go
Raw Normal View History

package config
import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
)
const (
defaultCredentialsFileName = "credentials.json"
)
type CredentialsConfig struct {
CurrentAccount string `json:"currentAccount"`
Credentials map[string]Credentials `json:"credentials"`
}
type Credentials struct {
Instance string `json:"instance"`
ClientID string `json:"clientId"`
ClientSecret string `json:"clientSecret"`
AccessToken string `json:"accessToken"`
}
type CredentialsNotFoundError struct {
AccountName string
}
func (e CredentialsNotFoundError) Error() string {
return "unable to find the credentials for the account '" + e.AccountName + "'"
}
// SaveCredentials saves the credentials into the credentials file within the specified configuration
// directory. If the directory is not specified then the default directory is used. If the directory
// is not present, it will be created.
func SaveCredentials(filePath, username string, credentials Credentials) (string, error) {
directory := filepath.Dir(filePath)
if err := utilities.EnsureDirectory(utilities.CalculateConfigDir(directory)); err != nil {
return "", fmt.Errorf("unable to ensure the configuration directory: %w", err)
}
var authConfig CredentialsConfig
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)
}
authConfig.Credentials = make(map[string]Credentials)
} else {
authConfig, err = NewCredentialsConfigFromFile(filePath)
if err != nil {
return "", fmt.Errorf("unable to retrieve the existing authentication configuration: %w", err)
}
}
instance := utilities.GetFQDN(credentials.Instance)
authenticationName := username + "@" + instance
authConfig.CurrentAccount = authenticationName
authConfig.Credentials[authenticationName] = credentials
if err := saveCredentialsConfigFile(authConfig, filePath); err != nil {
return "", fmt.Errorf("unable to save the authentication configuration to file: %w", err)
}
return authenticationName, nil
}
func UpdateCurrentAccount(account string, filePath string) error {
credentialsConfig, err := NewCredentialsConfigFromFile(filePath)
if err != nil {
return fmt.Errorf("unable to retrieve the existing authentication configuration: %w", err)
}
if _, ok := credentialsConfig.Credentials[account]; !ok {
return CredentialsNotFoundError{account}
}
credentialsConfig.CurrentAccount = account
if err := saveCredentialsConfigFile(credentialsConfig, filePath); err != nil {
return fmt.Errorf("unable to save the authentication configuration to file: %w", err)
}
return nil
}
// NewCredentialsConfigFromFile creates a new CredentialsConfig value from reading
// the credentials file.
func NewCredentialsConfigFromFile(filePath string) (CredentialsConfig, error) {
file, err := os.Open(filePath)
if err != nil {
return CredentialsConfig{}, fmt.Errorf("unable to open %s: %w", filePath, err)
}
defer file.Close()
var authConfig CredentialsConfig
if err := json.NewDecoder(file).Decode(&authConfig); err != nil {
return CredentialsConfig{}, fmt.Errorf("unable to decode the JSON data: %w", err)
}
return authConfig, nil
}
func saveCredentialsConfigFile(authConfig CredentialsConfig, filePath string) error {
file, err := os.Create(filePath)
if err != nil {
return fmt.Errorf("unable to create the file at %s: %w", filePath, err)
}
defer file.Close()
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
if err := encoder.Encode(authConfig); err != nil {
return fmt.Errorf("unable to save the JSON data to the authentication config file: %w", err)
}
return nil
}
func defaultCredentialsConfigFile(configDir string) string {
return filepath.Join(utilities.CalculateConfigDir(configDir), defaultCredentialsFileName)
}