lockbox

password manager
Log | Files | Refs | README | LICENSE

commit ab81af8a2e2e05221038f5c0db2310027f6c1fcd
parent e586fd8024c1920f8f9cda76284747733aafde04
Author: Sean Enck <sean@ttypty.com>
Date:   Wed,  6 Sep 2023 20:37:37 -0400

use an ansi module for better coloring outputs

Diffstat:
Mgo.mod | 1+
Mgo.sum | 2++
Minternal/app/totp.go | 46+++++++++++++++++++++++++++++++++-------------
Dinternal/platform/terminal.go | 54------------------------------------------------------
Dinternal/platform/terminal_test.go | 66------------------------------------------------------------------
5 files changed, 36 insertions(+), 133 deletions(-)

diff --git a/go.mod b/go.mod @@ -7,6 +7,7 @@ require ( github.com/hashicorp/go-envparse v0.1.0 github.com/pquerna/otp v1.4.0 github.com/tobischo/gokeepasslib/v3 v3.5.1 + mpldr.codes/ansi v1.5.0 mvdan.cc/sh/v3 v3.7.0 ) diff --git a/go.sum b/go.sum @@ -31,5 +31,7 @@ golang.org/x/exp v0.0.0-20230105202349-8879d0199aa3 h1:fJwx88sMf5RXwDwziL0/Mn9Wq golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +mpldr.codes/ansi v1.5.0 h1:jAAtDMwU/DC7OPxmrVFpmM3RrSQDcMeLhuk6BuEoWZc= +mpldr.codes/ansi v1.5.0/go.mod h1:SYuKX0r6nxvySxMxzQX9frQaKLjEqKapjjg17euonMc= mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8= diff --git a/internal/app/totp.go b/internal/app/totp.go @@ -14,6 +14,7 @@ import ( "github.com/enckse/lockbox/internal/platform" coreotp "github.com/pquerna/otp" otp "github.com/pquerna/otp/totp" + "mpldr.codes/ansi" ) var ( @@ -105,10 +106,6 @@ func (args *TOTPArguments) display(opts TOTPOptions) error { if !interactive && clip { return errors.New("clipboard not available in non-interactive mode") } - coloring, err := platform.NewTerminal(platform.Red) - if err != nil { - return err - } entity, err := opts.app.Transaction().Get(backend.NewPath(args.Entry, args.token), backend.SecretValue) if err != nil { return err @@ -159,6 +156,10 @@ func (args *TOTPArguments) display(opts TOTPOptions) error { if err != nil { return err } + allowColor, err := canColor() + if err != nil { + return err + } for { if !first { time.Sleep(500 * time.Millisecond) @@ -180,27 +181,30 @@ func (args *TOTPArguments) display(opts TOTPOptions) error { if err != nil { return err } - startColor := "" - endColor := "" - for _, when := range colorRules { - if left < when.End && left >= when.Start { - startColor = coloring.Start - endColor = coloring.End + isColor := false + if allowColor { + for _, when := range colorRules { + if left < when.End && left >= when.Start { + isColor = true + } } } leftString := fmt.Sprintf("%d", left) if len(leftString) < 2 { leftString = "0" + leftString } - expires := fmt.Sprintf("%s%s (%s)%s", startColor, now.Format("15:04:05"), leftString, endColor) - outputs := []string{expires} + txt := fmt.Sprintf("%s (%s)", now.Format("15:04:05"), leftString) + if isColor { + txt = ansi.Red(txt) + } + outputs := []string{txt} if !clip { outputs = append(outputs, fmt.Sprintf("%s\n %s", args.Entry, code)) if !once { outputs = append(outputs, "-> CTRL+C to exit") } } else { - fmt.Fprintf(writer, "-> %s\n", expires) + fmt.Fprintf(writer, "-> %s\n", txt) return clipboard.CopyTo(code) } if !once { @@ -287,3 +291,19 @@ func NewTOTPArguments(args []string, tokenType string) (*TOTPArguments, error) { } return opts, nil } + +func canColor() (bool, error) { + interactive, err := config.EnvInteractive.Get() + if err != nil { + return false, err + } + colors := interactive + if colors { + isColored, err := config.EnvNoColor.Get() + if err != nil { + return false, err + } + colors = !isColored + } + return colors, nil +} diff --git a/internal/platform/terminal.go b/internal/platform/terminal.go @@ -1,54 +0,0 @@ -// Package platform handles platform-specific operations. -package platform - -import ( - "errors" - - "github.com/enckse/lockbox/internal/config" -) - -const ( - termBeginRed = "\033[1;31m" - termEndRed = "\033[0m" -) - -const ( - // Red will get red terminal coloring. - Red = iota -) - -type ( - // Color are terminal colors for dumb terminal coloring. - Color int -) - -type ( - // Terminal represents terminal coloring information. - Terminal struct { - Start string - End string - } -) - -// NewTerminal will retrieve start/end terminal coloration indicators. -func NewTerminal(color Color) (Terminal, error) { - if color != Red { - return Terminal{}, errors.New("bad color") - } - interactive, err := config.EnvInteractive.Get() - if err != nil { - return Terminal{}, err - } - colors := interactive - if colors { - isColored, err := config.EnvNoColor.Get() - if err != nil { - return Terminal{}, err - } - colors = !isColored - } - if colors { - return Terminal{Start: termBeginRed, End: termEndRed}, nil - } - return Terminal{}, nil -} diff --git a/internal/platform/terminal_test.go b/internal/platform/terminal_test.go @@ -1,66 +0,0 @@ -package platform_test - -import ( - "os" - "testing" - - "github.com/enckse/lockbox/internal/platform" -) - -func TestHasColoring(t *testing.T) { - os.Setenv("LOCKBOX_INTERACTIVE", "yes") - os.Setenv("LOCKBOX_NOCOLOR", "no") - term, err := platform.NewTerminal(platform.Red) - if err != nil { - t.Errorf("color was valid: %v", err) - } - if term.Start != "\033[1;31m" || term.End != "\033[0m" { - t.Error("bad resulting color") - } -} - -func TestBadColor(t *testing.T) { - _, err := platform.NewTerminal(platform.Color(5)) - if err == nil || err.Error() != "bad color" { - t.Errorf("invalid color error: %v", err) - } -} - -func TestNoColoring(t *testing.T) { - os.Setenv("LOCKBOX_INTERACTIVE", "no") - os.Setenv("LOCKBOX_NOCOLOR", "yes") - term, err := platform.NewTerminal(platform.Red) - if err != nil { - t.Errorf("color was valid: %v", err) - } - if term.Start != "" || term.End != "" { - t.Error("should have no color") - } - os.Setenv("LOCKBOX_INTERACTIVE", "yes") - os.Setenv("LOCKBOX_NOCOLOR", "yes") - term, err = platform.NewTerminal(platform.Red) - if err != nil { - t.Errorf("color was valid: %v", err) - } - if term.Start != "" || term.End != "" { - t.Error("should have no color") - } - os.Setenv("LOCKBOX_INTERACTIVE", "no") - os.Setenv("LOCKBOX_NOCOLOR", "no") - term, err = platform.NewTerminal(platform.Red) - if err != nil { - t.Errorf("color was valid: %v", err) - } - if term.Start != "" || term.End != "" { - t.Error("should have no color") - } - os.Setenv("LOCKBOX_INTERACTIVE", "yes") - os.Setenv("LOCKBOX_NOCOLOR", "no") - term, err = platform.NewTerminal(platform.Red) - if err != nil { - t.Errorf("color was valid: %v", err) - } - if term.Start == "" || term.End == "" { - t.Error("should have color") - } -}