lockbox

password manager
Log | Files | Refs | README | LICENSE

commit e80b71e1c96504b4ec04200547b035d6a838834e
parent 468fd7380db2f83537bd4adea8be2b161ca5ee11
Author: Sean Enck <sean@ttypty.com>
Date:   Mon,  2 Jun 2025 21:54:28 -0400

parsing the time window and time window are really config and totp components

Diffstat:
Minternal/app/totp.go | 37++++++++++++++++++++++++++++++++++---
Minternal/app/totp_test.go | 33+++++++++++++++++++++++++++++++++
Minternal/config/core.go | 15+++++++++++----
Minternal/config/vars.go | 2+-
Dinternal/util/time.go | 51---------------------------------------------------
Dinternal/util/time_test.go | 40----------------------------------------
6 files changed, 79 insertions(+), 99 deletions(-)

diff --git a/internal/app/totp.go b/internal/app/totp.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "slices" + "strconv" "strings" "time" @@ -15,7 +16,6 @@ import ( "git.sr.ht/~enckse/lockbox/internal/backend" "git.sr.ht/~enckse/lockbox/internal/config" "git.sr.ht/~enckse/lockbox/internal/platform/clip" - "git.sr.ht/~enckse/lockbox/internal/util" ) var ( @@ -78,12 +78,12 @@ func clearFunc() { fmt.Print("\033[H\033[2J") } -func colorWhenRules() ([]util.TimeWindow, error) { +func colorWhenRules() ([]config.TimeWindow, error) { envTime := config.EnvTOTPColorBetween.Get() if slices.Compare(envTime, config.TOTPDefaultBetween) == 0 { return config.TOTPDefaultColorWindow, nil } - return util.ParseTimeWindow(envTime...) + return ParseTimeWindow(envTime...) } func (w totpWrapper) generateCode() (string, error) { @@ -284,3 +284,34 @@ func NewTOTPArguments(args []string, tokenType string) (*TOTPArguments, error) { } return opts, nil } + +// ParseTimeWindow will handle parsing a window of colors for TOTP operations +func ParseTimeWindow(windows ...string) ([]config.TimeWindow, error) { + var rules []config.TimeWindow + for _, item := range windows { + line := strings.TrimSpace(item) + if line == "" { + continue + } + parts := strings.Split(line, config.TimeWindowSpan) + if len(parts) != 2 { + return nil, fmt.Errorf("invalid colorization rule found: %s", line) + } + s, err := strconv.Atoi(parts[0]) + if err != nil { + return nil, err + } + e, err := strconv.Atoi(parts[1]) + if err != nil { + return nil, err + } + if s < 0 || e < 0 || e < s || s > 59 || e > 59 { + return nil, fmt.Errorf("invalid time found for colorization rule: %s", line) + } + rules = append(rules, config.TimeWindow{Start: s, End: e}) + } + if len(rules) == 0 { + return nil, errors.New("invalid colorization rules for totp, none found") + } + return rules, nil +} diff --git a/internal/app/totp_test.go b/internal/app/totp_test.go @@ -235,3 +235,36 @@ func TestShow(t *testing.T) { t.Errorf("invalid short: %s", m.buf.String()) } } + +func TestParseWindows(t *testing.T) { + if _, err := app.ParseTimeWindow(); err.Error() != "invalid colorization rules for totp, none found" { + t.Errorf("invalid error: %v", err) + } + if _, err := app.ParseTimeWindow(" ", "2"); err.Error() != "invalid colorization rule found: 2" { + t.Errorf("invalid error: %v", err) + } + if _, err := app.ParseTimeWindow(" 1:200"); err.Error() != "invalid time found for colorization rule: 1:200" { + t.Errorf("invalid error: %v", err) + } + if _, err := app.ParseTimeWindow(" 1:-1"); err.Error() != "invalid time found for colorization rule: 1:-1" { + t.Errorf("invalid error: %v", err) + } + if _, err := app.ParseTimeWindow(" 200:1"); err.Error() != "invalid time found for colorization rule: 200:1" { + t.Errorf("invalid error: %v", err) + } + if _, err := app.ParseTimeWindow(" -1:1"); err.Error() != "invalid time found for colorization rule: -1:1" { + t.Errorf("invalid error: %v", err) + } + if _, err := app.ParseTimeWindow(" 2:1"); err.Error() != "invalid time found for colorization rule: 2:1" { + t.Errorf("invalid error: %v", err) + } + if _, err := app.ParseTimeWindow("xxx:1"); err.Error() != "strconv.Atoi: parsing \"xxx\": invalid syntax" { + t.Errorf("invalid error: %v", err) + } + if _, err := app.ParseTimeWindow(" 1:xxx"); err.Error() != "strconv.Atoi: parsing \"xxx\": invalid syntax" { + t.Errorf("invalid error: %v", err) + } + if _, err := app.ParseTimeWindow("1:2", " 11:22"); err != nil { + t.Errorf("invalid error: %v", err) + } +} diff --git a/internal/config/core.go b/internal/config/core.go @@ -11,7 +11,6 @@ import ( "time" "git.sr.ht/~enckse/lockbox/internal/config/store" - "git.sr.ht/~enckse/lockbox/internal/util" ) const ( @@ -29,10 +28,12 @@ const ( requiredKeyOrKeyFile = "a key, a key file, or both must be set" // ModTimeFormat is the expected modtime format ModTimeFormat = time.RFC3339 - exampleColorWindow = "start" + util.TimeWindowSpan + "end" + exampleColorWindow = "start" + TimeWindowSpan + "end" detectedValue = "(detected)" unset = "(unset)" arrayDelimiter = " " + // TimeWindowSpan indicates the delineation between start -> end (start:end) + TimeWindowSpan = ":" ) const ( @@ -56,18 +57,24 @@ var ( // NoValue is the string variant of 'No' (or false) items NoValue = strconv.FormatBool(false) // TOTPDefaultColorWindow is the default coloring rules for totp - TOTPDefaultColorWindow = []util.TimeWindow{{Start: 0, End: 5}, {Start: 30, End: 35}} + TOTPDefaultColorWindow = []TimeWindow{{Start: 0, End: 5}, {Start: 30, End: 35}} // TOTPDefaultBetween is the default color window as a string TOTPDefaultBetween = func() []string { var results []string for _, w := range TOTPDefaultColorWindow { - results = append(results, fmt.Sprintf("%d%s%d", w.Start, util.TimeWindowSpan, w.End)) + results = append(results, fmt.Sprintf("%d%s%d", w.Start, TimeWindowSpan, w.End)) } return results }() ) type ( + // TimeWindow for handling terminal colors based on timing + TimeWindow struct { + Start int + End int + } + stringsFlags int printer interface { display() metaData diff --git a/internal/config/vars.go b/internal/config/vars.go @@ -172,7 +172,7 @@ var ( environmentBase{ key: totpCategory + "COLOR_WINDOWS", description: fmt.Sprintf(`Override when to set totp generated outputs to different colors, -must be a list of one (or more) rules where a '%s' delimits the start and end second (0-60 for each).`, util.TimeWindowSpan), +must be a list of one (or more) rules where a '%s' delimits the start and end second (0-60 for each).`, TimeWindowSpan), }), flags: []stringsFlags{canDefaultFlag}, allowed: exampleColorWindows, diff --git a/internal/util/time.go b/internal/util/time.go @@ -1,51 +0,0 @@ -// Package util has to assist with some time windowing -package util - -import ( - "errors" - "fmt" - "strconv" - "strings" -) - -const ( - // TimeWindowSpan indicates the delineation between start -> end (start:end) - TimeWindowSpan = ":" -) - -// TimeWindow for handling terminal colors based on timing -type TimeWindow struct { - Start int - End int -} - -// ParseTimeWindow will handle parsing a window of colors for TOTP operations -func ParseTimeWindow(windows ...string) ([]TimeWindow, error) { - var rules []TimeWindow - for _, item := range windows { - line := strings.TrimSpace(item) - if line == "" { - continue - } - parts := strings.Split(line, TimeWindowSpan) - if len(parts) != 2 { - return nil, fmt.Errorf("invalid colorization rule found: %s", line) - } - s, err := strconv.Atoi(parts[0]) - if err != nil { - return nil, err - } - e, err := strconv.Atoi(parts[1]) - if err != nil { - return nil, err - } - if s < 0 || e < 0 || e < s || s > 59 || e > 59 { - return nil, fmt.Errorf("invalid time found for colorization rule: %s", line) - } - rules = append(rules, TimeWindow{Start: s, End: e}) - } - if len(rules) == 0 { - return nil, errors.New("invalid colorization rules for totp, none found") - } - return rules, nil -} diff --git a/internal/util/time_test.go b/internal/util/time_test.go @@ -1,40 +0,0 @@ -package util_test - -import ( - "testing" - - "git.sr.ht/~enckse/lockbox/internal/util" -) - -func TestParseWindows(t *testing.T) { - if _, err := util.ParseTimeWindow(); err.Error() != "invalid colorization rules for totp, none found" { - t.Errorf("invalid error: %v", err) - } - if _, err := util.ParseTimeWindow(" ", "2"); err.Error() != "invalid colorization rule found: 2" { - t.Errorf("invalid error: %v", err) - } - if _, err := util.ParseTimeWindow(" 1:200"); err.Error() != "invalid time found for colorization rule: 1:200" { - t.Errorf("invalid error: %v", err) - } - if _, err := util.ParseTimeWindow(" 1:-1"); err.Error() != "invalid time found for colorization rule: 1:-1" { - t.Errorf("invalid error: %v", err) - } - if _, err := util.ParseTimeWindow(" 200:1"); err.Error() != "invalid time found for colorization rule: 200:1" { - t.Errorf("invalid error: %v", err) - } - if _, err := util.ParseTimeWindow(" -1:1"); err.Error() != "invalid time found for colorization rule: -1:1" { - t.Errorf("invalid error: %v", err) - } - if _, err := util.ParseTimeWindow(" 2:1"); err.Error() != "invalid time found for colorization rule: 2:1" { - t.Errorf("invalid error: %v", err) - } - if _, err := util.ParseTimeWindow("xxx:1"); err.Error() != "strconv.Atoi: parsing \"xxx\": invalid syntax" { - t.Errorf("invalid error: %v", err) - } - if _, err := util.ParseTimeWindow(" 1:xxx"); err.Error() != "strconv.Atoi: parsing \"xxx\": invalid syntax" { - t.Errorf("invalid error: %v", err) - } - if _, err := util.ParseTimeWindow("1:2", " 11:22"); err != nil { - t.Errorf("invalid error: %v", err) - } -}