commit 46934afcb75a339f3a8681128ad2b74e6dd9923b
parent 3f591cf1874d6e87360a9b67bf35465ca4d0eb11
Author: Sean Enck <sean@ttypty.com>
Date: Sat, 7 Jun 2025 20:17:11 -0400
support URL field
Diffstat:
5 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/cmd/lb/main_test.go b/cmd/lb/main_test.go
@@ -207,7 +207,7 @@ func test(profile string) error {
for _, k := range []string{"insert test4/multiline/notes", "insert test5/multiline/notes", "insert test5/multiline/otp", "insert test5/multiline/password"} {
r.run(`printf "testing3\ntesting4\n" |`, k)
}
- for _, k := range []string{"insert test6/multiline/password", "insert test6/multiline/notes", "insert test7/deeper/rooted/notes", "insert test7/deeper/rooted/otp", "insert test8/unset/password", "insert test8/unset/notes", "insert test9/key1/sub1/password", "insert test9/key1/sub2/password", "insert test9/key2/sub1/password"} {
+ for _, k := range []string{"insert test6/multiline/password", "insert test6/multiline/notes", "insert test7/deeper/rooted/notes", "insert test7/deeper/rooted/otp", "insert test7/deeper/root/url", "insert test8/unset/password", "insert test8/unset/notes", "insert test9/key1/sub1/password", "insert test9/key1/sub2/password", "insert test9/key2/sub1/password"} {
r.run(`printf "testing5" |`, k)
r.run("", fmt.Sprintf("show %s", strings.ReplaceAll(k, "insert ", "")))
}
diff --git a/cmd/lb/tests/expected.log b/cmd/lb/tests/expected.log
@@ -13,6 +13,7 @@ testing5
testing5
testing5
testing5
+testing5
test1/key1/password
test2/key1/notes
test2/key1/password
@@ -20,6 +21,7 @@ test4/multiline/notes
test5/multiline/notes
test6/multiline/notes
test6/multiline/password
+test7/deeper/root/url
test7/deeper/rooted/notes
test7/deeper/rooted/otp
test8/unset/notes
@@ -32,6 +34,7 @@ test2/key1
test4/multiline
test5/multiline
test6/multiline
+test7/deeper/root
test7/deeper/rooted
test8/unset
test9/key1/sub1
@@ -43,6 +46,7 @@ test4/multiline/notes
test5/multiline/notes
test6/multiline/notes
test6/multiline/password
+test7/deeper/root/url
test7/deeper/rooted/notes
test7/deeper/rooted/otp
test8/unset/notes
@@ -72,6 +76,10 @@ test6/multiline/password
"notes": "cbf67e6da88d43f048050e36d7010080536372397b6ed0a0446cd2640340bf47cb616ddbc5d35ec3500e295f875f806fc20120a2d5497b3e729e904091424633",
"password": "cbf67e6da88d43f048050e36d7010080536372397b6ed0a0446cd2640340bf47cb616ddbc5d35ec3500e295f875f806fc20120a2d5497b3e729e904091424633"
},
+ "test7/deeper/root": {
+ "modtime": "XXXX-XX-XX",
+ "url": "cbf67e6da88d43f048050e36d7010080536372397b6ed0a0446cd2640340bf47cb616ddbc5d35ec3500e295f875f806fc20120a2d5497b3e729e904091424633"
+ },
"test7/deeper/rooted": {
"modtime": "XXXX-XX-XX",
"notes": "cbf67e6da88d43f048050e36d7010080536372397b6ed0a0446cd2640340bf47cb616ddbc5d35ec3500e295f875f806fc20120a2d5497b3e729e904091424633",
@@ -141,6 +149,10 @@ period: 30
"otp": "b6c44d5d8a75071d8e8a39df231b0b98584d1d42982b5cf230e44f94d9c48e2983e78955a54b70c0acb0428d6db7205101e332f950ffb6b6d643aa37287c6aa5",
"password": "cbf67e6da88d43f048050e36d7010080536372397b6ed0a0446cd2640340bf47cb616ddbc5d35ec3500e295f875f806fc20120a2d5497b3e729e904091424633"
}
+"test7/deeper/root": {
+ "modtime": "XXXX-XX-XX",
+ "url": "cbf67e6da88d43f048050e36d7010080536372397b6ed0a0446cd2640340bf47cb616ddbc5d35ec3500e295f875f806fc20120a2d5497b3e729e904091424633"
+}
"test7/deeper/rooted": {
"modtime": "XXXX-XX-XX",
"notes": "cbf67e6da88d43f048050e36d7010080536372397b6ed0a0446cd2640340bf47cb616ddbc5d35ec3500e295f875f806fc20120a2d5497b3e729e904091424633",
@@ -167,7 +179,11 @@ no entities matching: test7/deeper
no entities matching: test7/deeper/ro
no entities matching: test1/key1/password
delete entry? (y/N)
-delete entry? (y/N)
+selected entities:
+ test7/deeper/root
+ test7/deeper/rooted
+
+delete entries? (y/N)
test4/multiline/notes
test5/multiline/notes
test6/multiline/notes
diff --git a/internal/kdbx/actions.go b/internal/kdbx/actions.go
@@ -225,7 +225,7 @@ func (t *Transaction) Move(src *Entity, dst string) error {
for k, v := range values {
val := v
switch k {
- case OTPField, PasswordField:
+ case OTPField, PasswordField, URLField:
if strings.Contains(val, "\n") {
return fmt.Errorf("%s can NOT be multi-line", strings.ToLower(k))
}
diff --git a/internal/kdbx/actions_test.go b/internal/kdbx/actions_test.go
@@ -129,7 +129,7 @@ func TestInserts(t *testing.T) {
if err := setup(t).Insert("/tests", map[string]string{"password": "test"}); err.Error() != "path can NOT be rooted" {
t.Errorf("wrong error: %v", err)
}
- if err := setup(t).Insert("test", map[string]string{"otp": "test"}); err.Error() != "input paths must contain at LEAST 2 components" {
+ if err := setup(t).Insert("test", map[string]string{"otp": "test", "url": "xyz"}); err.Error() != "input paths must contain at LEAST 2 components" {
t.Errorf("wrong error: %v", err)
}
if err := setup(t).Insert("a", nil); err.Error() != "empty secrets not allowed" {
@@ -144,7 +144,7 @@ func TestInserts(t *testing.T) {
if err := fullSetup(t, true).Insert(kdbx.NewPath("test", "offset", "value"), map[string]string{"NoTes": "pass2"}); err != nil {
t.Errorf("wrong error: %v", err)
}
- if err := fullSetup(t, true).Insert(kdbx.NewPath("test", "offset", "value2"), map[string]string{"NOTES": "pass\npass", "password": "xxx", "otP": "zzz"}); err != nil {
+ if err := fullSetup(t, true).Insert(kdbx.NewPath("test", "offset", "value2"), map[string]string{"NOTES": "pass\npass", "uRL": "123", "password": "xxx", "otP": "zzz"}); err != nil {
t.Errorf("no error: %v", err)
}
q, err := fullSetup(t, true).Get(kdbx.NewPath("test", "offset", "value"), kdbx.SecretValue)
@@ -167,12 +167,18 @@ func TestInserts(t *testing.T) {
if val, ok := q.Value("otp"); !ok || val != "otpauth://totp/lbissuer:lbaccount?algorithm=SHA1&digits=6&issuer=lbissuer&period=30&secret=zzz" {
t.Errorf("invalid retrieval: %s", val)
}
+ if val, ok := q.Value("url"); !ok || val != "123" {
+ t.Errorf("invalid retrieval: %s", val)
+ }
if err := fullSetup(t, true).Insert(kdbx.NewPath("test", "offset"), map[string]string{"otp": "5ae472sabqdekjqykoyxk7hvc2leklq5n"}); err != nil {
t.Errorf("no error: %v", err)
}
if err := fullSetup(t, true).Insert(kdbx.NewPath("test", "offset"), map[string]string{"OTP": "ljaf\n5ae472abqdekjqykoyxk7hvc2leklq5n"}); err == nil || err.Error() != "otp can NOT be multi-line" {
t.Errorf("wrong error: %v", err)
}
+ if err := fullSetup(t, true).Insert(kdbx.NewPath("test", "offset"), map[string]string{"urL": "ljaf\n5ae472abqdekjqykoyxk7hvc2leklq5n"}); err == nil || err.Error() != "url can NOT be multi-line" {
+ t.Errorf("wrong error: %v", err)
+ }
if err := fullSetup(t, true).Insert(kdbx.NewPath("test", "offset"), map[string]string{"password": "ljaf\n5ae472abqdekjqykoyxk7hvc2leklq5n"}); err == nil || err.Error() != "password can NOT be multi-line" {
t.Errorf("wrong error: %v", err)
}
diff --git a/internal/kdbx/core.go b/internal/kdbx/core.go
@@ -17,7 +17,7 @@ import (
var (
errPath = errors.New("input paths must contain at LEAST 2 components")
// AllowedFields are the same of allowed names for storing in a kdbx entry
- AllowedFields = []string{NotesField, OTPField, PasswordField}
+ AllowedFields = []string{NotesField, OTPField, PasswordField, URLField}
)
const (
@@ -31,6 +31,8 @@ const (
NotesField = "Notes"
// PasswordField is where the password is stored
PasswordField = "Password"
+ // URLField is the URL field in the kdbx
+ URLField = "URL"
)
type (