2024-02-23 09:44:57 +00:00
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2024-06-22 01:16:24 +01:00
|
|
|
|
|
|
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
|
2024-02-23 09:44:57 +00:00
|
|
|
)
|
|
|
|
|
2024-02-27 09:31:17 +00:00
|
|
|
const (
|
2024-06-25 12:39:39 +01:00
|
|
|
defaultCredentialsFileName = "credentials.json"
|
2024-02-27 09:31:17 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type CredentialsConfig struct {
|
|
|
|
CurrentAccount string `json:"currentAccount"`
|
|
|
|
Credentials map[string]Credentials `json:"credentials"`
|
2024-02-23 09:44:57 +00:00
|
|
|
}
|
|
|
|
|
2024-02-27 09:31:17 +00:00
|
|
|
type Credentials struct {
|
2024-02-23 09:44:57 +00:00
|
|
|
Instance string `json:"instance"`
|
|
|
|
ClientID string `json:"clientId"`
|
|
|
|
ClientSecret string `json:"clientSecret"`
|
|
|
|
AccessToken string `json:"accessToken"`
|
|
|
|
}
|
|
|
|
|
2024-05-22 23:30:09 +01:00
|
|
|
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.
|
2024-06-25 12:39:39 +01:00
|
|
|
func SaveCredentials(filePath, username string, credentials Credentials) (string, error) {
|
2024-08-18 21:13:08 +01:00
|
|
|
part := filepath.Dir(filePath)
|
2024-06-25 12:39:39 +01:00
|
|
|
|
2024-08-18 21:13:08 +01:00
|
|
|
// ensure that the directory exists.
|
|
|
|
credentialsDir, err := utilities.CalculateConfigDir(part)
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("unable to calculate the directory to your credentials file: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := utilities.EnsureDirectory(credentialsDir); err != nil {
|
2024-06-02 11:35:43 +01:00
|
|
|
return "", fmt.Errorf("unable to ensure the configuration directory: %w", err)
|
2024-02-23 09:44:57 +00:00
|
|
|
}
|
|
|
|
|
2024-02-27 09:31:17 +00:00
|
|
|
var authConfig CredentialsConfig
|
2024-02-23 09:44:57 +00:00
|
|
|
|
2024-06-25 12:39:39 +01:00
|
|
|
if _, err := os.Stat(filePath); err != nil {
|
2024-02-23 09:44:57 +00:00
|
|
|
if !errors.Is(err, os.ErrNotExist) {
|
2024-06-25 12:39:39 +01:00
|
|
|
return "", fmt.Errorf("unknown error received when running stat on %s: %w", filePath, err)
|
2024-02-23 09:44:57 +00:00
|
|
|
}
|
|
|
|
|
2024-02-27 09:31:17 +00:00
|
|
|
authConfig.Credentials = make(map[string]Credentials)
|
2024-02-23 09:44:57 +00:00
|
|
|
} else {
|
2024-06-25 12:39:39 +01:00
|
|
|
authConfig, err = NewCredentialsConfigFromFile(filePath)
|
2024-02-23 09:44:57 +00:00
|
|
|
if err != nil {
|
2024-06-02 11:35:43 +01:00
|
|
|
return "", fmt.Errorf("unable to retrieve the existing authentication configuration: %w", err)
|
2024-02-23 09:44:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-25 12:39:39 +01:00
|
|
|
instance := utilities.GetFQDN(credentials.Instance)
|
2024-02-23 09:44:57 +00:00
|
|
|
|
|
|
|
authenticationName := username + "@" + instance
|
|
|
|
|
|
|
|
authConfig.CurrentAccount = authenticationName
|
|
|
|
|
2024-02-27 09:31:17 +00:00
|
|
|
authConfig.Credentials[authenticationName] = credentials
|
2024-02-23 09:44:57 +00:00
|
|
|
|
2024-06-25 12:39:39 +01:00
|
|
|
if err := saveCredentialsConfigFile(authConfig, filePath); err != nil {
|
2024-06-02 11:35:43 +01:00
|
|
|
return "", fmt.Errorf("unable to save the authentication configuration to file: %w", err)
|
2024-02-23 09:44:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return authenticationName, nil
|
|
|
|
}
|
|
|
|
|
2024-06-25 12:39:39 +01:00
|
|
|
func UpdateCurrentAccount(account string, filePath string) error {
|
|
|
|
credentialsConfig, err := NewCredentialsConfigFromFile(filePath)
|
2024-02-23 09:44:57 +00:00
|
|
|
if err != nil {
|
2024-06-02 11:35:43 +01:00
|
|
|
return fmt.Errorf("unable to retrieve the existing authentication configuration: %w", err)
|
2024-02-23 09:44:57 +00:00
|
|
|
}
|
|
|
|
|
2024-05-22 23:30:09 +01:00
|
|
|
if _, ok := credentialsConfig.Credentials[account]; !ok {
|
|
|
|
return CredentialsNotFoundError{account}
|
2024-02-23 09:44:57 +00:00
|
|
|
}
|
|
|
|
|
2024-05-22 23:30:09 +01:00
|
|
|
credentialsConfig.CurrentAccount = account
|
2024-02-23 09:44:57 +00:00
|
|
|
|
2024-06-25 12:39:39 +01:00
|
|
|
if err := saveCredentialsConfigFile(credentialsConfig, filePath); err != nil {
|
2024-06-02 11:35:43 +01:00
|
|
|
return fmt.Errorf("unable to save the authentication configuration to file: %w", err)
|
2024-02-23 09:44:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-06-25 12:39:39 +01:00
|
|
|
// NewCredentialsConfigFromFile creates a new CredentialsConfig value from reading
|
|
|
|
// the credentials file.
|
|
|
|
func NewCredentialsConfigFromFile(filePath string) (CredentialsConfig, error) {
|
|
|
|
file, err := os.Open(filePath)
|
2024-02-23 09:44:57 +00:00
|
|
|
if err != nil {
|
2024-06-25 12:39:39 +01:00
|
|
|
return CredentialsConfig{}, fmt.Errorf("unable to open %s: %w", filePath, err)
|
2024-02-23 09:44:57 +00:00
|
|
|
}
|
2024-05-22 23:30:09 +01:00
|
|
|
defer file.Close()
|
2024-02-23 09:44:57 +00:00
|
|
|
|
2024-05-22 23:30:09 +01:00
|
|
|
var authConfig CredentialsConfig
|
2024-02-23 09:44:57 +00:00
|
|
|
|
2024-05-22 23:30:09 +01:00
|
|
|
if err := json.NewDecoder(file).Decode(&authConfig); err != nil {
|
2024-06-02 11:35:43 +01:00
|
|
|
return CredentialsConfig{}, fmt.Errorf("unable to decode the JSON data: %w", err)
|
2024-02-23 09:44:57 +00:00
|
|
|
}
|
|
|
|
|
2024-05-22 23:30:09 +01:00
|
|
|
return authConfig, nil
|
2024-02-23 09:44:57 +00:00
|
|
|
}
|
|
|
|
|
2024-06-25 12:39:39 +01:00
|
|
|
func saveCredentialsConfigFile(authConfig CredentialsConfig, filePath string) error {
|
|
|
|
file, err := os.Create(filePath)
|
2024-02-23 09:44:57 +00:00
|
|
|
if err != nil {
|
2024-06-25 12:39:39 +01:00
|
|
|
return fmt.Errorf("unable to create the file at %s: %w", filePath, err)
|
2024-02-23 09:44:57 +00:00
|
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
encoder := json.NewEncoder(file)
|
|
|
|
encoder.SetIndent("", " ")
|
|
|
|
|
|
|
|
if err := encoder.Encode(authConfig); err != nil {
|
2024-06-02 11:35:43 +01:00
|
|
|
return fmt.Errorf("unable to save the JSON data to the authentication config file: %w", err)
|
2024-02-23 09:44:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2024-05-22 23:30:09 +01:00
|
|
|
|
2024-08-18 21:13:08 +01:00
|
|
|
func defaultCredentialsConfigFile(configDir string) (string, error) {
|
|
|
|
dir, err := utilities.CalculateConfigDir(configDir)
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("unable to calculate the config directory: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
path, err := utilities.AbsolutePath(filepath.Join(dir, defaultCredentialsFileName))
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("unable to get the absolute path to the credentials config file: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return path, nil
|
2024-05-22 23:30:09 +01:00
|
|
|
}
|