diff --git a/internal/sso/cache.go b/internal/sso/cache.go index 5e5e759..effe268 100644 --- a/internal/sso/cache.go +++ b/internal/sso/cache.go @@ -27,13 +27,17 @@ type ClientRegistrationCache struct { ReceivedAt time.Time `json:"receivedAt"` } -// normalizeStartURL removes trailing /# or / to match aws-sso-util format +// normalizeStartURL removes a trailing "#" or "/" from startURL to normalize AWS SSO start URLs. func normalizeStartURL(startURL string) string { startURL = strings.TrimSuffix(startURL, "#") startURL = strings.TrimSuffix(startURL, "/") return startURL } +// getTokenCachePath returns the filesystem path for the SSO token cache file corresponding to startURL. +// It ensures the ~/.aws/sso/cache directory exists, normalizes startURL (removes trailing "#" and "/"), +// and uses the SHA-1 hex of the normalized URL with a ".json" extension as the filename. +// An error is returned if the user's home directory cannot be determined or the cache directory cannot be created. func getTokenCachePath(startURL string) (string, error) { homeDir, err := os.UserHomeDir() if err != nil { @@ -52,6 +56,15 @@ func getTokenCachePath(startURL string) (string, error) { return filepath.Join(cacheDir, hash+".json"), nil } +// LoadTokenCache loads the SSO token cache for the given start URL. +// It first attempts a direct lookup using the normalized start URL hash, and if that +// fails it scans the SSO cache directory for a token whose stored StartUrl matches +// the provided start URL (after normalization). +// +// The startURL parameter is the SSO start URL used to locate the cached token. +// It returns a pointer to the TokenCache when a matching cache file is found, +// (nil, nil) if no matching token exists, or (nil, error) if an I/O or parsing +// error occurs. func LoadTokenCache(startURL string) (*TokenCache, error) { // First try direct path lookup with normalized URL path, err := getTokenCachePath(startURL) @@ -72,7 +85,10 @@ func LoadTokenCache(startURL string) (*TokenCache, error) { return findTokenByStartURL(startURL) } -// findTokenByStartURL scans all cache files to find a token matching the startURL +// findTokenByStartURL scans the user's SSO cache (~/.aws/sso/cache) for a token whose StartUrl matches the provided startURL after normalization. +// It ignores directories, non-`.json` files, and files prefixed with "botocore-client-id-"; unreadable or unparseable files are skipped. +// If a matching token is found it is returned. If no match is found or the cache directory does not exist, (nil, nil) is returned. +// Any error encountered while reading the cache directory is returned. func findTokenByStartURL(startURL string) (*TokenCache, error) { homeDir, err := os.UserHomeDir() if err != nil { @@ -119,6 +135,9 @@ func findTokenByStartURL(startURL string) (*TokenCache, error) { return nil, nil } +// SaveTokenCache writes a botocore-compatible SSO token cache file for the given start URL and region. +// It serializes a TokenCache containing the normalized StartUrl, Region, AccessToken, ExpiresAt, and the current ReceivedAt timestamp, and writes it to the per-start-URL cache file with file mode 0600. +// Returns an error if the cache path cannot be determined, JSON marshaling fails, or the file cannot be written. func SaveTokenCache(accessToken, startUrl, region string, expiresAt time.Time) error { path, err := getTokenCachePath(startUrl) if err != nil { @@ -141,6 +160,10 @@ func SaveTokenCache(accessToken, startUrl, region string, expiresAt time.Time) e return os.WriteFile(path, data, 0600) } +// ClearTokenCache removes all SSO token cache JSON files from the user's +// ~/.aws/sso/cache directory except for botocore client-registration files. +// It returns nil if the cache directory does not exist and otherwise +// propagates any filesystem errors encountered while reading or removing files. func ClearTokenCache() error { homeDir, err := os.UserHomeDir() if err != nil { @@ -178,6 +201,7 @@ func ClearTokenCache() error { return nil } +// user home directory cannot be determined or the cache directory cannot be created. func getClientRegistrationCachePath(region string) (string, error) { homeDir, err := os.UserHomeDir() if err != nil { @@ -194,6 +218,8 @@ func getClientRegistrationCachePath(region string) (string, error) { return filepath.Join(cacheDir, filename), nil } +// LoadClientRegistration reads the botocore-style client registration cache for the given region. +// It returns the cached ClientRegistrationCache if present, `nil, nil` when no cache file exists, or an error if reading or JSON unmarshalling fails. func LoadClientRegistration(region string) (*ClientRegistrationCache, error) { path, err := getClientRegistrationCachePath(region) if err != nil { @@ -216,6 +242,8 @@ func LoadClientRegistration(region string) (*ClientRegistrationCache, error) { return &cache, nil } +// SaveClientRegistration writes botocore-compatible client registration data for the given region into the SSO cache directory. +// The stored record contains the client ID, client secret, the provided expiration time, and the current receipt timestamp; an error is returned if the cache path cannot be determined or the file cannot be written. func SaveClientRegistration(region, clientId, clientSecret string, expiresAt time.Time) error { path, err := getClientRegistrationCachePath(region) if err != nil { @@ -235,4 +263,4 @@ func SaveClientRegistration(region, clientId, clientSecret string, expiresAt tim } return os.WriteFile(path, data, 0600) -} +} \ No newline at end of file