commit 1f0674f8d6a579cb474f6a8af65ffd03a9f39bf3
parent d7d15be67abe320bd324339173d50c902f4567c5
Author: Sean Enck <sean@ttypty.com>
Date: Mon, 12 Jan 2026 22:13:31 -0500
no longer output all the fields and just produce the singular checksum field
Diffstat:
5 files changed, 32 insertions(+), 71 deletions(-)
diff --git a/cmd/lb/tests/expected.log b/cmd/lb/tests/expected.log
@@ -110,73 +110,56 @@ test7/deeper/root/url
"test1/key1": {
"checksum": "[00 00 00 00 cd 5p]",
"modtime": "XXXX-XX-XX",
- "password": "57c8df271f1dfecb52f1e56d419bcf57b9cbf649a29bba042ccc8e1301acb0d930b22bedeb1373d8489b9f8eb1ccb310a877f382f62e597c9f5dbdd4a3ee2323"
},
"test4/multiline": {
"checksum": "[00 00 00 00 dd fn]",
"modtime": "XXXX-XX-XX",
- "notes": "08ecffb3ead6b577fbbacef5b1b87c240588208eee82904acc8e300fc10c504758878e9a2202a6e161d7d4925983117ee00293434bddb592656fcf01bca69ad3"
},
"test5/multiline": {
"checksum": "[00 00 00 00 cd fn]",
"modtime": "XXXX-XX-XX",
- "notes": "6be4f7e6c6761aa37ad0da252f7647e0d5401608dc193e0cf6c9cf16331600ca96df65cc5bdb2a085e79fb0818e98d1aabe8ae4e129ae369115f67f56ef9a859"
},
"test6/multiline": {
"checksum": "[00 00 00 2d cn cp]",
"modtime": "XXXX-XX-XX",
- "notes": "5b88331608e33b74c5fd5d22e9053a65f5cace6a3c046d7fbc9aaea1340bd1de90b6198a99af93d02df3c4715febb1daac5babb596867137b2a65ff91fd799ad",
- "password": "5b88331608e33b74c5fd5d22e9053a65f5cace6a3c046d7fbc9aaea1340bd1de90b6198a99af93d02df3c4715febb1daac5babb596867137b2a65ff91fd799ad"
},
"test7/deeper/root": {
"checksum": "[00 00 00 00 7d cu]",
"modtime": "XXXX-XX-XX",
- "url": "ea959087841400b15d443e852860b70d4350c7264b4a8a446021416868d193c992c7a864881da3c4cbaaed4f6c970a6aeeeee0a2bc39f8a1f6845d2d95e14786"
},
"test7/deeper/rooted": {
"checksum": "[00 00 00 3d cn 3o]",
"modtime": "XXXX-XX-XX",
- "notes": "1abfb8edd6c73ae6b1eb9842863b95a30e2308e7a0fe0070745ea3871a106813e9a3cf04fa43b0d322f79c03da6851b18e2139f827399fe019fc13eaaa993815",
- "otp": "d7d94959b640a2a11bac8cfde21cb8780943625403592b77a520585cdaf0469d2d0c7a834b70c053676f7298cb3d6f9b0d0a6dba4599dc2d53ec8508aedea801"
},
"test8/unset": {
"checksum": "[00 00 00 2d cn cp]",
"modtime": "XXXX-XX-XX",
- "notes": "0956b6450f907573260ad631985167421abbc38d2d69e690f87a370a0e4755a388b6e20e8ec15cfa8ce8d3c2a11117bbf345492ff9446f5781c10cfd54d68403",
- "password": "0956b6450f907573260ad631985167421abbc38d2d69e690f87a370a0e4755a388b6e20e8ec15cfa8ce8d3c2a11117bbf345492ff9446f5781c10cfd54d68403"
},
"test9/key1/sub1": {
"checksum": "[00 00 00 00 4d cp]",
"modtime": "XXXX-XX-XX",
- "password": "e1fe8b29f0ed07e6af8a6a1100ed5268a58185eaf167726599be55ef09c363adf4df3257f45a84557977fd6b45f0713d6f791f6bc1e0ebce046568256859445b"
},
"test9/key1/sub2": {
"checksum": "[00 00 00 00 7d cp]",
"modtime": "XXXX-XX-XX",
- "password": "ef69a69c35f720f0f252d4ed94c65fa5217222689a1ced1b3c409eb0a47736ba9df2d8e78563a6b1b78fb89c36c8cdc74c0bb195e025131b2ef615dc45444784"
},
"test9/key2/sub1": {
"checksum": "[00 00 00 00 fd cp]",
"modtime": "XXXX-XX-XX",
- "password": "27141582d19bb3d4e6ef34333895f2e193655ab069bb71331755caf310dac9610ca7027ec66faeceb3ac98b20bac5a77d580e95e6d8bd404b5d1ffb816192b9e"
}
}
{
"test4/multiline": {
"checksum": "[00 00 00 00 dd fn]",
"modtime": "XXXX-XX-XX",
- "notes": "08ecffb3ead6b577fbbacef5b1b87c240588208eee82904acc8e300fc10c504758878e9a2202a6e161d7d4925983117ee00293434bddb592656fcf01bca69ad3"
},
"test5/multiline": {
"checksum": "[00 00 00 00 cd fn]",
"modtime": "XXXX-XX-XX",
- "notes": "6be4f7e6c6761aa37ad0da252f7647e0d5401608dc193e0cf6c9cf16331600ca96df65cc5bdb2a085e79fb0818e98d1aabe8ae4e129ae369115f67f56ef9a859"
},
"test6/multiline": {
"checksum": "[00 00 00 2d cn cp]",
"modtime": "XXXX-XX-XX",
- "notes": "5b88331608e33b74c5fd5d22e9053a65f5cace6a3c046d7fbc9aaea1340bd1de90b6198a99af93d02df3c4715febb1daac5babb596867137b2a65ff91fd799ad",
- "password": "5b88331608e33b74c5fd5d22e9053a65f5cace6a3c046d7fbc9aaea1340bd1de90b6198a99af93d02df3c4715febb1daac5babb596867137b2a65ff91fd799ad"
}
}
totp
@@ -204,61 +187,46 @@ period: 30
"test1/key1": {
"checksum": "[00 00 00 00 cd 5p]",
"modtime": "XXXX-XX-XX",
- "password": "57c8df271f1dfecb52f1e56d419bcf57b9cbf649a29bba042ccc8e1301acb0d930b22bedeb1373d8489b9f8eb1ccb310a877f382f62e597c9f5dbdd4a3ee2323"
}
"test10/key1": {
"checksum": "[00 00 00 00 cd bo]",
"modtime": "XXXX-XX-XX",
- "otp": "f79f64504a1841638238141f19ec05f237d1b692c935dc605a1efc0f42e7fcfdb838ece01c644fe8ee9586faf6ff5cc5df2c7b300165df7af33e9e2e87322687"
}
"test4/multiline": {
"checksum": "[00 00 00 00 dd fn]",
"modtime": "XXXX-XX-XX",
- "notes": "08ecffb3ead6b577fbbacef5b1b87c240588208eee82904acc8e300fc10c504758878e9a2202a6e161d7d4925983117ee00293434bddb592656fcf01bca69ad3"
}
"test5/multiline": {
"checksum": "[00 00 00 00 cd fn]",
"modtime": "XXXX-XX-XX",
- "notes": "6be4f7e6c6761aa37ad0da252f7647e0d5401608dc193e0cf6c9cf16331600ca96df65cc5bdb2a085e79fb0818e98d1aabe8ae4e129ae369115f67f56ef9a859"
}
"test6/multiline": {
"checksum": "[00 00 2d cn bo cp]",
"modtime": "XXXX-XX-XX",
- "notes": "5b88331608e33b74c5fd5d22e9053a65f5cace6a3c046d7fbc9aaea1340bd1de90b6198a99af93d02df3c4715febb1daac5babb596867137b2a65ff91fd799ad",
- "otp": "6d76012d8097b71107085ba0427460d1cec5bf5f18d93ab7001ec43a65b73def59078680999fc9b9476a923cfe34850b8dbe74292aa7b862e214f5f1070cf720",
- "password": "5b88331608e33b74c5fd5d22e9053a65f5cace6a3c046d7fbc9aaea1340bd1de90b6198a99af93d02df3c4715febb1daac5babb596867137b2a65ff91fd799ad"
}
"test7/deeper/root": {
"checksum": "[00 00 00 00 7d cu]",
"modtime": "XXXX-XX-XX",
- "url": "ea959087841400b15d443e852860b70d4350c7264b4a8a446021416868d193c992c7a864881da3c4cbaaed4f6c970a6aeeeee0a2bc39f8a1f6845d2d95e14786"
}
"test7/deeper/rooted": {
"checksum": "[00 00 00 3d cn 3o]",
"modtime": "XXXX-XX-XX",
- "notes": "1abfb8edd6c73ae6b1eb9842863b95a30e2308e7a0fe0070745ea3871a106813e9a3cf04fa43b0d322f79c03da6851b18e2139f827399fe019fc13eaaa993815",
- "otp": "d7d94959b640a2a11bac8cfde21cb8780943625403592b77a520585cdaf0469d2d0c7a834b70c053676f7298cb3d6f9b0d0a6dba4599dc2d53ec8508aedea801"
}
"test8/unset": {
"checksum": "[00 00 00 2d cn cp]",
"modtime": "XXXX-XX-XX",
- "notes": "0956b6450f907573260ad631985167421abbc38d2d69e690f87a370a0e4755a388b6e20e8ec15cfa8ce8d3c2a11117bbf345492ff9446f5781c10cfd54d68403",
- "password": "0956b6450f907573260ad631985167421abbc38d2d69e690f87a370a0e4755a388b6e20e8ec15cfa8ce8d3c2a11117bbf345492ff9446f5781c10cfd54d68403"
}
"test9/key1/sub1": {
"checksum": "[00 00 00 00 4d cp]",
"modtime": "XXXX-XX-XX",
- "password": "e1fe8b29f0ed07e6af8a6a1100ed5268a58185eaf167726599be55ef09c363adf4df3257f45a84557977fd6b45f0713d6f791f6bc1e0ebce046568256859445b"
}
"test9/key1/sub2": {
"checksum": "[00 00 00 00 7d cp]",
"modtime": "XXXX-XX-XX",
- "password": "ef69a69c35f720f0f252d4ed94c65fa5217222689a1ced1b3c409eb0a47736ba9df2d8e78563a6b1b78fb89c36c8cdc74c0bb195e025131b2ef615dc45444784"
}
"test9/key2/sub1": {
"checksum": "[00 00 00 00 fd cp]",
"modtime": "XXXX-XX-XX",
- "password": "27141582d19bb3d4e6ef34333895f2e193655ab069bb71331755caf310dac9610ca7027ec66faeceb3ac98b20bac5a77d580e95e6d8bd404b5d1ffb816192b9e"
}
removing
delete entry? (y/N)
@@ -410,11 +378,8 @@ json
}
{
"test6/multiline": {
- "checksum": "[00 00 2d cn bo cp]",
+ "checksum": "[0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 23cd cbfn b6co cbfp]",
"modtime": "XXXX-XX-XX",
- "notes": "5b8",
- "otp": "6d7",
- "password": "5b8"
}
}
clipboard
diff --git a/internal/config/vars.go b/internal/config/vars.go
@@ -35,13 +35,13 @@ var (
})
// EnvJSONHashLength handles the hashing output length
EnvJSONHashLength = environmentRegister(EnvironmentInt{
- environmentDefault: newDefaultedEnvironment(0,
+ environmentDefault: newDefaultedEnvironment(1,
environmentBase{
- key: jsonCategory + "HASH_LENGTH",
- description: fmt.Sprintf("Maximum string length of the JSON value when '%s' mode is set for JSON output.", output.JSONModes.Hash),
+ key: jsonCategory + "HASH_LENGTH",
+ description: fmt.Sprintf(`Maximum string length of the JSON checksum value when JSON '%s' mode is set.
+This value is appended to the single character type field`, output.JSONModes.Hash),
}),
- short: "hash length",
- canZero: true,
+ short: "checksum value length",
})
// EnvReadOnly indicates if in read-only mode
EnvReadOnly = environmentRegister(EnvironmentBool{
diff --git a/internal/config/vars_test.go b/internal/config/vars_test.go
@@ -66,7 +66,7 @@ func TestFormatTOTP(t *testing.T) {
}
func TestHashLength(t *testing.T) {
- checkInt(config.EnvJSONHashLength, "LOCKBOX_JSON_HASH_LENGTH", "hash length", 0, true, t)
+ checkInt(config.EnvJSONHashLength, "LOCKBOX_JSON_HASH_LENGTH", "checksum value length", 1, false, t)
}
func TestMaxTOTP(t *testing.T) {
diff --git a/internal/kdbx/query.go b/internal/kdbx/query.go
@@ -173,33 +173,30 @@ func (t *Transaction) QueryCallback(args QueryOptions) (QuerySeq2, error) {
}
jsonMode = m
}
- jsonHasher := func(string, string) string {
+ jsonHasher := func(string) string {
return ""
}
isChecksum := false
- requiredChecksum := len(AllowedFields) + 2
+ to := 1
switch jsonMode {
case output.JSONModes.Raw:
- jsonHasher = func(val, _ string) string {
+ jsonHasher = func(val string) string {
return val
}
case output.JSONModes.Hash:
- isChecksum = args.Values == JSONValue
- hashLength, err := config.EnvJSONHashLength.Get()
+ length, err := config.EnvJSONHashLength.Get()
if err != nil {
return nil, err
}
- l := int(hashLength)
- jsonHasher = func(val, path string) string {
- data := fmt.Sprintf("%x", sha512.Sum512([]byte(val+path)))
- if hashLength > 0 && len(data) > l {
- data = data[0:hashLength]
- }
- return data
+ to = max(int(length), to)
+ isChecksum = args.Values == JSONValue
+ jsonHasher = func(val string) string {
+ return fmt.Sprintf("%x", sha512.Sum512([]byte(val)))
}
}
+ requiredChecksum := (len(AllowedFields) + 2) * to
type checksummable struct {
- value byte
+ value string
typeof byte
}
return func(yield func(Entity, error) bool) {
@@ -218,9 +215,11 @@ func (t *Transaction) QueryCallback(args QueryOptions) (QuerySeq2, error) {
}
val = v.Value.Content
raw = val
- switch args.Values {
- case JSONValue:
- val = jsonHasher(val, entity.Path)
+ if !isChecksum {
+ switch args.Values {
+ case JSONValue:
+ val = jsonHasher(val)
+ }
}
}
if key == modTimeKey || key == titleKey {
@@ -228,25 +227,26 @@ func (t *Transaction) QueryCallback(args QueryOptions) (QuerySeq2, error) {
}
field := strings.ToLower(key)
if isChecksum {
- if r := jsonHasher(raw, ""); len(r) > 0 {
- checksums = append(checksums, checksummable{r[0], field[0]})
+ if r := jsonHasher(raw); len(r) > 0 {
+ checksums = append(checksums, checksummable{r[0:to], field[0]})
}
+ continue
}
values[field] = val
}
if isChecksum {
var check string
if len(checksums) > 0 {
- checksums = append(checksums, checksummable{jsonHasher(entity.Path, "")[0], byte('d')})
+ checksums = append(checksums, checksummable{jsonHasher(entity.Path)[0:to], byte('d')})
slices.SortFunc(checksums, func(x, y checksummable) int {
return int(x.typeof) - int(y.typeof)
})
var vals []string
for _, item := range checksums {
- vals = append(vals, fmt.Sprintf("%s%s", string(item.value), string(item.typeof)))
+ vals = append(vals, fmt.Sprintf("%s%s", item.value, string(item.typeof)))
}
for len(vals) < requiredChecksum {
- vals = append([]string{"00"}, vals...)
+ vals = append([]string{"0" + strings.Repeat("0", to)}, vals...)
}
check = fmt.Sprintf("[%s]", strings.Join(vals, " "))
}
diff --git a/internal/kdbx/query_test.go b/internal/kdbx/query_test.go
@@ -156,13 +156,11 @@ func TestValueModes(t *testing.T) {
Path: "test/test/abc",
Values: map[string]string{
"checksum": "[00 00 00 bd 9n 4p]",
- "notes": "164f7d1c788400c54db852f5f1ef4629e4d0020a87e935dfd643dc4f765dfd201ce43b2b2ec23ff8f5b966ed15715f79d276d4ededf05691197096bb4247d665",
- "password": "a3ea1c021135a8070c62a3a1080d9cd3385ebca45687636ba87c9abd1f5c2d68b17d68e72dc22461d0c8fc371573c568664e98fbfb832fcdda000318211b9538",
},
}) {
t.Errorf("invalid entity: %v", q)
}
- store.SetInt64("LOCKBOX_JSON_HASH_LENGTH", 10)
+ store.SetInt64("LOCKBOX_JSON_HASH_LENGTH", 5)
q, err = fullSetup(t, true).Get("test/test/abc", kdbx.JSONValue)
if err != nil {
t.Errorf("no error: %v", err)
@@ -170,9 +168,7 @@ func TestValueModes(t *testing.T) {
if !compareEntity(q, kdbx.Entity{
Path: "test/test/abc",
Values: map[string]string{
- "checksum": "[00 00 00 bd 9n 4p]",
- "notes": "164f7d1c78",
- "password": "a3ea1c0211",
+ "checksum": "[000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 b00d0d 9057fn 44276p]",
},
}) {
t.Errorf("invalid entity: %v", q)
@@ -332,7 +328,7 @@ func TestAttributeModes(t *testing.T) {
}) {
t.Errorf("invalid entity: %v", q)
}
- store.SetInt64("LOCKBOX_JSON_HASH_LENGTH", 10)
+ store.SetInt64("LOCKBOX_JSON_HASH_LENGTH", 4)
q, err = fullSetup(t, true).Get("test/test/totp", kdbx.JSONValue)
if err != nil {
t.Errorf("no error: %v", err)
@@ -340,7 +336,7 @@ func TestAttributeModes(t *testing.T) {
if !compareEntity(q, kdbx.Entity{
Path: "test/test/totp",
Values: map[string]string{
- "checksum": "[00 00 00 00 ed 7o]",
+ "checksum": "[00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 ef10d 7f8fo]",
"otp": "cb9c99a3ba",
},
}) {