lockbox

password manager
Log | Files | Refs | README | LICENSE

commit 0c8a8a7be66adccfe1955eb9086d570ebf1b1762
parent d24f7fadd4ec1c907cbf8ceb741d9c82338f6506
Author: Sean Enck <sean@ttypty.com>
Date:   Tue, 25 Jul 2023 20:06:26 -0400

system split to inputs, platform, other

Diffstat:
Minternal/backend/actions.go | 5++---
Minternal/backend/hooks.go | 3+--
Minternal/inputs/env.go | 56+++++++++++++++++++++++++++++++++-----------------------
Minternal/inputs/env_test.go | 18++++++++++++++++++
Minternal/inputs/json.go | 4+---
Minternal/inputs/totp.go | 4+---
Minternal/platform/clipboard.go | 3+--
Dinternal/system/env.go | 53-----------------------------------------------------
Dinternal/system/env_test.go | 54------------------------------------------------------
Minternal/totp/core.go | 5++---
10 files changed, 59 insertions(+), 146 deletions(-)

diff --git a/internal/backend/actions.go b/internal/backend/actions.go @@ -8,7 +8,6 @@ import ( "time" "github.com/enckse/lockbox/internal/inputs" - "github.com/enckse/lockbox/internal/system" "github.com/tobischo/gokeepasslib/v3" "github.com/tobischo/gokeepasslib/v3/wrappers" ) @@ -22,7 +21,7 @@ func (t *Transaction) act(cb action) error { return err } k := string(key) - file := system.EnvironOrDefault(inputs.KeyFileEnv, "") + file := inputs.EnvironOrDefault(inputs.KeyFileEnv, "") if !t.exists { if err := create(t.file, k, file); err != nil { return err @@ -164,7 +163,7 @@ func (t *Transaction) Move(src QueryEntity, dst string) error { if strings.TrimSpace(src.Value) == "" { return errors.New("empty secret not allowed") } - mod := system.EnvironOrDefault(inputs.ModTimeEnv, "") + mod := inputs.EnvironOrDefault(inputs.ModTimeEnv, "") modTime := time.Now() if mod != "" { p, err := time.Parse(inputs.ModTimeFormat, mod) diff --git a/internal/backend/hooks.go b/internal/backend/hooks.go @@ -10,7 +10,6 @@ import ( "github.com/enckse/lockbox/internal/inputs" "github.com/enckse/lockbox/internal/platform" - "github.com/enckse/lockbox/internal/system" ) // NewHook will create a new hook type @@ -18,7 +17,7 @@ func NewHook(path string, a ActionMode) (Hook, error) { if strings.TrimSpace(path) == "" { return Hook{}, errors.New("empty path is not allowed for hooks") } - dir := system.EnvironOrDefault(inputs.HookDirEnv, "") + dir := inputs.EnvironOrDefault(inputs.HookDirEnv, "") if dir == "" { return Hook{enabled: false}, nil } diff --git a/internal/inputs/env.go b/internal/inputs/env.go @@ -12,11 +12,12 @@ import ( "strings" "time" - "github.com/enckse/lockbox/internal/system" "mvdan.cc/sh/v3/shell" ) const ( + yes = "yes" + no = "no" prefixKey = "LOCKBOX_" noClipEnv = prefixKey + "NOCLIP" noColorEnv = prefixKey + "NOCOLOR" @@ -72,7 +73,7 @@ const ( hashJSONLengthEnv = JSONDataOutputEnv + "_HASH_LENGTH" ) -var isYesNoArgs = []string{system.Yes, system.No} +var isYesNoArgs = []string{yes, no} type ( environmentOutput struct { @@ -206,20 +207,6 @@ func getKey(keyMode, name string) ([]byte, error) { return []byte(strings.TrimSpace(string(data))), nil } -func isYesNoEnv(defaultValue bool, envKey string) (bool, error) { - read := system.EnvironValue(envKey) - switch read { - case system.NoValue: - return false, nil - case system.YesValue: - return true, nil - case system.EmptyValue: - return defaultValue, nil - } - - return false, fmt.Errorf("invalid yes/no env value for %s", envKey) -} - // IsClipOSC52 indicates if OSC52 mode is enabled func IsClipOSC52() (bool, error) { return isYesNoEnv(false, clipOSC52Env) @@ -252,7 +239,7 @@ func IsInteractive() (bool, error) { // TOTPToken gets the name of the totp special case tokens func TOTPToken() string { - return system.EnvironOrDefault(fieldTOTPEnv, defaultTOTPField) + return EnvironOrDefault(fieldTOTPEnv, defaultTOTPField) } func (o environmentOutput) formatEnvironmentVariable(required bool, name, val, desc string, allowed []string) string { @@ -284,10 +271,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, system.No, "disable clipboard operations", isYesNoArgs)) - results = append(results, e.formatEnvironmentVariable(false, noColorEnv, system.No, "disable terminal colors", isYesNoArgs)) - results = append(results, e.formatEnvironmentVariable(false, interactiveEnv, system.Yes, "enable interactive mode", isYesNoArgs)) - results = append(results, e.formatEnvironmentVariable(false, readOnlyEnv, system.No, "operate in readonly mode", isYesNoArgs)) + 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, 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"})) @@ -296,12 +283,35 @@ 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, clipMaxEnv, fmt.Sprintf("%d", defaultMaxClipboard), "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, system.No, "disable TOTP integrations", isYesNoArgs)) + results = append(results, e.formatEnvironmentVariable(false, noTOTPEnv, 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, system.No, "enable OSC52 clipboard mode", isYesNoArgs)) + results = append(results, e.formatEnvironmentVariable(false, clipOSC52Env, 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)})) results = append(results, e.formatEnvironmentVariable(false, hashJSONLengthEnv, fmt.Sprintf("%d", defaultHashLength), fmt.Sprintf("maximum hash length the JSON output should contain\nwhen '%s' mode is set for JSON output", JSONDataOutputHash), []string{"integer"})) return results } + +// EnvironOrDefault will get the environment value OR default if env is not set. +func EnvironOrDefault(envKey, defaultValue string) string { + val := os.Getenv(envKey) + if strings.TrimSpace(val) == "" { + return defaultValue + } + return val +} + +func isYesNoEnv(defaultValue bool, envKey string) (bool, error) { + read := strings.ToLower(strings.TrimSpace(os.Getenv(envKey))) + switch read { + case no: + return false, nil + case yes: + return true, nil + case "": + return defaultValue, nil + } + + return false, fmt.Errorf("invalid yes/no env value for %s", envKey) +} diff --git a/internal/inputs/env_test.go b/internal/inputs/env_test.go @@ -198,3 +198,21 @@ func TestGetHashLength(t *testing.T) { t.Errorf("invalid err: %v", err) } } + +func TestEnvDefault(t *testing.T) { + os.Clearenv() + val := inputs.EnvironOrDefault("TEST", "value") + if val != "value" { + t.Error("invalid read") + } + os.Setenv("TEST", " ") + val = inputs.EnvironOrDefault("TEST", "value") + if val != "value" { + t.Error("invalid read") + } + os.Setenv("TEST", " a") + val = inputs.EnvironOrDefault("TEST", "value") + if val != " a" { + t.Error("invalid read") + } +} diff --git a/internal/inputs/json.go b/internal/inputs/json.go @@ -4,8 +4,6 @@ package inputs import ( "fmt" "strings" - - "github.com/enckse/lockbox/internal/system" ) const ( @@ -24,7 +22,7 @@ type ( // ParseJSONOutput handles detecting the JSON output mode func ParseJSONOutput() (JSONOutputMode, error) { - val := strings.ToLower(strings.TrimSpace(system.EnvironOrDefault(JSONDataOutputEnv, string(JSONDataOutputHash)))) + val := strings.ToLower(strings.TrimSpace(EnvironOrDefault(JSONDataOutputEnv, string(JSONDataOutputHash)))) switch JSONOutputMode(val) { case JSONDataOutputHash: return JSONDataOutputHash, nil diff --git a/internal/inputs/totp.go b/internal/inputs/totp.go @@ -5,8 +5,6 @@ import ( "fmt" "net/url" "strings" - - "github.com/enckse/lockbox/internal/system" ) const ( @@ -19,7 +17,7 @@ func FormatTOTP(value string) string { if strings.HasPrefix(value, otpAuth) { return value } - override := system.EnvironOrDefault(formatTOTPEnv, "") + override := EnvironOrDefault(formatTOTPEnv, "") if override != "" { return fmt.Sprintf(override, value) } diff --git a/internal/platform/clipboard.go b/internal/platform/clipboard.go @@ -10,7 +10,6 @@ import ( osc "github.com/aymanbagabas/go-osc52" "github.com/enckse/lockbox/internal/inputs" - "github.com/enckse/lockbox/internal/system" ) type ( @@ -32,7 +31,7 @@ func newClipboard(copying, pasting []string) (Clipboard, error) { } func overrideCommand(v string) ([]string, error) { - value := system.EnvironOrDefault(v, "") + value := inputs.EnvironOrDefault(v, "") if strings.TrimSpace(value) == "" { return nil, nil } diff --git a/internal/system/env.go b/internal/system/env.go @@ -1,53 +0,0 @@ -// Package system handles simple environment variable processing -package system - -import ( - "os" - "strings" -) - -const ( - // Yes is the string expected for yes values - Yes = "yes" - // No is the string expected for no values - No = "no" -) - -type ( - // ReadValue is the output of reading a known bool/yes/no - ReadValue uint -) - -const ( - // UnknownValue indicates an unknown value was read - UnknownValue ReadValue = iota - // YesValue means yes was set - YesValue - // NoValue means no was set - NoValue - // EmptyValue means that the value was not set (empty string) - EmptyValue -) - -// EnvironOrDefault will get the environment value OR default if env is not set. -func EnvironOrDefault(envKey, defaultValue string) string { - val := os.Getenv(envKey) - if strings.TrimSpace(val) == "" { - return defaultValue - } - return val -} - -// EnvironValue read a simple yes/no from an environment value -func EnvironValue(envKey string) ReadValue { - value := strings.ToLower(strings.TrimSpace(os.Getenv(envKey))) - switch value { - case No: - return NoValue - case Yes: - return YesValue - case "": - return EmptyValue - } - return UnknownValue -} diff --git a/internal/system/env_test.go b/internal/system/env_test.go @@ -1,54 +0,0 @@ -package system_test - -import ( - "os" - "testing" - - "github.com/enckse/lockbox/internal/system" -) - -func TestEnvDefault(t *testing.T) { - os.Clearenv() - val := system.EnvironOrDefault("TEST", "value") - if val != "value" { - t.Error("invalid read") - } - os.Setenv("TEST", " ") - val = system.EnvironOrDefault("TEST", "value") - if val != "value" { - t.Error("invalid read") - } - os.Setenv("TEST", " a") - val = system.EnvironOrDefault("TEST", "value") - if val != " a" { - t.Error("invalid read") - } -} - -func TestReadValue(t *testing.T) { - os.Clearenv() - val := system.EnvironValue("test") - if val != system.EmptyValue { - t.Error("bad read") - } - os.Setenv("TEST", "a") - val = system.EnvironValue("TEST") - if val != system.UnknownValue { - t.Error("bad read") - } - os.Setenv("TEST", " YeS ") - val = system.EnvironValue("TEST") - if val != system.YesValue { - t.Error("bad read") - } - os.Setenv("TEST", " NO ") - val = system.EnvironValue("TEST") - if val != system.NoValue { - t.Error("bad read") - } - os.Setenv("TEST", "FALSESSS") - val = system.EnvironValue("TEST") - if val != system.UnknownValue { - t.Error("bad read") - } -} diff --git a/internal/totp/core.go b/internal/totp/core.go @@ -14,7 +14,6 @@ import ( "github.com/enckse/lockbox/internal/backend" "github.com/enckse/lockbox/internal/inputs" "github.com/enckse/lockbox/internal/platform" - "github.com/enckse/lockbox/internal/system" coreotp "github.com/pquerna/otp" otp "github.com/pquerna/otp/totp" ) @@ -84,7 +83,7 @@ func clear() { } func colorWhenRules() ([]inputs.ColorWindow, error) { - envTime := system.EnvironOrDefault(inputs.ColorBetweenEnv, inputs.TOTPDefaultBetween) + envTime := inputs.EnvironOrDefault(inputs.ColorBetweenEnv, inputs.TOTPDefaultBetween) if envTime == inputs.TOTPDefaultBetween { return inputs.TOTPDefaultColorWindow, nil } @@ -158,7 +157,7 @@ func (args *Arguments) display(opts Options) error { if err != nil { return err } - runString := system.EnvironOrDefault(inputs.MaxTOTPTime, inputs.MaxTOTPTimeDefault) + runString := inputs.EnvironOrDefault(inputs.MaxTOTPTime, inputs.MaxTOTPTimeDefault) runFor, err := strconv.Atoi(runString) if err != nil { return err