Documentation
¶
Overview ¶
Package config manages CLI configuration and profiles.
Index ¶
- Constants
- Variables
- func CredentialsFilePath() string
- func GetUATExpiresAt() (time.Time, error)
- func IsMigrated() bool
- func MigrateConfigFile(path string) (bool, error)
- func NeedsMigration() bool
- func PluginConfigKey(scope, field string) string
- func RedactAPIKey(apiKey string) string
- func ReloadConfigFile() error
- func SaveActiveContext(accountID string, livemode bool) error
- func SaveUATExpiresAt(t time.Time) error
- func ValidateProfileName(name string) error
- type ActiveContext
- type ActiveContextLivemodeMismatchError
- type AuthorizedAccount
- type Compartment
- type Config
- func (c *Config) CopyProfile(source string, target string) error
- func (c *Config) EditConfig() error
- func (c *Config) GetConfigFolder(xdgPath string) string
- func (c *Config) GetInstalledPlugins() []string
- func (c *Config) GetMachineUUID() string
- func (c *Config) GetProfile() *Profile
- func (c *Config) InitConfig()
- func (c *Config) ListProfiles() error
- func (c *Config) PrintConfig() error
- func (c *Config) RemoveAllAuthFields() error
- func (c *Config) RemoveAllProfiles() error
- func (c *Config) RemoveAuthFields(profileName string) error
- func (c *Config) RemoveProfile(profileName string) error
- func (c *Config) SwitchProfile(profileName string) error
- func (c *Config) WriteConfigField(field string, value interface{}) error
- type IConfig
- type Profile
- func (p *Profile) CreateProfile() error
- func (p *Profile) DeleteConfigField(field string) error
- func (p *Profile) GetAPIKey(livemode bool) (string, error)
- func (p *Profile) GetAccountID() (string, error)
- func (p *Profile) GetColor() (string, error)
- func (p *Profile) GetCompartmentID(livemode bool) (string, error)
- func (p *Profile) GetConfigField(field string) string
- func (p *Profile) GetDeviceName() (string, error)
- func (p *Profile) GetDisplayName() string
- func (p *Profile) GetExpiresAt(livemode bool) (time.Time, error)
- func (p *Profile) GetPublishableKey(livemode bool) (string, error)
- func (p *Profile) GetSessionCredentials() (*SessionCredentials, error)
- func (p *Profile) GetTerminalPOSDeviceID() string
- func (p *Profile) GetUAT() (string, error)
- func (p *Profile) GetUserID() (string, error)
- func (p *Profile) GetUserInfo() (*UserInfo, error)
- func (p *Profile) HasAPIKey(livemode bool) bool
- func (p *Profile) HasOverrideAPIKey() bool
- func (p *Profile) PrintActiveContextBanner()
- func (p *Profile) ReadProfileString(field string) string
- func (p *Profile) ReadProfileStringMap(field string) map[string]string
- func (p *Profile) RegisterAlias(alias, key string)
- func (p *Profile) ResolveCredentials(livemode bool) (stripe.Credentials, error)
- func (p *Profile) ResolveCredentialsForAnyMode(livemode bool) (stripe.Credentials, error)
- func (p *Profile) ValidateProfileNameForWrite() error
- func (p *Profile) WarnIfLegacyProfileName()
- func (p *Profile) WriteConfigField(field, value string) error
- type SessionCredentials
- type UserInfo
Constants ¶
const ( // ColorName is the color setting. It is also a valid profile field, so it can // appear both at the top level and inside a profile. ColorName = "color" // InstalledPluginsKey lists the locally installed plugins. InstalledPluginsKey = "installed_plugins" // MachineUUIDKey is the persistent machine identifier used for telemetry. MachineUUIDKey = "machine_uuid" )
Top-level config.toml keys that belong to the CLI itself rather than to a profile. A profile with one of these names is a collision, which is what moving profiles under the reserved profiles table fixes.
const ( // PluginConfigGlobalScope is used as the scope when a setting applies to all plugins. PluginConfigGlobalScope = "__global" // PluginConfigUpdatesField is the config field name controlling automatic updates. PluginConfigUpdatesField = "updates" // PluginConfigsKey is the top-level table holding every plugin config // section. It is a CLI setting, not a profile. PluginConfigsKey = "plugin_configs" )
const ( AccountIDName = "account_id" UserIDName = "user_id" DeviceNameName = "device_name" DisplayNameName = "display_name" IsTermsAcceptanceValidName = "is_terms_acceptance_valid" TestModeAPIKeyName = "test_mode_api_key" TestModePubKeyName = "test_mode_pub_key" TestModeKeyExpiresAtName = "test_mode_key_expires_at" LiveModeAPIKeyName = "live_mode_api_key" LiveModePubKeyName = "live_mode_pub_key" LiveModeKeyExpiresAtName = "live_mode_key_expires_at" SandboxClaimURLName = "sandbox_claim_url" SandboxExpiresAtName = "sandbox_expires_at" UserInfoName = "user_info" // TODO: remove with legacy RAK/OIDC flow // ConfigVersionName is the top-level key recording the config file's schema // version. It is absent from v1 files, which is how an unmigrated file is // recognized. ConfigVersionName = "config_version" // ProfilesTableName is the reserved top-level table that holds every profile // in a v2 config file. ProfilesTableName = "profiles" )
config key names
const ( // DateStringFormat is the format for expiredAt date DateStringFormat = "2006-01-02" // KeyValidInDays is the number of days the API key is valid for KeyValidInDays = 90 // KeyManagementService is the key management service name KeyManagementService = "StripeCLI" )
const ColorAuto = "auto"
ColorAuto represents the auto-state for colors
const ColorOff = "off"
ColorOff represents the off-state for colors
const ColorOn = "on"
ColorOn represnets the on-state for colors
const ConfigBackupSuffix = ".v1.bak"
ConfigBackupSuffix is appended to the config file name to name the backup that the migration leaves behind, e.g. "config.toml.v1.bak".
const ConfigVersionV1 = 1
ConfigVersionV1 is the original layout, with each profile as a top-level table. A v1 file records no config_version key at all; the constant exists so that version comparisons don't have to spell out that absence.
const ConfigVersionV2 = 2
ConfigVersionV2 is the schema version in which every profile moved under the reserved ProfilesTableName table, so that profile names can no longer collide with top-level CLI settings.
const MaxSupportedConfigVersion = ConfigVersionV2
MaxSupportedConfigVersion is the newest config.toml layout this binary can act on. A file recording a higher version was written by a newer CLI, whose layout this build has no way to know.
const OAuthActiveContextKeychainKey = "oauth_active_context"
OAuthActiveContextKeychainKey is the keyring key for the active OAuth context.
const OAuthRefreshTokenKeychainKey = "oauth_refresh_token"
OAuthRefreshTokenKeychainKey is the keyring key for the OAuth refresh token.
const OAuthUATExpiresAtKeychainKey = "oauth_uat_expires_at"
OAuthUATExpiresAtKeychainKey is the keyring key for the UAT expiry time (RFC3339).
const UATKeychainItemKey = "uat"
Variables ¶
var ErrProfileNotFound = errorcategory.New(errorcategory.UserInput, "profile not found")
ErrProfileNotFound is returned when no profile matches the requested name.
var KeyRing keyring.SecureStore
KeyRing is the global secure credential store.
var OAuthTokenRefresher func(p *Profile) error
OAuthTokenRefresher is called by ResolveCredentials when an OAK token is expired or about to expire. It refreshes the token and updates p in-place. Set by the login package via init().
Functions ¶
func CredentialsFilePath ¶ added in v1.43.0
func CredentialsFilePath() string
CredentialsFilePath returns the path of the plain-text credentials file used by the file fallback store when the OS keyring is unavailable.
func GetUATExpiresAt ¶ added in v1.45.3
GetUATExpiresAt retrieves the stored UAT expiry time from the keyring. Returns ErrKeyNotFound (wrapped) when no expiry has been saved.
func IsMigrated ¶ added in v1.50.7
func IsMigrated() bool
IsMigrated reports whether the loaded config file uses the v2 layout.
func MigrateConfigFile ¶ added in v1.50.7
MigrateConfigFile rewrites the config file at path in the v2 layout, moving every profile under the reserved profiles table and recording config_version = 2. It reports whether the file changed.
The original file is copied to path + ConfigBackupSuffix first. The migrated document is verified in memory and again after the write; a failure at either point restores the backup and returns an error, so a partial or mangled file is never left behind.
A file whose config_version is newer than this binary understands is left untouched and returns an error.
This function does not decide *whether* to migrate. Callers own that.
func NeedsMigration ¶ added in v1.50.7
func NeedsMigration() bool
NeedsMigration reports whether the loaded config file should be rewritten in the v2 layout. It answers from the config already in memory, so it costs nothing on the common path.
It does not check that migrating is safe for plugins, and it does not check that the config file exists: a viper with no file loaded looks exactly like an unmigrated one.
func PluginConfigKey ¶ added in v1.40.1
PluginConfigKey returns the key for a plugin config field. Use PluginConfigGlobalScope as scope to target all plugins. Use the plugin name as scope to target a specific plugin. Example: PluginConfigKey("__global", "updates") to read or set the global updates setting Example: PluginConfigKey("apps", "updates") to read or set the updates setting for the "apps" plugin
func RedactAPIKey ¶ added in v1.10.4
RedactAPIKey returns a redacted version of API keys. The first 8 and last 4 characters are not redacted, everything else is replaced by "*" characters.
It panics if the provided string has less than 12 characters.
func ReloadConfigFile ¶ added in v1.50.7
func ReloadConfigFile() error
ReloadConfigFile re-reads the config file into the global viper, replacing what is already loaded rather than merging into it. Anything that rewrites the file behind viper's back — the config migration, for one — needs this to see its own changes.
The reset matters: ReadInConfig merges with existing values, so keys the rewrite removed would otherwise linger in memory.
func SaveActiveContext ¶ added in v1.45.3
SaveActiveContext persists the active OAuth context (account ID + livemode) in the keyring so that ResolveCredentials can build the Stripe-Context header.
func SaveUATExpiresAt ¶ added in v1.45.3
SaveUATExpiresAt persists the UAT expiry time in the keyring.
func ValidateProfileName ¶ added in v1.50.7
ValidateProfileName reports whether name can be used as a profile name.
A period is rejected because it is viper's path separator, which hides the profile from every operation that enumerates top-level tables; see WarnIfLegacyProfileName for the full explanation. An empty name produces a leading-period key that viper silently drops, so writes to it are discarded without error.
Every other character round-trips correctly and is allowed.
Types ¶
type ActiveContext ¶ added in v1.45.3
ActiveContext identifies the account and mode that is currently selected.
func GetActiveContext ¶ added in v1.45.3
func GetActiveContext() (*ActiveContext, error)
GetActiveContext reads the stored OAuth active context from the keyring. Returns nil, nil when no active context has been saved yet.
type ActiveContextLivemodeMismatchError ¶ added in v1.45.3
ActiveContextLivemodeMismatchError indicates that the requested livemode does not match the OAuth active context's livemode. Callers that expose their own mode selection (e.g. a --live flag) can catch this with errors.As and explain how to reconcile it; callers that don't care which mode is used can retry ResolveCredentials(err.ActiveLivemode) to get credentials for whichever mode is actually active.
func (*ActiveContextLivemodeMismatchError) Error ¶ added in v1.45.3
func (e *ActiveContextLivemodeMismatchError) Error() string
type AuthorizedAccount ¶ added in v1.45.3
type AuthorizedAccount struct {
ID string `json:"id"`
Name string `json:"name"`
Modes []string `json:"modes"`
}
AuthorizedAccount represents a Stripe account accessible to an OAuth token.
type Compartment ¶ added in v1.42.12
type Compartment struct {
CompartmentID string `json:"compartment_id" mapstructure:"compartment_id" toml:"compartment_id"`
Livemode bool `json:"livemode" mapstructure:"livemode" toml:"livemode"`
}
Compartment represents a Stripe workspace from the OIDC userinfo response. TODO: remove with legacy RAK/OIDC flow.
type Config ¶
type Config struct {
Color string
LogLevel string
Profile Profile
ProfilesFile string
InstalledPlugins []string
// contains filtered or unexported fields
}
Config handles all overall configuration for the CLI
func (*Config) CopyProfile ¶ added in v1.38.0
func (*Config) EditConfig ¶ added in v0.3.0
EditConfig opens the configuration file in the default editor.
func (*Config) GetConfigFolder ¶ added in v0.6.0
func (*Config) GetInstalledPlugins ¶ added in v1.9.0
GetInstalledPlugins returns a list of locally installed plugins. This does not vary by profile
func (*Config) GetMachineUUID ¶ added in v1.44.1
GetMachineUUID returns the persistent machine UUID from config, generating and saving one if it doesn't exist.
func (*Config) GetProfile ¶ added in v1.8.0
GetProfile returns the Profile of the config
func (*Config) InitConfig ¶
func (c *Config) InitConfig()
InitConfig reads in profiles file and ENV variables if set.
func (*Config) ListProfiles ¶ added in v1.38.0
func (*Config) PrintConfig ¶ added in v0.3.0
PrintConfig outputs the contents of the configuration file.
func (*Config) RemoveAllAuthFields ¶ added in v1.40.1
RemoveAllAuthFields removes only auth-related fields from all profiles, preserving non-auth settings like color.
func (*Config) RemoveAllProfiles ¶ added in v1.4.0
RemoveAllProfiles removes all the profiles from the config file.
func (*Config) RemoveAuthFields ¶ added in v1.40.1
RemoveAuthFields removes only auth-related fields for the named profile, preserving non-auth settings like color.
func (*Config) RemoveProfile ¶ added in v1.4.0
RemoveProfile removes the profile whose name matches the provided profileName from the config file.
It returns ErrProfileNotFound when there is nothing to remove, so a caller acting on a name a user typed can tell the difference between a removal and a no-op. Callers that treat removal as best effort can ignore it.
func (*Config) SwitchProfile ¶ added in v1.38.0
func (*Config) WriteConfigField ¶ added in v1.8.2
WriteConfigField updates a configuration field and writes the updated configuration to disk.
type IConfig ¶ added in v1.8.0
type IConfig interface {
GetProfile() *Profile
GetConfigFolder(xdgPath string) string
InitConfig()
EditConfig() error
PrintConfig() error
CopyProfile(source string, target string) error
ListProfiles() error
SwitchProfile(targetProfileName string) error
RemoveProfile(profileName string) error
RemoveAllProfiles() error
RemoveAuthFields(profileName string) error
RemoveAllAuthFields() error
WriteConfigField(field string, value interface{}) error
GetInstalledPlugins() []string
GetMachineUUID() string
}
IConfig allows us to add more implementations, such as ones for unit tests
type Profile ¶
type Profile struct {
DeviceName string
ProfileName string
APIKey string
LiveModeAPIKey string
LiveModePublishableKey string
TestModeAPIKey string
TestModePublishableKey string
TerminalPOSDeviceID string
DisplayName string
AccountID string
UserID string
SandboxClaimURL string
SandboxExpiresAt string
UAT string
UserInfo *UserInfo // TODO: remove with legacy RAK/OIDC flow
// OAuthAccessBaseURL is the access-srv base URL to use for token refresh
// and revocation. Set at startup from the --access-base flag; not persisted.
OAuthAccessBaseURL string
}
Profile handles all things related to managing the project specific configurations
func (*Profile) CreateProfile ¶
CreateProfile creates a profile when logging in
func (*Profile) DeleteConfigField ¶ added in v0.3.0
DeleteConfigField deletes a configuration field.
func (*Profile) GetAPIKey ¶ added in v0.3.0
GetAPIKey will return the existing key for the given profile
func (*Profile) GetAccountID ¶ added in v1.7.4
GetAccountID returns the accountId for the given profile.
func (*Profile) GetColor ¶ added in v0.5.2
GetColor gets the color setting for the user based on the flag or the persisted color stored in the config file
func (*Profile) GetCompartmentID ¶ added in v1.45.0
GetCompartmentID returns the account ID for the given livemode from the legacy OIDC UserInfo stored in the config file. TODO: remove with legacy RAK/OIDC flow.
func (*Profile) GetConfigField ¶
GetConfigField returns the flat (v1) configuration path for a profile field, e.g. "default.account_id".
This same string is used verbatim as the keyring item ID for livemode secrets, so it must not gain the v2 "profiles." prefix: changing it would orphan every credential already stored in the OS keychain. To read a config value, use ReadProfileString or profileFieldIsSet, which understand both the v1 and v2 layouts. To write one, use configFieldForWrite.
func (*Profile) GetDeviceName ¶
GetDeviceName returns the configured device name
func (*Profile) GetDisplayName ¶ added in v1.5.6
GetDisplayName returns the account display name of the user
func (*Profile) GetExpiresAt ¶ added in v1.10.4
GetExpiresAt returns the API key expirary date
func (*Profile) GetPublishableKey ¶ added in v0.6.0
GetPublishableKey returns the publishable key for the user
func (*Profile) GetSessionCredentials ¶ added in v1.14.2
func (p *Profile) GetSessionCredentials() (*SessionCredentials, error)
GetSessionCredentials retrieves the session credentials from the keyring
func (*Profile) GetTerminalPOSDeviceID ¶ added in v1.4.0
GetTerminalPOSDeviceID returns the device id from the config for Terminal quickstart to use
func (*Profile) GetUAT ¶ added in v1.45.0
GetUAT retrieves the user access token from the keyring. Returns an empty string if no UAT is stored.
func (*Profile) GetUserInfo ¶ added in v1.42.12
GetUserInfo reads the stored UserInfo from the profile config. Returns nil, nil when no user_info has been saved yet. TODO: remove with legacy RAK/OIDC flow.
func (*Profile) HasAPIKey ¶ added in v1.42.2
HasAPIKey reports whether an API key is available for the given mode without reading its value. For live mode this checks the keyring key list only, avoiding OS-level auth prompts (e.g. macOS Keychain) that would be required to access the secret data.
func (*Profile) HasOverrideAPIKey ¶ added in v1.42.2
HasOverrideAPIKey reports whether an in-memory API key override is active (via STRIPE_API_KEY env var or --api-key flag).
func (*Profile) PrintActiveContextBanner ¶ added in v1.45.3
func (p *Profile) PrintActiveContextBanner()
PrintActiveContextBanner prints the active context to stderr once per process. Call this at the start of commands that make user-visible Stripe API requests (resource commands, raw HTTP, fixtures, triggers).
func (*Profile) ReadProfileString ¶ added in v1.50.7
ReadProfileString reads a profile field from the config file, preferring the v2 nested layout and falling back to the v1 flat layout.
Both layouts are supported indefinitely. A config file that has never been migrated stays fully readable, and one that a v2 CLI migrated is readable from this release line without the user having to undo anything.
func (*Profile) ReadProfileStringMap ¶ added in v1.50.7
ReadProfileStringMap reads a nested table inside a profile, such as the docs preferences, from whichever layout holds it.
func (*Profile) RegisterAlias ¶ added in v0.3.0
RegisterAlias registers an alias for a given key in both layouts, so that legacy field names (secret_key, api_key, publishable_key) keep resolving in a migrated config file as well as an unmigrated one.
func (*Profile) ResolveCredentials ¶ added in v1.44.1
func (p *Profile) ResolveCredentials(livemode bool) (stripe.Credentials, error)
ResolveCredentials returns the credentials for the given mode. If an OAK token (prefix "oak_") is stored in the keyring and no explicit override is active, it is preferred over the configured API key. For OAK tokens the active context stored in the keyring sets both Stripe-Context and Stripe-Livemode; the livemode parameter is used only for the legacy OIDC fallback and plain API key path. If the active context's livemode differs from the requested livemode, it returns an *ActiveContextLivemodeMismatchError.
func (*Profile) ResolveCredentialsForAnyMode ¶ added in v1.50.1
func (p *Profile) ResolveCredentialsForAnyMode(livemode bool) (stripe.Credentials, error)
ResolveCredentialsForAnyMode resolves credentials for specified mode, but if that doesn't match the OAuth active context, resolves credentials for whichever mode is actually active instead of failing.
func (*Profile) ValidateProfileNameForWrite ¶ added in v1.50.7
ValidateProfileNameForWrite validates the profile name before writing to it.
Profiles that already exist are allowed through unchanged: reads against them work correctly, and refusing to write would leave users unable to update a profile they are actively using. Only the creation of new invalid names is blocked.
This grandfather clause can be dropped once the config migration renames existing dotted profiles, at which point the rule becomes unconditional.
func (*Profile) WarnIfLegacyProfileName ¶ added in v1.50.2
func (p *Profile) WarnIfLegacyProfileName()
WarnIfLegacyProfileName tells the user when the active profile has a period in its name.
Profile fields are addressed as <profile>.<field> keys in viper, which uses "." as its path separator. A profile name containing a period is therefore indistinguishable from a nested table: viper reads ["a.b"] back as a -> b, so the profile becomes invisible to every operation that enumerates top-level tables, even though reads against it keep working. That makes this warning the only signal the user gets that the profile cannot be listed by name.
It only fires for a profile that is actually in the config file, so that a period in a name nobody is using stays silent.
func (*Profile) WriteConfigField ¶ added in v0.3.0
WriteConfigField updates a configuration field and writes the updated configuration to disk.
type SessionCredentials ¶ added in v1.14.2
type SessionCredentials struct {
UAT string `json:"uat"`
PrivateKey string `json:"private_key"`
AccountID string `json:"account_id"`
}
SessionCredentials are the credentials needed for this session
type UserInfo ¶ added in v1.42.12
type UserInfo struct {
Compartments []Compartment `json:"https://stripe.com/compartments" mapstructure:"compartments" toml:"compartments"`
}
UserInfo mirrors the OIDC userinfo endpoint response and is persisted as a nested table in the profile config. TODO: remove with legacy RAK/OIDC flow.