lockbox

password manager
Log | Files | Refs | README | LICENSE

commit 0778bd3edf758f173104d02d889fcad17b044ee5
parent 802341a8fb8d398e72d847c910a2cbf296e28ed7
Author: Sean Enck <sean@ttypty.com>
Date:   Wed, 26 Jul 2023 20:59:23 -0400

formatting for env variables is now inline with definitions

Diffstat:
Minternal/app/totp.go | 2+-
Minternal/inputs/env.go | 50+++++++++++++++++++++++++++++++++++++++++++-------
Minternal/inputs/vars.go | 106++++++++++++++++++++++++++++---------------------------------------------------
Minternal/inputs/vars_test.go | 2+-
Minternal/platform/clipboard.go | 2+-
5 files changed, 84 insertions(+), 78 deletions(-)

diff --git a/internal/app/totp.go b/internal/app/totp.go @@ -81,7 +81,7 @@ func clear() { } func colorWhenRules() ([]inputs.ColorWindow, error) { - envTime := inputs.EnvColorBetween.Get() + envTime := inputs.EnvTOTPColorBetween.Get() if envTime == inputs.TOTPDefaultBetween { return inputs.TOTPDefaultColorWindow, nil } diff --git a/internal/inputs/env.go b/internal/inputs/env.go @@ -23,16 +23,18 @@ const ( WindowsLinuxPlatform = "wsl" ) -var ( - isYesNoArgs = []string{yes, no} - intArgs = []string{"integer"} -) - type ( + // JSONOutputMode is the output mode definition + JSONOutputMode string + environmentOutput struct { + showValues bool + } // SystemPlatform represents the platform lockbox is running on. SystemPlatform string environmentBase struct { - key string + key string + required bool + desc string } // EnvironmentInt are environment settings that are integers EnvironmentInt struct { @@ -51,6 +53,7 @@ type ( environmentBase canDefault bool defaultValue string + allowed []string } // EnvironmentCommand are settings that are parsed as shell commands EnvironmentCommand struct { @@ -59,7 +62,12 @@ type ( // EnvironmentFormatter allows for sending a string into a get request EnvironmentFormatter struct { environmentBase - fxn func(string, string) string + allowed string + fxn func(string, string) string + } + printer interface { + values() (string, []string) + self() environmentBase } ) @@ -159,3 +167,31 @@ func (e environmentBase) Set(value string) { func (e EnvironmentFormatter) Get(value string) string { return e.fxn(e.key, value) } + +func (e EnvironmentString) values() (string, []string) { + return e.defaultValue, e.allowed +} + +func (e environmentBase) self() environmentBase { + return e +} + +func (e EnvironmentBool) values() (string, []string) { + val := no + if e.defaultValue { + val = yes + } + return val, []string{yes, no} +} + +func (e EnvironmentInt) values() (string, []string) { + return fmt.Sprintf("%d", e.defaultValue), []string{"integer"} +} + +func (e EnvironmentFormatter) values() (string, []string) { + return strings.ReplaceAll(strings.ReplaceAll(EnvFormatTOTP.Get("%s"), "%25s", "%s"), "&", " \\\n &"), []string{e.allowed} +} + +func (e EnvironmentCommand) values() (string, []string) { + return detectedValue, []string{commandArgsExample} +} diff --git a/internal/inputs/vars.go b/internal/inputs/vars.go @@ -18,7 +18,6 @@ const ( clipBaseEnv = prefixKey + "CLIP_" plainKeyMode = "plaintext" commandKeyMode = "command" - defaultTOTPField = "totp" commandArgsExample = "[cmd args...]" detectedValue = "(detected)" // ModTimeFormat is the expected modtime format @@ -32,56 +31,48 @@ const ( ) var ( - // EnvClipboardMax gets the maximum clipboard time - EnvClipboardMax = EnvironmentInt{environmentBase: environmentBase{key: clipBaseEnv + "MAX"}, shortDesc: "clipboard max time", allowZero: false, defaultValue: 45} + // EnvClipMax gets the maximum clipboard time + EnvClipMax = EnvironmentInt{environmentBase: environmentBase{key: clipBaseEnv + "MAX", desc: "override the amount of time before totp clears the clipboard (e.g. 10),\nmust be an integer"}, shortDesc: "clipboard max time", allowZero: false, defaultValue: 45} // EnvHashLength handles the hashing output length - EnvHashLength = EnvironmentInt{environmentBase: environmentBase{key: EnvJSONDataOutput.key + "_HASH_LENGTH"}, shortDesc: "hash length", allowZero: true, defaultValue: 0} + EnvHashLength = EnvironmentInt{environmentBase: environmentBase{key: EnvJSONDataOutput.key + "_HASH_LENGTH", desc: fmt.Sprintf("maximum hash length the JSON output should contain\nwhen '%s' mode is set for JSON output", JSONDataOutputHash)}, shortDesc: "hash length", allowZero: true, defaultValue: 0} // EnvClipOSC52 indicates if OSC52 clipboard mode is enabled - EnvClipOSC52 = EnvironmentBool{environmentBase: environmentBase{key: clipBaseEnv + "OSC52"}, defaultValue: false} + EnvClipOSC52 = EnvironmentBool{environmentBase: environmentBase{key: clipBaseEnv + "OSC52", desc: "enable OSC52 clipboard mode"}, defaultValue: false} // EnvNoTOTP indicates if TOTP is disabled - EnvNoTOTP = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "NOTOTP"}, defaultValue: false} + EnvNoTOTP = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "NOTOTP", desc: "disable TOTP integrations"}, defaultValue: false} // EnvReadOnly indicates if in read-only mode - EnvReadOnly = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "READONLY"}, defaultValue: false} + EnvReadOnly = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "READONLY", desc: "operate in readonly mode"}, defaultValue: false} // EnvNoClip indicates clipboard functionality is off - EnvNoClip = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "NOCLIP"}, defaultValue: false} + EnvNoClip = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "NOCLIP", desc: "disable clipboard operations"}, defaultValue: false} // EnvNoColor indicates if color outputs are disabled - EnvNoColor = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "NOCOLOR"}, defaultValue: false} + EnvNoColor = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "NOCOLOR", desc: "disable terminal colors"}, defaultValue: false} // EnvInteractive indicates if operating in interactive mode - EnvInteractive = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "INTERACTIVE"}, defaultValue: true} + EnvInteractive = EnvironmentBool{environmentBase: environmentBase{key: prefixKey + "INTERACTIVE", desc: "enable interactive mode"}, defaultValue: true} // EnvMaxTOTP is the max TOTP time to run (default) - EnvMaxTOTP = EnvironmentInt{environmentBase: environmentBase{key: EnvTOTPToken.key + "_MAX"}, shortDesc: "max totp time", allowZero: false, defaultValue: 120} + EnvMaxTOTP = EnvironmentInt{environmentBase: environmentBase{key: EnvTOTPToken.key + "_MAX", desc: "time, in seconds, in which to show a TOTP token before automatically exiting"}, shortDesc: "max totp time", allowZero: false, defaultValue: 120} // EnvTOTPToken is the leaf token to use to store TOTP tokens - EnvTOTPToken = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "TOTP"}, canDefault: true, defaultValue: "totp"} + EnvTOTPToken = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "TOTP", desc: "attribute name to store TOTP tokens within the database"}, allowed: []string{"string"}, canDefault: true, defaultValue: "totp"} // EnvPlatform is the platform that the application is running on - EnvPlatform = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "PLATFORM"}, canDefault: false} + EnvPlatform = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "PLATFORM", desc: "override the detected platform"}, defaultValue: detectedValue, allowed: PlatformSet(), canDefault: false} // EnvStore is the location of the keepass file/store - EnvStore = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "STORE"}, canDefault: false} + EnvStore = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "STORE", required: true, desc: "directory to the database file"}, canDefault: false, allowed: []string{"file"}} // EnvHookDir is the directory of hooks to execute - EnvHookDir = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "HOOKDIR"}, canDefault: true, defaultValue: ""} + EnvHookDir = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "HOOKDIR", desc: "the path to hooks to execute on actions against the database"}, allowed: []string{"directory"}, canDefault: true, defaultValue: ""} // EnvClipCopy allows overriding the clipboard copy command - EnvClipCopy = EnvironmentCommand{environmentBase: environmentBase{key: clipBaseEnv + "COPY"}} + EnvClipCopy = EnvironmentCommand{environmentBase: environmentBase{key: clipBaseEnv + "COPY", desc: "override the detected platform copy command"}} // EnvClipPaste allows overriding the clipboard paste command - EnvClipPaste = EnvironmentCommand{environmentBase: environmentBase{key: clipBaseEnv + "PASTE"}} - // EnvColorBetween handles terminal coloring for TOTP windows (seconds) - EnvColorBetween = EnvironmentString{environmentBase: environmentBase{key: EnvTOTPToken.key + "_BETWEEN"}, canDefault: true, defaultValue: TOTPDefaultBetween} + EnvClipPaste = EnvironmentCommand{environmentBase: environmentBase{key: clipBaseEnv + "PASTE", desc: "override the detected platform paste command"}} + // EnvTOTPColorBetween handles terminal coloring for TOTP windows (seconds) + EnvTOTPColorBetween = EnvironmentString{environmentBase: environmentBase{key: EnvTOTPToken.key + "_BETWEEN", desc: "override when to set totp generated outputs to different colors, must be a\nlist of one (or more) rules where a semicolon delimits the start and end\nsecond (0-60 for each)"}, canDefault: true, defaultValue: TOTPDefaultBetween, allowed: []string{"start:end,start:end,start:end..."}} // EnvKeyFile is an OPTIONAL keyfile for the database - EnvKeyFile = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "KEYFILE"}, canDefault: true, defaultValue: ""} - envKeyMode = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "KEYMODE"}, canDefault: true, defaultValue: commandKeyMode} - envKey = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "KEY"}, canDefault: false} + EnvKeyFile = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "KEYFILE", desc: "additional keyfile to access/protect the database"}, allowed: []string{"keyfile"}, canDefault: true, defaultValue: ""} // EnvModTime is modtime override ability for entries - EnvModTime = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "SET_MODTIME"}, canDefault: true, defaultValue: ""} + EnvModTime = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "SET_MODTIME", desc: fmt.Sprintf("input modification time to set for the entry\n(expected format: %s)", ModTimeFormat)}, canDefault: true, defaultValue: "", allowed: []string{"modtime"}} // EnvJSONDataOutput controls how JSON is output in the 'data' field - EnvJSONDataOutput = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "JSON_DATA_OUTPUT"}, canDefault: true, defaultValue: string(JSONDataOutputHash)} + EnvJSONDataOutput = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "JSON_DATA_OUTPUT", desc: fmt.Sprintf("changes what the data field in JSON outputs will contain\nuse '%s' with CAUTION", JSONDataOutputRaw)}, canDefault: true, defaultValue: string(JSONDataOutputHash), allowed: []string{string(JSONDataOutputRaw), string(JSONDataOutputHash), string(JSONDataOutputBlank)}} // EnvFormatTOTP supports formatting the TOTP tokens for generation of tokens - EnvFormatTOTP = EnvironmentFormatter{environmentBase: environmentBase{key: EnvTOTPToken.key + "_FORMAT"}, fxn: formatterTOTP} -) - -type ( - // JSONOutputMode is the output mode definition - JSONOutputMode string - environmentOutput struct { - showValues bool - } + EnvFormatTOTP = EnvironmentFormatter{environmentBase: environmentBase{key: EnvTOTPToken.key + "_FORMAT", desc: "override the otpauth url used to store totp tokens. It must have ONE format\nstring ('%s') to insert the totp base code"}, fxn: formatterTOTP, allowed: "otpauth//url/%s/args..."} + envKeyMode = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "KEYMODE", required: true, desc: "how to retrieve the database store password"}, allowed: []string{commandKeyMode, plainKeyMode}, canDefault: true, defaultValue: commandKeyMode} + envKey = EnvironmentString{environmentBase: environmentBase{key: prefixKey + "KEY", required: true, desc: fmt.Sprintf("the database key ('%s' mode) or command to run ('%s' mode)\nto retrieve the database password", plainKeyMode, commandKeyMode)}, allowed: []string{commandArgsExample, "password"}, canDefault: false} ) // GetReKey will get the rekey environment settings @@ -156,44 +147,23 @@ func GetKey() ([]byte, error) { return b, nil } -func (o environmentOutput) formatEnvironmentVariable(required bool, name, val, desc string, allowed []string) string { - value := val - if o.showValues { - value = os.Getenv(name) - } - if len(value) == 0 { - value = "(unset)" - } - description := strings.ReplaceAll(desc, "\n", "\n ") - return fmt.Sprintf("\n%s\n %s\n\n required: %t\n value: %s\n options: %s\n", name, description, required, value, strings.Join(allowed, "|")) -} - // ListEnvironmentVariables will print information about env variables and potential/set values func ListEnvironmentVariables(showValues bool) []string { - e := environmentOutput{showValues: showValues} + out := environmentOutput{showValues: showValues} var results []string - results = append(results, e.formatEnvironmentVariable(true, EnvStore.key, "", "directory to the database file", []string{"file"})) - results = append(results, e.formatEnvironmentVariable(true, envKeyMode.key, commandKeyMode, "how to retrieve the database store password", []string{commandKeyMode, plainKeyMode})) - results = append(results, e.formatEnvironmentVariable(true, envKey.key, "", 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, 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, EnvTOTPToken.key, defaultTOTPField, "attribute name to store TOTP tokens within the database", []string{"string"})) - results = append(results, e.formatEnvironmentVariable(false, EnvFormatTOTP.key, strings.ReplaceAll(strings.ReplaceAll(EnvFormatTOTP.Get("%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, EnvMaxTOTP.key, fmt.Sprintf("%d", EnvMaxTOTP.defaultValue), "time, in seconds, in which to show a TOTP token before automatically exiting", intArgs)) - results = append(results, e.formatEnvironmentVariable(false, EnvColorBetween.key, TOTPDefaultBetween, "override when to set totp generated outputs to different colors, must be a\nlist of one (or more) rules where a semicolon delimits the start and end\nsecond (0-60 for each)", []string{"start:end,start:end,start:end..."})) - results = append(results, e.formatEnvironmentVariable(false, EnvClipPaste.key, detectedValue, "override the detected platform paste command", []string{commandArgsExample})) - results = append(results, e.formatEnvironmentVariable(false, EnvClipCopy.key, 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", intArgs)) - results = append(results, e.formatEnvironmentVariable(false, EnvPlatform.key, detectedValue, "override the detected platform", PlatformSet())) - results = append(results, e.formatEnvironmentVariable(false, EnvNoTOTP.key, no, "disable TOTP integrations", isYesNoArgs)) - results = append(results, e.formatEnvironmentVariable(false, EnvHookDir.key, "", "the path to hooks to execute on actions against the database", []string{"directory"})) - results = append(results, e.formatEnvironmentVariable(false, EnvClipOSC52.key, no, "enable OSC52 clipboard mode", isYesNoArgs)) - results = append(results, e.formatEnvironmentVariable(false, EnvKeyFile.key, "", "additional keyfile to access/protect the database", []string{"keyfile"})) - results = append(results, e.formatEnvironmentVariable(false, EnvModTime.key, ModTimeFormat, fmt.Sprintf("input modification time to set for the entry\n(expected format: %s)", ModTimeFormat), []string{"modtime"})) - results = append(results, e.formatEnvironmentVariable(false, EnvJSONDataOutput.key, 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, EnvHashLength.key, fmt.Sprintf("%d", EnvHashLength.defaultValue), fmt.Sprintf("maximum hash length the JSON output should contain\nwhen '%s' mode is set for JSON output", JSONDataOutputHash), intArgs)) + for _, item := range []printer{EnvStore, envKeyMode, envKey, EnvNoClip, EnvNoColor, EnvInteractive, EnvReadOnly, EnvTOTPToken, EnvFormatTOTP, EnvMaxTOTP, EnvTOTPColorBetween, EnvClipPaste, EnvClipCopy, EnvClipMax, EnvPlatform, EnvNoTOTP, EnvHookDir, EnvClipOSC52, EnvKeyFile, EnvModTime, EnvJSONDataOutput, EnvHashLength} { + env := item.self() + value, allow := item.values() + if out.showValues { + value = os.Getenv(env.key) + } + if len(value) == 0 { + value = "(unset)" + } + description := strings.ReplaceAll(env.desc, "\n", "\n ") + text := fmt.Sprintf("\n%s\n %s\n\n required: %t\n value: %s\n options: %s\n", env.key, description, env.required, value, strings.Join(allow, "|")) + results = append(results, text) + } return results } diff --git a/internal/inputs/vars_test.go b/internal/inputs/vars_test.go @@ -195,7 +195,7 @@ func TestParseJSONMode(t *testing.T) { } func TestClipboardMax(t *testing.T) { - checkInt(inputs.EnvClipboardMax, "LOCKBOX_CLIP_MAX", "clipboard max time", 45, false, t) + checkInt(inputs.EnvClipMax, "LOCKBOX_CLIP_MAX", "clipboard max time", 45, false, t) } func TestHashLength(t *testing.T) { diff --git a/internal/platform/clipboard.go b/internal/platform/clipboard.go @@ -22,7 +22,7 @@ type ( ) func newClipboard(copying, pasting []string) (Clipboard, error) { - max, err := inputs.EnvClipboardMax.Get() + max, err := inputs.EnvClipMax.Get() if err != nil { return Clipboard{}, err }