lockbox

password manager
Log | Files | Refs | README | LICENSE

commit 059e23465573c662dfeb08c6e3246efdb7049fa2
parent 9c7f86eede5b9d57c5b4f122182f7f84a1c1da3f
Author: Sean Enck <sean@ttypty.com>
Date:   Wed, 26 Jul 2023 18:32:00 -0400

transition int/bool env handlers

Diffstat:
Minternal/app/completions.go | 6+++---
Minternal/app/totp.go | 4++--
Minternal/backend/core.go | 2+-
Minternal/inputs/env.go | 29++++++++++++++++++++---------
Minternal/inputs/vars.go | 80++++++++++++++++++++++++++++---------------------------------------------------
Minternal/inputs/vars_test.go | 22+++++++++++-----------
Minternal/platform/clipboard.go | 4++--
Minternal/platform/colors.go | 4++--
8 files changed, 69 insertions(+), 82 deletions(-)

diff --git a/internal/app/completions.go b/internal/app/completions.go @@ -62,19 +62,19 @@ func GenerateCompletions(isBash, defaults bool) ([]string, error) { isClip := true isTOTP := true if !defaults { - ro, err := inputs.IsReadOnly() + ro, err := inputs.EnvReadOnly.Get() if err != nil { return nil, err } isReadOnly = ro - noClip, err := inputs.IsNoClipEnabled() + noClip, err := inputs.EnvNoClip.Get() if err != nil { return nil, err } if noClip { isClip = false } - noTOTP, err := inputs.IsNoTOTP() + noTOTP, err := inputs.EnvNoTOTP.Get() if err != nil { return nil, err } diff --git a/internal/app/totp.go b/internal/app/totp.go @@ -68,8 +68,8 @@ func NewDefaultTOTPOptions(app CommandOptions) TOTPOptions { return TOTPOptions{ app: app, Clear: clear, - IsInteractive: inputs.IsInteractive, - IsNoTOTP: inputs.IsNoTOTP, + IsInteractive: inputs.EnvInteractive.Get, + IsNoTOTP: inputs.EnvNoTOTP.Get, } } diff --git a/internal/backend/core.go b/internal/backend/core.go @@ -29,7 +29,7 @@ func loadFile(file string, must bool) (*Transaction, error) { return nil, errors.New("invalid file, does not exist") } } - ro, err := inputs.IsReadOnly() + ro, err := inputs.EnvReadOnly.Get() if err != nil { return nil, err } diff --git a/internal/inputs/env.go b/internal/inputs/env.go @@ -27,12 +27,21 @@ var isYesNoArgs = []string{yes, no} type ( // SystemPlatform represents the platform lockbox is running on. - SystemPlatform string - environmentInt struct { - key string + SystemPlatform string + environmentBase struct { + key string + } + // EnvironmentInt are environment settings that are integers + EnvironmentInt struct { + environmentBase defaultValue int - shortDesc string allowZero bool + shortDesc string + } + // EnvironmentBool are environment settings that are booleans + EnvironmentBool struct { + environmentBase + defaultValue bool } ) @@ -60,21 +69,23 @@ func EnvironOrDefault(envKey, defaultValue string) string { return val } -func isYesNoEnv(defaultValue bool, envKey string) (bool, error) { - read := strings.ToLower(strings.TrimSpace(os.Getenv(envKey))) +// Get will get the boolean value for the setting +func (e EnvironmentBool) Get() (bool, error) { + read := strings.ToLower(strings.TrimSpace(os.Getenv(e.key))) switch read { case no: return false, nil case yes: return true, nil case "": - return defaultValue, nil + return e.defaultValue, nil } - return false, fmt.Errorf("invalid yes/no env value for %s", envKey) + return false, fmt.Errorf("invalid yes/no env value for %s", e.key) } -func (e environmentInt) Get() (int, error) { +// Get will get the integer value for the setting +func (e EnvironmentInt) Get() (int, error) { val := e.defaultValue use := os.Getenv(e.key) if use != "" { diff --git a/internal/inputs/vars.go b/internal/inputs/vars.go @@ -14,18 +14,14 @@ import ( ) const ( - otpAuth = "otpauth" - otpIssuer = "lbissuer" - prefixKey = "LOCKBOX_" - noClipEnv = prefixKey + "NOCLIP" - noColorEnv = prefixKey + "NOCOLOR" - interactiveEnv = prefixKey + "INTERACTIVE" - readOnlyEnv = prefixKey + "READONLY" - fieldTOTPEnv = prefixKey + "TOTP" - clipBaseEnv = prefixKey + "CLIP_" - formatTOTPEnv = fieldTOTPEnv + "_FORMAT" - keyModeEnv = prefixKey + "KEYMODE" - keyEnv = prefixKey + "KEY" + otpAuth = "otpauth" + otpIssuer = "lbissuer" + prefixKey = "LOCKBOX_" + fieldTOTPEnv = prefixKey + "TOTP" + clipBaseEnv = prefixKey + "CLIP_" + formatTOTPEnv = fieldTOTPEnv + "_FORMAT" + keyModeEnv = prefixKey + "KEYMODE" + keyEnv = prefixKey + "KEY" // KeyFileEnv is an OPTIONAL keyfile for the database KeyFileEnv = prefixKey + "KEYFILE" plainKeyMode = "plaintext" @@ -42,11 +38,9 @@ const ( ClipPasteEnv = clipBaseEnv + "PASTE" // ClipCopyEnv allows overriding the clipboard copy command ClipCopyEnv = clipBaseEnv + "COPY" - clipOSC52Env = clipBaseEnv + "OSC52" defaultTOTPField = "totp" commandArgsExample = "[cmd args...]" detectedValue = "(detected)" - noTOTPEnv = prefixKey + "NOTOTP" // HookDirEnv represents a stored location for user hooks HookDirEnv = prefixKey + "HOOKDIR" // ModTimeEnv is modtime override ability for entries @@ -67,9 +61,21 @@ const ( var ( // EnvClipboardMax gets the maximum clipboard time - EnvClipboardMax = environmentInt{key: clipBaseEnv + "MAX", shortDesc: "clipboard max time", allowZero: false, defaultValue: 45} + EnvClipboardMax = EnvironmentInt{environmentBase: environmentBase{key: clipBaseEnv + "MAX"}, shortDesc: "clipboard max time", allowZero: false, defaultValue: 45} // EnvHashLength handles the hashing output length - EnvHashLength = environmentInt{key: JSONDataOutputEnv + "_HASH_LENGTH", shortDesc: "hash length", allowZero: true, defaultValue: 0} + EnvHashLength = EnvironmentInt{environmentBase: environmentBase{key: JSONDataOutputEnv + "_HASH_LENGTH"}, shortDesc: "hash length", allowZero: true, defaultValue: 0} + // EnvClipOSC52 indicates if OSC52 clipboard mode is enabled + EnvClipOSC52 = EnvironmentBool{environmentBase: environmentBase{key: clipBaseEnv + "OSC52"}, defaultValue: false} + // EnvNoTOTP indicates if TOTP is disabled + EnvNoTOTP = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "NOTOTP"}, defaultValue: false} + // EnvReadOnly indicates if in read-only mode + EnvReadOnly = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "READONLY"}, defaultValue: false} + // EnvNoClip indicates clipboard functionality is off + EnvNoClip = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "NOCLIP"}, defaultValue: false} + // EnvNoColor indicates if color outputs are disabled + EnvNoColor = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "NOCOLOR"}, defaultValue: false} + // EnvInteractive indicates if operating in interactive mode + EnvInteractive = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "INTERACTIVE"}, defaultValue: true} ) type ( @@ -162,36 +168,6 @@ func getKey(keyMode, name string) ([]byte, error) { return []byte(strings.TrimSpace(string(data))), nil } -// IsClipOSC52 indicates if OSC52 mode is enabled -func IsClipOSC52() (bool, error) { - return isYesNoEnv(false, clipOSC52Env) -} - -// IsNoTOTP indicates if TOTP is disabled -func IsNoTOTP() (bool, error) { - return isYesNoEnv(false, noTOTPEnv) -} - -// IsReadOnly indicates to operate in readonly, no writing to file allowed -func IsReadOnly() (bool, error) { - return isYesNoEnv(false, readOnlyEnv) -} - -// IsNoClipEnabled indicates if clipboard mode is enabled. -func IsNoClipEnabled() (bool, error) { - return isYesNoEnv(false, noClipEnv) -} - -// IsNoColorEnabled indicates if the flag is set to disable color. -func IsNoColorEnabled() (bool, error) { - return isYesNoEnv(false, noColorEnv) -} - -// IsInteractive indicates if running as a user UI experience. -func IsInteractive() (bool, error) { - return isYesNoEnv(true, interactiveEnv) -} - // TOTPToken gets the name of the totp special case tokens func TOTPToken() string { return EnvironOrDefault(fieldTOTPEnv, defaultTOTPField) @@ -216,10 +192,10 @@ func ListEnvironmentVariables(showValues bool) []string { results = append(results, e.formatEnvironmentVariable(true, StoreEnv, "", "directory to the database file", []string{"file"})) results = append(results, e.formatEnvironmentVariable(true, keyModeEnv, commandKeyMode, "how to retrieve the database store password", []string{commandKeyMode, plainKeyMode})) results = append(results, e.formatEnvironmentVariable(true, keyEnv, "", fmt.Sprintf("the database key ('%s' mode) or command to run ('%s' mode)\nto retrieve the database password", plainKeyMode, commandKeyMode), []string{commandArgsExample, "password"})) - results = append(results, e.formatEnvironmentVariable(false, noClipEnv, no, "disable clipboard operations", isYesNoArgs)) - results = append(results, e.formatEnvironmentVariable(false, noColorEnv, no, "disable terminal colors", isYesNoArgs)) - results = append(results, e.formatEnvironmentVariable(false, interactiveEnv, yes, "enable interactive mode", isYesNoArgs)) - results = append(results, e.formatEnvironmentVariable(false, readOnlyEnv, no, "operate in readonly mode", isYesNoArgs)) + results = append(results, e.formatEnvironmentVariable(false, EnvNoClip.key, no, "disable clipboard operations", isYesNoArgs)) + results = append(results, e.formatEnvironmentVariable(false, EnvNoColor.key, no, "disable terminal colors", isYesNoArgs)) + results = append(results, e.formatEnvironmentVariable(false, EnvInteractive.key, yes, "enable interactive mode", isYesNoArgs)) + results = append(results, e.formatEnvironmentVariable(false, EnvReadOnly.key, no, "operate in readonly mode", isYesNoArgs)) results = append(results, e.formatEnvironmentVariable(false, fieldTOTPEnv, defaultTOTPField, "attribute name to store TOTP tokens within the database", []string{"string"})) results = append(results, e.formatEnvironmentVariable(false, formatTOTPEnv, strings.ReplaceAll(strings.ReplaceAll(FormatTOTP("%s"), "%25s", "%s"), "&", " \\\n &"), "override the otpauth url used to store totp tokens. It must have ONE format\nstring ('%s') to insert the totp base code", []string{"otpauth//url/%s/args..."})) results = append(results, e.formatEnvironmentVariable(false, MaxTOTPTime, MaxTOTPTimeDefault, "time, in seconds, in which to show a TOTP token before automatically exiting", []string{"integer"})) @@ -228,9 +204,9 @@ func ListEnvironmentVariables(showValues bool) []string { results = append(results, e.formatEnvironmentVariable(false, ClipCopyEnv, detectedValue, "override the detected platform copy command", []string{commandArgsExample})) results = append(results, e.formatEnvironmentVariable(false, EnvClipboardMax.key, fmt.Sprintf("%d", EnvClipboardMax.defaultValue), "override the amount of time before totp clears the clipboard (e.g. 10),\nmust be an integer", []string{"integer"})) results = append(results, e.formatEnvironmentVariable(false, PlatformEnv, detectedValue, "override the detected platform", PlatformSet())) - results = append(results, e.formatEnvironmentVariable(false, noTOTPEnv, no, "disable TOTP integrations", isYesNoArgs)) + results = append(results, e.formatEnvironmentVariable(false, EnvNoTOTP.key, no, "disable TOTP integrations", isYesNoArgs)) results = append(results, e.formatEnvironmentVariable(false, HookDirEnv, "", "the path to hooks to execute on actions against the database", []string{"directory"})) - results = append(results, e.formatEnvironmentVariable(false, clipOSC52Env, no, "enable OSC52 clipboard mode", isYesNoArgs)) + results = append(results, e.formatEnvironmentVariable(false, EnvClipOSC52.key, no, "enable OSC52 clipboard mode", isYesNoArgs)) results = append(results, e.formatEnvironmentVariable(false, KeyFileEnv, "", "additional keyfile to access/protect the database", []string{"keyfile"})) results = append(results, e.formatEnvironmentVariable(false, ModTimeEnv, ModTimeFormat, fmt.Sprintf("input modification time to set for the entry\n(expected format: %s)", ModTimeFormat), []string{"modtime"})) results = append(results, e.formatEnvironmentVariable(false, JSONDataOutputEnv, string(JSONDataOutputHash), fmt.Sprintf("changes what the data field in JSON outputs will contain\nuse '%s' with CAUTION", JSONDataOutputRaw), []string{string(JSONDataOutputRaw), string(JSONDataOutputHash), string(JSONDataOutputBlank)})) diff --git a/internal/inputs/vars_test.go b/internal/inputs/vars_test.go @@ -9,9 +9,9 @@ import ( "github.com/enckse/lockbox/internal/inputs" ) -func checkYesNo(key string, t *testing.T, cb func() (bool, error), onEmpty bool) { +func checkYesNo(key string, t *testing.T, obj inputs.EnvironmentBool, onEmpty bool) { os.Setenv(key, "yes") - c, err := cb() + c, err := obj.Get() if err != nil { t.Errorf("invalid error: %v", err) } @@ -19,7 +19,7 @@ func checkYesNo(key string, t *testing.T, cb func() (bool, error), onEmpty bool) t.Error("invalid setting") } os.Setenv(key, "") - c, err = cb() + c, err = obj.Get() if err != nil { t.Errorf("invalid error: %v", err) } @@ -27,7 +27,7 @@ func checkYesNo(key string, t *testing.T, cb func() (bool, error), onEmpty bool) t.Error("invalid setting") } os.Setenv(key, "no") - c, err = cb() + c, err = obj.Get() if err != nil { t.Errorf("invalid error: %v", err) } @@ -35,34 +35,34 @@ func checkYesNo(key string, t *testing.T, cb func() (bool, error), onEmpty bool) t.Error("invalid setting") } os.Setenv(key, "afoieae") - _, err = cb() + _, err = obj.Get() if err == nil || err.Error() != fmt.Sprintf("invalid yes/no env value for %s", key) { t.Errorf("unexpected error: %v", err) } } func TestColorSetting(t *testing.T) { - checkYesNo("LOCKBOX_NOCOLOR", t, inputs.IsNoColorEnabled, false) + checkYesNo("LOCKBOX_NOCOLOR", t, inputs.EnvNoColor, false) } func TestInteractiveSetting(t *testing.T) { - checkYesNo("LOCKBOX_INTERACTIVE", t, inputs.IsInteractive, true) + checkYesNo("LOCKBOX_INTERACTIVE", t, inputs.EnvInteractive, true) } func TestIsReadOnly(t *testing.T) { - checkYesNo("LOCKBOX_READONLY", t, inputs.IsReadOnly, false) + checkYesNo("LOCKBOX_READONLY", t, inputs.EnvReadOnly, false) } func TestIsOSC52(t *testing.T) { - checkYesNo("LOCKBOX_CLIP_OSC52", t, inputs.IsClipOSC52, false) + checkYesNo("LOCKBOX_CLIP_OSC52", t, inputs.EnvClipOSC52, false) } func TestIsNoTOTP(t *testing.T) { - checkYesNo("LOCKBOX_NOTOTP", t, inputs.IsNoTOTP, false) + checkYesNo("LOCKBOX_NOTOTP", t, inputs.EnvNoTOTP, false) } func TestIsNoClip(t *testing.T) { - checkYesNo("LOCKBOX_NOCLIP", t, inputs.IsNoClipEnabled, false) + checkYesNo("LOCKBOX_NOCLIP", t, inputs.EnvNoClip, false) } func TestTOTP(t *testing.T) { diff --git a/internal/platform/clipboard.go b/internal/platform/clipboard.go @@ -40,7 +40,7 @@ func overrideCommand(v string) ([]string, error) { // NewClipboard will retrieve the commands to use for clipboard operations. func NewClipboard() (Clipboard, error) { - noClip, err := inputs.IsNoClipEnabled() + noClip, err := inputs.EnvNoClip.Get() if err != nil { return Clipboard{}, err } @@ -58,7 +58,7 @@ func NewClipboard() (Clipboard, error) { if overrideCopy != nil && overridePaste != nil { return newClipboard(overrideCopy, overridePaste) } - isOSC, err := inputs.IsClipOSC52() + isOSC, err := inputs.EnvClipOSC52.Get() if err != nil { return Clipboard{}, err } diff --git a/internal/platform/colors.go b/internal/platform/colors.go @@ -35,13 +35,13 @@ func NewTerminal(color Color) (Terminal, error) { if color != Red { return Terminal{}, errors.New("bad color") } - interactive, err := inputs.IsInteractive() + interactive, err := inputs.EnvInteractive.Get() if err != nil { return Terminal{}, err } colors := interactive if colors { - isColored, err := inputs.IsNoColorEnabled() + isColored, err := inputs.EnvNoColor.Get() if err != nil { return Terminal{}, err }