commit 6aca128594765319aaba8e45f4b71c8e09ff0d27
parent d69ae80d8b1d166cd2cc85ce295d0a5cdbc70681
Author: Sean Enck <sean@ttypty.com>
Date: Wed, 4 Feb 2026 16:33:54 -0500
generate fields
Diffstat:
10 files changed, 88 insertions(+), 27 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,2 +1,3 @@
target/
testdata
+internal/kdbx/fields.go
diff --git a/Makefile b/Makefile
@@ -14,6 +14,7 @@ setup:
@test -d $(TARGET) || mkdir -p $(TARGET)
$(OBJECT):
+ go generate ./...
GOOS=$(GOOS) GOARCH=$(GOARCH) go build $(GOFLAGS) -ldflags "$(LDFLAGS) -X main.version=$(VERSION)" -o "$(OBJECT)" $(CMD)/main.go
unittest:
diff --git a/internal/app/help/core.go b/internal/app/help/core.go
@@ -127,14 +127,10 @@ func Usage(verbose bool, exe string) ([]string, error) {
document.Config.XDG = config.ConfigXDG
document.ReKey.KeyFile = setDocFlag(commands.ReKeyFlags.KeyFile)
document.ReKey.NoKey = commands.ReKeyFlags.NoKey
- var fields []string
- for _, field := range kdbx.AllowedFields {
- fields = append(fields, strings.ToLower(field))
- }
- document.Database.Fields = strings.Join(fields, ", ")
+ document.Database.Fields = strings.Join(kdbx.AllFieldsLower, ", ")
var examples []string
for _, example := range []string{commands.Insert, commands.Show} {
- for _, field := range fields {
+ for _, field := range kdbx.AllFieldsLower {
examples = append(examples, fmt.Sprintf("%s %s my/path/%s", document.Executable, example, field))
}
}
diff --git a/internal/app/insert.go b/internal/app/insert.go
@@ -21,7 +21,7 @@ func Insert(cmd UserInputOptions) error {
}
entry := args[0]
base := kdbx.Base(entry)
- if !slices.ContainsFunc(kdbx.AllowedFields, func(v string) bool {
+ if !slices.ContainsFunc(kdbx.AllFields, func(v string) bool {
return base == strings.ToLower(v)
}) {
return fmt.Errorf("'%s' is not an allowed field name", base)
diff --git a/internal/app/list.go b/internal/app/list.go
@@ -57,10 +57,7 @@ func doList(attr, filter string, cmd CommandOptions, mode ListMode) error {
isFields := mode == ListFieldsMode
var allowedFields []string
if isFields {
- allowedFields = make([]string, len(kdbx.AllowedFields))
- for idx, item := range kdbx.AllowedFields {
- allowedFields[idx] = strings.ToLower(item)
- }
+ allowedFields = kdbx.AllFieldsLower
}
isGroups := mode == ListGroupsMode || isFields
for f, err := range e {
diff --git a/internal/kdbx/actions.go b/internal/kdbx/actions.go
@@ -208,7 +208,7 @@ func (t *Transaction) Move(moves ...MoveRequest) error {
values := make(map[string]string)
for k, v := range move.Source.Values {
found := false
- for _, mapping := range AllowedFields {
+ for _, mapping := range AllFields {
if strings.EqualFold(k, mapping) {
values[mapping] = v
found = true
diff --git a/internal/kdbx/core.go b/internal/kdbx/core.go
@@ -14,23 +14,13 @@ import (
"github.com/tobischo/gokeepasslib/v3/wrappers"
)
-var (
- errPath = errors.New("input paths must contain at LEAST 2 components (excluding field)")
- // AllowedFields are the same of allowed names for storing in a kdbx entry
- AllowedFields = []string{NotesField, OTPField, "Password", URLField}
-)
+var errPath = errors.New("input paths must contain at LEAST 2 components (excluding field)")
const (
checksumKey = "checksum"
titleKey = "Title"
pathSep = "/"
modTimeKey = "ModTime"
- // OTPField is the totp storage attribute
- OTPField = "otp"
- // NotesField is the multiline notes key
- NotesField = "Notes"
- // URLField is a non-secret (in terms of input) entry field
- URLField = "URL"
)
type (
diff --git a/internal/kdbx/core_test.go b/internal/kdbx/core_test.go
@@ -11,13 +11,16 @@ import (
)
func TestAllowedSort(t *testing.T) {
- set := fmt.Sprintf("%v", kdbx.AllowedFields)
- have := kdbx.AllowedFields
+ testSorted(kdbx.AllFields, fmt.Sprintf("%v", kdbx.AllFields), t)
+ testSorted(kdbx.AllFieldsLower, fmt.Sprintf("%v", kdbx.AllFieldsLower), t)
+}
+
+func testSorted(have []string, set string, t *testing.T) {
slices.SortFunc(have, func(x, y string) int {
return strings.Compare(strings.ToLower(x), strings.ToLower(y))
})
if fmt.Sprintf("%v", have) != set {
- t.Error("allowed fields has incorrect sort")
+ t.Errorf("allowed fields has incorrect sort: %v", set)
}
}
diff --git a/internal/kdbx/hasher.go b/internal/kdbx/hasher.go
@@ -58,7 +58,7 @@ func NewHasher(mode ValueMode) (*Hasher, error) {
}
obj.checksumTo = max(int(length), obj.checksumTo)
}
- obj.requiredLength = (len(AllowedFields) + 2) * obj.checksumTo
+ obj.requiredLength = (len(AllFields) + 2) * obj.checksumTo
return obj, nil
}
diff --git a/tools/kdbx.go b/tools/kdbx.go
@@ -0,0 +1,73 @@
+//go:generate go run kdbx.go
+package main
+
+import (
+ "os"
+ "path/filepath"
+ "slices"
+ "strings"
+ "text/template"
+)
+
+var items = map[string]string{"Password": "", "OTP": "otp", "Notes": "", "URL": ""}
+
+const fileTemplate = `// Package kdbx requires fields for kdbx handling
+// Code generated by generator; DO NOT EDIT.
+package kdbx
+
+const (
+{{- range . }}
+ // {{ .Variable }} is the value of '{{ .Value }}' for kdbx files
+ {{ .Variable }} = "{{ .Value }}"
+{{- end }}
+)
+
+var (
+ // AllFields are the kdbx fields
+ AllFields = []string{
+ {{- range . }}
+ {{ .Variable }},
+ {{- end }}
+ }
+
+ // AllFieldsLower are the kdbx fields lowercase
+ AllFieldsLower = []string{
+ {{- range . }}
+ "{{ .Lower }}",
+ {{- end }}
+ }
+)
+`
+
+type Item struct {
+ Variable string
+ Value string
+ Lower string
+}
+
+func main() {
+ var data []Item
+ for k, v := range items {
+ value := v
+ if value == "" {
+ value = k
+ }
+ data = append(data, Item{
+ Variable: k + "Field",
+ Value: value,
+ Lower: strings.ToLower(value),
+ })
+ }
+ slices.SortFunc(data, func(x, y Item) int {
+ return strings.Compare(x.Lower, y.Lower)
+ })
+
+ f, err := os.Create(filepath.Join("..", "internal", "kdbx", "fields.go"))
+ if err != nil {
+ panic(err)
+ }
+ defer f.Close()
+
+ tmpl := template.Must(template.New("gen").Parse(fileTemplate))
+ tmpl.Execute(f, data)
+}