lockbox

password manager
Log | Files | Refs | README | LICENSE

commit 2919ef4dd392cc53ca965fba04d0c93adbed4348
parent fc0c6c317501548ecb60f69796f626693d96c981
Author: Sean Enck <sean@ttypty.com>
Date:   Sat, 31 Dec 2022 18:42:34 -0500

allow overriding modtime

Diffstat:
Mcmd/vers.txt | 4++--
Minternal/backend/actions.go | 11++++++++++-
Minternal/backend/actions_test.go | 2++
Minternal/backend/query_test.go | 47+++++++++++++++++++++++++++++++++++++++++++++++
Minternal/inputs/env.go | 6++++++
Minternal/inputs/env_test.go | 2+-
6 files changed, 68 insertions(+), 4 deletions(-)

diff --git a/cmd/vers.txt b/cmd/vers.txt @@ -1 +1 @@ -v22.12.05 -\ No newline at end of file +v22.12.06 +\ No newline at end of file diff --git a/internal/backend/actions.go b/internal/backend/actions.go @@ -225,6 +225,15 @@ func (t *Transaction) Move(src QueryEntity, dst string) error { if strings.TrimSpace(src.Value) == "" { return errors.New("empty secret not allowed") } + mod := inputs.EnvOrDefault(inputs.ModTimeEnv, "") + modTime := time.Now() + if mod != "" { + p, err := time.Parse(inputs.ModTimeFormat, mod) + if err != nil { + return err + } + modTime = p + } dOffset, dTitle, err := splitComponents(dst) if err != nil { return err @@ -269,7 +278,7 @@ func (t *Transaction) Move(src QueryEntity, dst string) error { e.Values = append(e.Values, protectedValue("otp", v)) } e.Values = append(e.Values, protectedValue(field, v)) - e.Values = append(e.Values, value(modTimeKey, time.Now().Format(time.RFC3339))) + e.Values = append(e.Values, value(modTimeKey, modTime.Format(time.RFC3339))) c.insertEntity(dOffset, dTitle, e) return nil }) diff --git a/internal/backend/actions_test.go b/internal/backend/actions_test.go @@ -21,6 +21,7 @@ func fullSetup(t *testing.T, keep bool) *backend.Transaction { os.Setenv("LOCKBOX_KEYMODE", "plaintext") os.Setenv("LOCKBOX_TOTP", "totp") os.Setenv("LOCKBOX_HOOKDIR", "") + os.Setenv("LOCKBOX_SET_MODTIME", "") tr, err := backend.NewTransaction() if err != nil { t.Errorf("failed: %v", err) @@ -38,6 +39,7 @@ func TestKeyFile(t *testing.T) { os.Setenv("LOCKBOX_KEYMODE", "plaintext") os.Setenv("LOCKBOX_TOTP", "totp") os.Setenv("LOCKBOX_HOOKDIR", "") + os.Setenv("LOCKBOX_SET_MODTIME", "") os.WriteFile("file.key.kdbx", []byte("test"), 0644) tr, err := backend.NewTransaction() if err != nil { diff --git a/internal/backend/query_test.go b/internal/backend/query_test.go @@ -1,6 +1,8 @@ package backend_test import ( + "fmt" + "os" "strings" "testing" @@ -188,3 +190,48 @@ func TestNewPath(t *testing.T) { t.Error("invalid new path") } } + +func TestSetModTime(t *testing.T) { + testDateTime := "2022-12-30T12:34:56-05:00" + tr := fullSetup(t, false) + os.Setenv("LOCKBOX_SET_MODTIME", testDateTime) + tr.Insert("test/xyz", "test") + q, err := fullSetup(t, true).Get("test/xyz", backend.HashedValue) + if err != nil { + t.Errorf("no error: %v", err) + } + hash := strings.TrimSpace(q.Value) + parts := strings.Split(hash, "\n") + if len(parts) != 2 { + t.Errorf("invalid hash output: %v", parts) + } + dt := parts[0] + if dt != fmt.Sprintf("modtime: %s", testDateTime) { + t.Errorf("invalid date/time: %s", dt) + } + + tr = fullSetup(t, false) + os.Setenv("LOCKBOX_SET_MODTIME", "") + tr.Insert("test/xyz", "test") + q, err = fullSetup(t, true).Get("test/xyz", backend.HashedValue) + if err != nil { + t.Errorf("no error: %v", err) + } + hash = strings.TrimSpace(q.Value) + parts = strings.Split(hash, "\n") + if len(parts) != 2 { + t.Errorf("invalid hash output: %v", parts) + } + dt = parts[0] + if dt == fmt.Sprintf("modtime: %s", testDateTime) { + t.Errorf("invalid date/time: %s", dt) + } + + tr = fullSetup(t, false) + os.Setenv("LOCKBOX_SET_MODTIME", "garbage") + err = tr.Insert("test/xyz", "test") + if err == nil || !strings.Contains(err.Error(), "parsing time") { + t.Errorf("invalid error: %v", err) + } + +} diff --git a/internal/inputs/env.go b/internal/inputs/env.go @@ -9,6 +9,7 @@ import ( "os/exec" "strconv" "strings" + "time" "github.com/google/shlex" ) @@ -61,6 +62,10 @@ const ( noTOTPEnv = prefixKey + "NOTOTP" // HookDirEnv represents a stored location for user hooks HookDirEnv = prefixKey + "HOOKDIR" + // ModTimeEnv is modtime override ability for entries + ModTimeEnv = prefixKey + "SET_MODTIME" + // ModTimeFormat is the expected modtime format + ModTimeFormat = time.RFC3339 ) var ( @@ -295,5 +300,6 @@ func ListEnvironmentVariables(showValues bool) []string { results = append(results, e.formatEnvironmentVariable(false, HookDirEnv, "", "the path to hooks to execute on actions against the database", []string{"directory"})) results = append(results, e.formatEnvironmentVariable(false, clipOSC52Env, isNo, "enable OSC52 clipboard mode", isYesNoArgs)) results = append(results, e.formatEnvironmentVariable(false, KeyFileEnv, "", "additional keyfile to access/protect the database", []string{"keyfile"})) + results = append(results, e.formatEnvironmentVariable(false, ModTimeEnv, ModTimeFormat, "input mod time to set for the entry", []string{"modtime"})) return results } diff --git a/internal/inputs/env_test.go b/internal/inputs/env_test.go @@ -166,7 +166,7 @@ func TestListVariables(t *testing.T) { known[trim] = struct{}{} } l := len(known) - if l != 18 { + if l != 19 { t.Errorf("invalid env count, outdated? %d", l) } }