lockbox

password manager
Log | Files | Refs | README | LICENSE

commit 71a27cf6a0348f2c7b29c4cc9689458d891326c5
parent 04f49dbb2e48823cd56d657e646ed04d2706d11f
Author: Sean Enck <sean@ttypty.com>
Date:   Sun,  3 Sep 2023 16:50:22 -0400

split detail and wordwrap externally

Diffstat:
Mgo.mod | 3+++
Mgo.sum | 7+++++++
Minternal/app/completions.go | 6+++---
Minternal/app/core.go | 77++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Minternal/app/core_test.go | 10+---------
Rinternal/app/doc/bash -> internal/app/doc/bash.sh | 0
Ainternal/app/doc/clipboard.txt | 3+++
Ainternal/app/doc/completions.txt | 5+++++
Ainternal/app/doc/database.txt | 8++++++++
Dinternal/app/doc/details | 57---------------------------------------------------------
Ainternal/app/doc/environment.txt | 1+
Ainternal/app/doc/globs.txt | 16++++++++++++++++
Ainternal/app/doc/rekey.txt | 7+++++++
Rinternal/app/doc/shell -> internal/app/doc/shell.sh | 0
Ainternal/app/doc/totp.txt | 3+++
Rinternal/app/doc/zsh -> internal/app/doc/zsh.sh | 0
16 files changed, 123 insertions(+), 80 deletions(-)

diff --git a/go.mod b/go.mod @@ -5,6 +5,7 @@ go 1.19 require ( github.com/aymanbagabas/go-osc52 v1.2.2 github.com/hashicorp/go-envparse v0.1.0 + github.com/muesli/reflow v0.3.0 github.com/pquerna/otp v1.4.0 github.com/tobischo/gokeepasslib/v3 v3.5.1 mvdan.cc/sh/v3 v3.7.0 @@ -14,6 +15,8 @@ require ( github.com/aead/argon2 v0.0.0-20180111183520-a87724528b07 // indirect github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/boombuler/barcode v1.0.1 // indirect + github.com/mattn/go-runewidth v0.0.12 // indirect + github.com/rivo/uniseg v0.2.0 // indirect golang.org/x/crypto v0.12.0 // indirect golang.org/x/sys v0.11.0 // indirect ) diff --git a/go.sum b/go.sum @@ -15,10 +15,17 @@ github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdm github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWzZ/PDqmVuf/FKHARG5EMid/tl7cv54Sw/QRVY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/internal/app/completions.go b/internal/app/completions.go @@ -161,17 +161,17 @@ export %s=<unknown> CompletionEnv: fmt.Sprintf("$%s", config.EnvironmentCompletionKey), } - using, err := readDoc("zsh") + using, err := readDoc("zsh.sh") if err != nil { return nil, err } if isBash { - using, err = readDoc("bash") + using, err = readDoc("bash.sh") if err != nil { return nil, err } } - shellScript, err := readDoc("shell") + shellScript, err := readDoc("shell.sh") if err != nil { return nil, err } diff --git a/internal/app/core.go b/internal/app/core.go @@ -4,6 +4,7 @@ package app import ( "bytes" "embed" + "errors" "fmt" "io" "os" @@ -15,6 +16,7 @@ import ( "github.com/enckse/lockbox/internal/backend" "github.com/enckse/lockbox/internal/config" "github.com/enckse/lockbox/internal/platform" + "github.com/muesli/reflow/wordwrap" ) const ( @@ -71,6 +73,8 @@ const ( JSONCommand = "json" // ZshCommand is the command to generate zsh completions ZshCommand = "zsh" + docDir = "doc" + textFile = ".txt" ) //go:embed doc/* @@ -207,14 +211,6 @@ func Usage(verbose bool, exe string) ([]string, error) { usage := []string{fmt.Sprintf("%s usage:", exe)} if verbose { results = append(results, "") - doc, err := readDoc("details") - if err != nil { - return nil, err - } - t, err := template.New("d").Parse(doc) - if err != nil { - return nil, err - } document := Documentation{ Executable: filepath.Base(exe), MoveCommand: MoveCommand, @@ -226,10 +222,32 @@ func Usage(verbose bool, exe string) ([]string, error) { document.ReKey.Key = setDocFlag(config.ReKeyKeyFlag) document.ReKey.KeyMode = setDocFlag(config.ReKeyKeyModeFlag) document.ReKey.KeyFile = setDocFlag(config.ReKeyKeyModeFlag) - var buf bytes.Buffer - if err := t.Execute(&buf, document); err != nil { + files, err := docs.ReadDir(docDir) + if err != nil { return nil, err } + var buf bytes.Buffer + var env string + for _, f := range files { + n := f.Name() + if !strings.HasSuffix(n, textFile) { + continue + } + header := fmt.Sprintf("[%s]", strings.TrimSuffix(filepath.Base(n), textFile)) + s, err := processDoc(header, n, document) + if err != nil { + return nil, err + } + if header == "[environment]" { + env = s + } else { + buf.WriteString(s) + } + } + if env == "" { + return nil, errors.New("no environment header configured") + } + buf.WriteString(env) results = append(results, strings.Split(strings.TrimSpace(buf.String()), "\n")...) results = append(results, "") results = append(results, config.ListEnvironmentVariables()...) @@ -237,12 +255,49 @@ func Usage(verbose bool, exe string) ([]string, error) { return append(usage, results...), nil } +func processDoc(header, file string, doc Documentation) (string, error) { + b, err := readDoc(file) + if err != nil { + return "", err + } + t, err := template.New("d").Parse(string(b)) + if err != nil { + return "", err + } + var buf bytes.Buffer + if err := t.Execute(&buf, doc); err != nil { + return "", err + } + var sections []string + var cur []string + for _, line := range strings.Split(strings.TrimSpace(buf.String()), "\n") { + trimmed := strings.TrimSpace(line) + if trimmed == "" { + if len(cur) > 0 { + sections = append(sections, strings.Join(cur, " ")) + cur = []string{} + } + continue + } + cur = append(cur, line) + } + if len(cur) > 0 { + sections = append(sections, strings.Join(cur, " ")) + } + var out bytes.Buffer + fmt.Fprintf(&out, "%s\n", header) + for _, s := range sections { + fmt.Fprintf(&out, "%s\n\n", wordwrap.String(s, 80)) + } + return out.String(), nil +} + func setDocFlag(f string) string { return fmt.Sprintf("-%s=", f) } func readDoc(doc string) (string, error) { - b, err := docs.ReadFile(filepath.Join("doc", doc)) + b, err := docs.ReadFile(filepath.Join(docDir, doc)) if err != nil { return "", err } diff --git a/internal/app/core_test.go b/internal/app/core_test.go @@ -1,7 +1,6 @@ package app_test import ( - "strings" "testing" "github.com/enckse/lockbox/internal/app" @@ -13,14 +12,7 @@ func TestUsage(t *testing.T) { t.Errorf("invalid usage, out of date? %d", len(u)) } u, _ = app.Usage(true, "lb") - if len(u) != 109 { + if len(u) != 108 { t.Errorf("invalid verbose usage, out of date? %d", len(u)) } - for _, usage := range u { - for _, l := range strings.Split(usage, "\n") { - if len(l) > 79 { - t.Errorf("usage line > 79 (%d), line: %s", len(l), l) - } - } - } } diff --git a/internal/app/doc/bash b/internal/app/doc/bash.sh diff --git a/internal/app/doc/clipboard.txt b/internal/app/doc/clipboard.txt @@ -0,0 +1,3 @@ +By default clipboard commands are detected via determing the platform and +utilizing default commands to interact with (copy to/paste to) the clipboard. +These settings can be overriden via environment variables. diff --git a/internal/app/doc/completions.txt b/internal/app/doc/completions.txt @@ -0,0 +1,5 @@ +Completions are available for certain shells and, by default, assume all +features of `{{ $.Executable }}` are enabled and available. When changing certain environment +flags it may be useful to change the completion profile to more closely match +the restricted command options, run `{{ $.Executable }} <shell> {{ $.ShellHelpCommand }}` for information +on how best to alter completion outputs. diff --git a/internal/app/doc/database.txt b/internal/app/doc/database.txt @@ -0,0 +1,8 @@ +While '{{ $.Executable }}' uses a kdbx file (version 4), it is opinionated about how to store +data within the file. This means '{{ $.Executable }}' should be the only way a user normally +interacts with or changes the underlying database. However as the file is a +normal kdbx file format (e.g. can be opened in tools supporting the format) it +is possible to use the database in those applications, just take caution when +changing it outside of '{{ $.Executable }}' usage. If a database not normally used by '{{ $.Executable }}' is +to be used by '{{ $.Executable }}', try using the various readonly settings to control +interactions. diff --git a/internal/app/doc/details b/internal/app/doc/details @@ -1,57 +0,0 @@ -[database] -While '{{ $.Executable }}' uses a kdbx file (version 4), it is opinionated about how to store -data within the file. This means '{{ $.Executable }}' should be the only way a user normally -interacts with or changes the underlying database. However as the file is a -normal kdbx file format (e.g. can be opened in tools supporting the format) it -is possible to use the database in those applications, just take caution when -changing it outside of '{{ $.Executable }}' usage. If a database not normally used by '{{ $.Executable }}' is -to be used by '{{ $.Executable }}', try using the various readonly settings to control -interactions. - -[globs] -The '{{ $.RemoveCommand }}' and '{{ $.MoveCommand }}' command can handle a simplistic glob if it is at the END -of the path. This allows for bulk-removal of entries at multiple levels. -Confirmation will still be required for removal (matching entries will be -listed). - -For '{{ $.MoveCommand }}' the destination must NOT be an entry but the final destination -location for all matched entries. Overwriting is not allowed by moving -via glob and moving via globs can ONLY be done via leaf level globs. - -Examples: - -{{ $.Executable }} {{ $.RemoveCommand }} path/to/leaf/dir/* - -{{ $.Executable }} {{ $.RemoveCommand }} path/to/* - -{{ $.Executable }} {{ $.MoveCommand }} path/to/* new/path/ - -[clipboard] -By default clipboard commands are detected via determing the platform and -utilizing default commands to interact with (copy to/paste to) the clipboard. -These settings can be overriden via environment variables. - -[totp] -By default '{{ $.Executable }}' tries to use some reasonable defaults to setup/manage oauth -token inputs and displaying of code outputs. Many of these settings can be -changed via environment variables. - -[rekey] -The password store can have the key (and file) changed via the '{{ $.ReKeyCommand }}' -subcommand. This command requires a '{{ $.ReKey.Store }}' value and some combination -of '{{ $.ReKey.Key }}', '{{ $.ReKey.KeyMode }}', and '{{ $.ReKey.KeyFile }}' depending on the new database -credential preferences. The settings correspond to the 'LOCKBOX_' -settings normally used when running `{{ $.Executable }}`. - -Note that is an advanced feature and should be used with caution/backups/etc. - -[completions] -Completions are available for certain shells and, by default, assume all -features of `{{ $.Executable }}` are enabled and available. When changing certain environment -flags it may be useful to change the completion profile to more closely match -the restricted command options, run `{{ $.Executable }} <shell> {{ $.ShellHelpCommand }}` for information -on how best to alter completion outputs. - -[environment variables] - -The following environment variables can alter how '{{ $.Executable }}' works. diff --git a/internal/app/doc/environment.txt b/internal/app/doc/environment.txt @@ -0,0 +1 @@ +The following environment variables can alter how '{{ $.Executable }}' works. diff --git a/internal/app/doc/globs.txt b/internal/app/doc/globs.txt @@ -0,0 +1,16 @@ +The '{{ $.RemoveCommand }}' and '{{ $.MoveCommand }}' command can handle a simplistic glob if it is at the END +of the path. This allows for bulk-removal of entries at multiple levels. +Confirmation will still be required for removal (matching entries will be +listed). + +For '{{ $.MoveCommand }}' the destination must NOT be an entry but the final destination +location for all matched entries. Overwriting is not allowed by moving +via glob and moving via globs can ONLY be done via leaf level globs. + +Examples: + +{{ $.Executable }} {{ $.RemoveCommand }} path/to/leaf/dir/* + +{{ $.Executable }} {{ $.RemoveCommand }} path/to/* + +{{ $.Executable }} {{ $.MoveCommand }} path/to/* new/path/ diff --git a/internal/app/doc/rekey.txt b/internal/app/doc/rekey.txt @@ -0,0 +1,7 @@ +The password store can have the key (and file) changed via the '{{ $.ReKeyCommand }}' +subcommand. This command requires that '{{ $.ReKey.Store }}' is set and +a combination of new key settings are configured via '{{ $.ReKey.Key }}', '{{ $.ReKey.KeyMode }}', and '{{ $.ReKey.KeyFile }}' depending on the new database +credential preferences. The settings correspond to the 'LOCKBOX_' +settings normally used when running `{{ $.Executable }}`. + +Note that is an advanced feature and should be used with caution/backups/etc. diff --git a/internal/app/doc/shell b/internal/app/doc/shell.sh diff --git a/internal/app/doc/totp.txt b/internal/app/doc/totp.txt @@ -0,0 +1,3 @@ +By default '{{ $.Executable }}' tries to use some reasonable defaults to setup/manage oauth +token inputs and displaying of code outputs. Many of these settings can be +changed via environment variables. diff --git a/internal/app/doc/zsh b/internal/app/doc/zsh.sh