commit aee4561166ec184eb93e87188ea5354d22bea6d8
parent 03474c5cdfe847ff9540afc64b335a53cf90e2ed
Author: Sean Enck <sean@ttypty.com>
Date: Sat, 1 Oct 2022 11:38:56 -0400
working through remaining bugs
Diffstat:
5 files changed, 52 insertions(+), 33 deletions(-)
diff --git a/cmd/main.go b/cmd/main.go
@@ -128,7 +128,7 @@ func run() *programError {
return newError("invalid input", err)
}
p := strings.TrimSpace(string(password))
- if err := t.Insert(entry, p, len(strings.Split(p, "\n")) > 1); err != nil {
+ if err := t.Insert(entry, p, existing, len(strings.Split(p, "\n")) > 1); err != nil {
return newError("failed to insert", err)
}
fmt.Println("")
diff --git a/internal/backend/query.go b/internal/backend/query.go
@@ -76,7 +76,8 @@ func (t *Transaction) QueryCallback(args QueryOptions) ([]QueryEntity, error) {
var keys []string
entities := make(map[string]QueryEntity)
isSort := args.Mode == ListMode || args.Mode == FindMode || args.Mode == SuffixMode
- err := t.Act(func(ctx Context) error {
+ decrypt := args.Values != BlankValue
+ err := t.act(func(ctx Context) error {
for idx, entry := range ctx.db.Content.Root.Groups[0].Entries {
path := getPathName(entry)
if isSort {
@@ -101,6 +102,9 @@ func (t *Transaction) QueryCallback(args QueryOptions) ([]QueryEntity, error) {
keys = append(keys, path)
entities[path] = QueryEntity{backing: entry, Index: idx}
}
+ if decrypt {
+ return ctx.db.UnlockProtectedEntries()
+ }
return nil
})
if err != nil {
@@ -110,12 +114,6 @@ func (t *Transaction) QueryCallback(args QueryOptions) ([]QueryEntity, error) {
sort.Strings(keys)
}
var results []QueryEntity
- decrypt := args.Values != BlankValue
- if decrypt {
- if err := t.db.UnlockProtectedEntries(); err != nil {
- return nil, err
- }
- }
for _, k := range keys {
entity := QueryEntity{Path: k}
if args.Values != BlankValue {
@@ -129,7 +127,7 @@ func (t *Transaction) QueryCallback(args QueryOptions) ([]QueryEntity, error) {
case SecretValue:
entity.Value = val
case HashedValue:
- entity.Value = fmt.Sprintf("%x", sha512.New().Sum([]byte(val)))
+ entity.Value = fmt.Sprintf("%x", sha512.Sum512([]byte(val)))
}
}
results = append(results, entity)
diff --git a/internal/backend/transact.go b/internal/backend/transact.go
@@ -20,19 +20,22 @@ const (
)
type (
- Action func(t Context) error
+ // action are transcation operations that more or less CRUD the kdbx file
+ action func(t Context) error
+ // Transaction handles the overall operation of the transaction
Transaction struct {
valid bool
file string
exists bool
- db *gokeepasslib.Database
write bool
}
+ // Context handles operating on the underlying database
Context struct {
db *gokeepasslib.Database
}
)
+// Load will load a kdbx file for transactions
func Load(file string) (*Transaction, error) {
return loadFile(file, true)
}
@@ -50,6 +53,7 @@ func loadFile(file string, must bool) (*Transaction, error) {
return &Transaction{valid: true, file: file, exists: exists}, nil
}
+// NewTransaction will use the underlying environment data store location
func NewTransaction() (*Transaction, error) {
return loadFile(os.Getenv(inputs.StoreEnv), false)
}
@@ -75,7 +79,7 @@ func encode(f *os.File, db *gokeepasslib.Database) error {
return gokeepasslib.NewEncoder(f).Encode(db)
}
-func (t *Transaction) Act(cb Action) error {
+func (t *Transaction) act(cb action) error {
if !t.valid {
return errors.New("invalid transaction")
}
@@ -102,10 +106,9 @@ func (t *Transaction) Act(cb Action) error {
if len(db.Content.Root.Groups) != 1 {
return errors.New("kdbx must only have ONE root group")
}
- t.db = db
- cErr := cb(Context{db: t.db})
+ cErr := cb(Context{db: db})
if t.write {
- if err := t.db.LockProtectedEntries(); err != nil {
+ if err := db.LockProtectedEntries(); err != nil {
return err
}
if err := f.Close(); err != nil {
@@ -116,13 +119,13 @@ func (t *Transaction) Act(cb Action) error {
return err
}
defer f.Close()
- return encode(f, t.db)
+ return encode(f, db)
}
return cErr
}
-func (t *Transaction) change(cb Action) error {
- return t.Act(func(c Context) error {
+func (t *Transaction) change(cb action) error {
+ return t.act(func(c Context) error {
if err := c.db.UnlockProtectedEntries(); err != nil {
return err
}
@@ -131,8 +134,14 @@ func (t *Transaction) change(cb Action) error {
})
}
-func (t *Transaction) Insert(path, val string, multi bool) error {
+// Insert handles inserting a new element
+func (t *Transaction) Insert(path, val string, entity *QueryEntity, multi bool) error {
return t.change(func(c Context) error {
+ if entity != nil {
+ if err := remove(entity, c); err != nil {
+ return err
+ }
+ }
e := gokeepasslib.NewEntry()
e.Values = append(e.Values, value(titleKey, filepath.Dir(path)))
e.Values = append(e.Values, value(userNameKey, filepath.Base(path)))
@@ -147,22 +156,27 @@ func (t *Transaction) Insert(path, val string, multi bool) error {
})
}
+func remove(entity *QueryEntity, c Context) error {
+ entries := c.db.Content.Root.Groups[0].Entries
+ if entity.Index >= len(entries) {
+ return errors.New("index out of bounds")
+ }
+ e := entries[entity.Index]
+ n := getPathName(e)
+ if n != entity.Path {
+ return errors.New("validation failed, index/name mismatch")
+ }
+ c.db.Content.Root.Groups[0].Entries = append(entries[:entity.Index], entries[entity.Index+1:]...)
+ return nil
+}
+
+// Remove handles remove an element
func (t *Transaction) Remove(entity *QueryEntity) error {
if entity == nil {
return errors.New("entity is empty/invalid")
}
return t.change(func(c Context) error {
- entries := c.db.Content.Root.Groups[0].Entries
- if entity.Index >= len(entries) {
- return errors.New("index out of bounds")
- }
- e := entries[entity.Index]
- n := getPathName(e)
- if n != entity.Path {
- return errors.New("validation failed, index/name mismatch")
- }
- c.db.Content.Root.Groups[0].Entries = append(entries[:entity.Index], entries[entity.Index+1:]...)
- return nil
+ return remove(entity, c)
})
}
diff --git a/tests/expected.log b/tests/expected.log
@@ -1,12 +1,15 @@
+
keys/one
keys/one2
keys2/three
delete entry? (y/N)
+keys/one
keys/one2
keys2/three
+keys/one
keys/one2
keys2/three
test2
@@ -15,11 +18,13 @@ test4
test/totp
XXXXXX
+keys/one:
+hash:ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff
keys/one2:
-hash:7465737432cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
+hash:6d201beeefb589b08ef0672dac82353d0cbd9ad99e1642c83a1601f3d647bcca003257b5e8f31bdc1d73fbec84fb085c79d6e2677b7ff927e823a54e789140d9
keys2/three:
-hash:74657374330a7465737434cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
+hash:132ab0244293c495a027cec12d0050598616daca888449920fc652719be0987830827d069ef78cc613e348de37c9b592d3406e2fb8d99a6961bf0c58da8a334f
test/totp:
-hash:35616534373261627164656b6a71796b6f79786b37687663326c656b6c71356ecf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
+hash:7ef183065ba70aaa417b87ea0a96b7e550a938a52440c640a07537f7794d8a89e50078eca6a7cbcfacabd97a2db06d11e82ddf7556ca909c4df9fc0d006013b1
delete entry? (y/N)
delete entry? (y/N)
\ No newline at end of file
diff --git a/tests/run.sh b/tests/run.sh
@@ -14,6 +14,7 @@ mkdir -p $TESTS
_run() {
echo "test" | "$BIN/lb" insert keys/one
echo "test2" | "$BIN/lb" insert keys/one2
+ echo "test" | "$BIN/lb" insert keys/one
echo -e "test3\ntest4" | "$BIN/lb" insert keys2/three
"$BIN/lb" ls
yes 2>/dev/null | "$BIN/lb" rm keys/one
@@ -29,6 +30,7 @@ _run() {
yes 2>/dev/null | "$BIN/lb" rm keys2/three
echo
yes 2>/dev/null | "$BIN/lb" rm test/totp
+ yes 2>/dev/null | "$BIN/lb" rm test/one
}
_run 2>&1 | sed "s#$LOCKBOX_STORE##g" > $TESTS/actual.log