commit 1c36decc72a49eab7de29f9787d0b043110bded9
parent 95b7766aad5a7c8e28e33d8facef1192b2d33aea
Author: Sean Enck <sean@ttypty.com>
Date: Sun, 8 Dec 2024 18:50:37 -0500
fix time windows
Diffstat:
7 files changed, 72 insertions(+), 26 deletions(-)
diff --git a/internal/app/totp.go b/internal/app/totp.go
@@ -4,6 +4,7 @@ package app
import (
"errors"
"fmt"
+ "slices"
"strings"
"time"
@@ -78,11 +79,11 @@ func clearFunc() {
}
func colorWhenRules() ([]util.TimeWindow, error) {
- envTime := config.EnvTOTPColorBetween.Get()
- if envTime == config.TOTPDefaultBetween {
+ envTime := config.EnvTOTPColorBetween.AsArray()
+ if slices.Compare(envTime, config.TOTPDefaultBetween) == 0 {
return config.TOTPDefaultColorWindow, nil
}
- return util.ParseTimeWindow(envTime)
+ return util.ParseTimeWindow(envTime...)
}
func (w totpWrapper) generateCode() (string, error) {
diff --git a/internal/config/core.go b/internal/config/core.go
@@ -32,6 +32,7 @@ const (
exampleColorWindow = "start" + util.TimeWindowSpan + "end"
detectedValue = "(detected)"
unset = "(unset)"
+ arrayDelimiter = " "
)
const (
@@ -42,7 +43,7 @@ const (
)
var (
- exampleColorWindows = []string{fmt.Sprintf("[%s]", strings.Join([]string{exampleColorWindow, exampleColorWindow, exampleColorWindow + "..."}, util.TimeWindowDelimiter))}
+ exampleColorWindows = []string{fmt.Sprintf("[%s]", strings.Join([]string{exampleColorWindow, exampleColorWindow, exampleColorWindow + "..."}, arrayDelimiter))}
configDirFile = filepath.Join("lockbox", "config.toml")
registry = map[string]printer{}
// ConfigXDG is the offset to the config for XDG
@@ -58,12 +59,12 @@ var (
// TOTPDefaultColorWindow is the default coloring rules for totp
TOTPDefaultColorWindow = []util.TimeWindow{{Start: 0, End: 5}, {Start: 30, End: 35}}
// TOTPDefaultBetween is the default color window as a string
- TOTPDefaultBetween = func() 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))
}
- return strings.Join(results, util.TimeWindowDelimiter)
+ return results
}()
)
diff --git a/internal/config/env.go b/internal/config/env.go
@@ -88,23 +88,24 @@ func (e EnvironmentInt) Get() (int64, error) {
// Get will read the string from the environment
func (e EnvironmentStrings) Get() string {
- val, ok := store.GetString(e.Key())
- if !ok {
- flags := e.flattenFlags()
- if slices.Contains(flags, canDefaultFlag) {
- val = e.value
- }
- }
- return val
+ return stringsGet(e, store.GetString, func(val string) string {
+ return val
+ })
}
// AsArray indicates the item should be queried as an array
func (e EnvironmentStrings) AsArray() []string {
- val, ok := store.GetArray(e.Key())
+ return stringsGet(e, store.GetArray, func(val string) []string {
+ return strings.Split(val, arrayDelimiter)
+ })
+}
+
+func stringsGet[T string | []string](e EnvironmentStrings, getter func(string) (T, bool), conv func(string) T) T {
+ val, ok := getter(e.Key())
if !ok {
flags := e.flattenFlags()
if slices.Contains(flags, canDefaultFlag) {
- val = []string{e.value}
+ val = conv(e.value)
}
}
return val
diff --git a/internal/config/vars.go b/internal/config/vars.go
@@ -3,6 +3,7 @@ package config
import (
"fmt"
+ "strings"
"github.com/seanenck/lockbox/internal/output"
"github.com/seanenck/lockbox/internal/platform"
@@ -170,12 +171,11 @@ var (
// EnvTOTPColorBetween handles terminal coloring for TOTP windows (seconds)
EnvTOTPColorBetween = environmentRegister(
EnvironmentStrings{
- environmentDefault: newDefaultedEnvironment(TOTPDefaultBetween,
+ environmentDefault: newDefaultedEnvironment(strings.Join(TOTPDefaultBetween, arrayDelimiter),
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),
-and '%s' allows for multiple windows.`, util.TimeWindowSpan, util.TimeWindowDelimiter),
+must be a list of one (or more) rules where a '%s' delimits the start and end second (0-60 for each).`, util.TimeWindowSpan),
}),
flags: []stringsFlags{isArrayFlag, canDefaultFlag},
allowed: exampleColorWindows,
diff --git a/internal/config/vars_test.go b/internal/config/vars_test.go
@@ -2,6 +2,7 @@ package config_test
import (
"fmt"
+ "slices"
"testing"
"github.com/seanenck/lockbox/internal/config"
@@ -138,3 +139,47 @@ func checkInt(e config.EnvironmentInt, key, text string, def int64, allowZero bo
}
}
}
+
+func TestStringsGetDefault(t *testing.T) {
+ store.Clear()
+ val := config.EnvPlatform.Get()
+ if val != "" {
+ t.Errorf("invalid read: %v", val)
+ }
+ val = config.EnvJSONMode.Get()
+ if val != "hash" {
+ t.Errorf("invalid read: %v", val)
+ }
+ store.SetString("LOCKBOX_PLATFORM", "1")
+ store.SetString("LOCKBOX_JSON_MODE", "a")
+ val = config.EnvPlatform.Get()
+ if val != "1" {
+ t.Errorf("invalid read: %v", val)
+ }
+ val = config.EnvJSONMode.Get()
+ if val != "a" {
+ t.Errorf("invalid read: %v", val)
+ }
+}
+
+func TestStringsArray(t *testing.T) {
+ store.Clear()
+ val := config.EnvTOTPColorBetween.AsArray()
+ if slices.Compare(val, config.TOTPDefaultBetween) != 0 {
+ t.Errorf("invalid read: %v", val)
+ }
+ val = config.EnvClipCopy.AsArray()
+ if len(val) != 0 {
+ t.Errorf("invalid read: %v", val)
+ }
+ store.SetArray("LOCKBOX_CLIP_COPY_COMMAND", []string{"1"})
+ store.SetArray("LOCKBOX_TOTP_COLOR_WINDOWS", []string{"1", "2", "3"})
+ val = config.EnvTOTPColorBetween.AsArray()
+ if len(val) != 3 {
+ t.Errorf("invalid read: %v", val)
+ }
+ val = config.EnvClipCopy.AsArray()
+ if len(val) != 1 {
+ t.Errorf("invalid read: %v", val)
+ }
+}
diff --git a/internal/util/time.go b/internal/util/time.go
@@ -9,8 +9,6 @@ import (
)
const (
- // TimeWindowDelimiter indicates how windows are split in env/config keys
- TimeWindowDelimiter = " "
// TimeWindowSpan indicates the delineation between start -> end (start:end)
TimeWindowSpan = ":"
)
@@ -22,9 +20,9 @@ type TimeWindow struct {
}
// ParseTimeWindow will handle parsing a window of colors for TOTP operations
-func ParseTimeWindow(windowString string) ([]TimeWindow, error) {
+func ParseTimeWindow(windows ...string) ([]TimeWindow, error) {
var rules []TimeWindow
- for _, item := range strings.Split(windowString, TimeWindowDelimiter) {
+ for _, item := range windows {
line := strings.TrimSpace(item)
if line == "" {
continue
diff --git a/internal/util/time_test.go b/internal/util/time_test.go
@@ -7,10 +7,10 @@ import (
)
func TestParseWindows(t *testing.T) {
- if _, err := util.ParseTimeWindow(""); err.Error() != "invalid colorization rules for totp, none found" {
+ 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" {
+ 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" {
@@ -34,7 +34,7 @@ func TestParseWindows(t *testing.T) {
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 {
+ if _, err := util.ParseTimeWindow("1:2", " 11:22"); err != nil {
t.Errorf("invalid error: %v", err)
}
}