commit 28ee0359ea885cec6d882f86f343de7c6a9c63cd
parent 63e8c229fcafad3564f515d4ac8d183c2495b59a
Author: Sean Enck <sean@ttypty.com>
Date: Fri, 16 Aug 2024 18:41:14 -0400
switch from QueryEntity to a TransactionEntity for transactions
Diffstat:
6 files changed, 65 insertions(+), 29 deletions(-)
diff --git a/internal/app/move.go b/internal/app/move.go
@@ -98,5 +98,5 @@ func (r moveRequest) do(dryRun bool) error {
if dryRun {
return nil
}
- return tx.Move(*srcExists, r.dst)
+ return tx.Move(srcExists.Transaction(), r.dst)
}
diff --git a/internal/app/remove.go b/internal/app/remove.go
@@ -4,6 +4,8 @@ package app
import (
"errors"
"fmt"
+
+ "github.com/seanenck/lockbox/internal/backend"
)
// Remove will remove an entry
@@ -32,7 +34,14 @@ func Remove(cmd CommandOptions) error {
fmt.Fprintln(w, "")
}
if cmd.Confirm(fmt.Sprintf("delete entr%s", postfixRemove)) {
- if err := t.RemoveAll(existings); err != nil {
+ removals := func() []backend.TransactionEntity {
+ var tx []backend.TransactionEntity
+ for _, e := range existings {
+ tx = append(tx, e.Transaction())
+ }
+ return tx
+ }()
+ if err := t.RemoveAll(removals); err != nil {
return fmt.Errorf("unable to remove: %w", err)
}
}
diff --git a/internal/backend/actions.go b/internal/backend/actions.go
@@ -182,11 +182,11 @@ func findAndDo(isAdd bool, entityName string, offset []string, opEntity *gokeepa
}
// Move will move a src object to a dst location
-func (t *Transaction) Move(src QueryEntity, dst string) error {
- if strings.TrimSpace(src.Path) == "" {
+func (t *Transaction) Move(src TransactionEntity, dst string) error {
+ if strings.TrimSpace(src.path) == "" {
return errors.New("empty path not allowed")
}
- if strings.TrimSpace(src.Value) == "" {
+ if strings.TrimSpace(src.value) == "" {
return errors.New("empty secret not allowed")
}
mod := config.EnvModTime.Get()
@@ -202,22 +202,22 @@ func (t *Transaction) Move(src QueryEntity, dst string) error {
if err != nil {
return err
}
- sOffset, sTitle, err := splitComponents(src.Path)
+ sOffset, sTitle, err := splitComponents(src.path)
if err != nil {
return err
}
action := MoveAction
- if dst == src.Path {
+ if dst == src.path {
action = InsertAction
}
- hook, err := NewHook(src.Path, action)
+ hook, err := NewHook(src.path, action)
if err != nil {
return err
}
if err := hook.Run(HookPre); err != nil {
return err
}
- multi := len(strings.Split(strings.TrimSpace(src.Value), "\n")) > 1
+ multi := len(strings.Split(strings.TrimSpace(src.value), "\n")) > 1
err = t.change(func(c Context) error {
c.removeEntity(sOffset, sTitle)
if action == MoveAction {
@@ -229,7 +229,7 @@ func (t *Transaction) Move(src QueryEntity, dst string) error {
if multi {
field = notesKey
}
- v := src.Value
+ v := src.value
ok, err := isTOTP(dTitle)
if err != nil {
return err
@@ -254,19 +254,19 @@ func (t *Transaction) Move(src QueryEntity, dst string) error {
// Insert is a move to the same location
func (t *Transaction) Insert(path, val string) error {
- return t.Move(QueryEntity{Path: path, Value: val}, path)
+ return t.Move(TransactionEntity{path: path, value: val}, path)
}
// Remove will remove a single entity
-func (t *Transaction) Remove(entity *QueryEntity) error {
+func (t *Transaction) Remove(entity *TransactionEntity) error {
if entity == nil {
return errors.New("entity is empty/invalid")
}
- return t.RemoveAll([]QueryEntity{*entity})
+ return t.RemoveAll([]TransactionEntity{*entity})
}
// RemoveAll handles removing elements
-func (t *Transaction) RemoveAll(entities []QueryEntity) error {
+func (t *Transaction) RemoveAll(entities []TransactionEntity) error {
if len(entities) == 0 {
return errors.New("no entities given")
}
@@ -278,11 +278,11 @@ func (t *Transaction) RemoveAll(entities []QueryEntity) error {
removals := []removal{}
hasHooks := false
for _, entity := range entities {
- offset, title, err := splitComponents(entity.Path)
+ offset, title, err := splitComponents(entity.path)
if err != nil {
return err
}
- hook, err := NewHook(entity.Path, RemoveAction)
+ hook, err := NewHook(entity.path, RemoveAction)
if err != nil {
return err
}
diff --git a/internal/backend/actions_test.go b/internal/backend/actions_test.go
@@ -97,7 +97,7 @@ func TestMove(t *testing.T) {
setup(t)
fullSetup(t, true).Insert(backend.NewPath("test", "test2", "test1"), "pass")
fullSetup(t, true).Insert(backend.NewPath("test", "test2", "test3"), "pass")
- if err := fullSetup(t, true).Move(backend.QueryEntity{Path: backend.NewPath("test", "test2", "test3"), Value: "abc"}, backend.NewPath("test1", "test2", "test3")); err != nil {
+ if err := fullSetup(t, true).Move(backend.QueryEntity{Path: backend.NewPath("test", "test2", "test3"), Value: "abc"}.Transaction(), backend.NewPath("test1", "test2", "test3")); err != nil {
t.Errorf("no error: %v", err)
}
q, err := fullSetup(t, true).Get(backend.NewPath("test1", "test2", "test3"), backend.SecretValue)
@@ -107,7 +107,7 @@ func TestMove(t *testing.T) {
if q.Value != "abc" {
t.Errorf("invalid retrieval")
}
- if err := fullSetup(t, true).Move(backend.QueryEntity{Path: backend.NewPath("test", "test2", "test1"), Value: "test"}, backend.NewPath("test1", "test2", "test3")); err != nil {
+ if err := fullSetup(t, true).Move(backend.QueryEntity{Path: backend.NewPath("test", "test2", "test1"), Value: "test"}.Transaction(), backend.NewPath("test1", "test2", "test3")); err != nil {
t.Errorf("no error: %v", err)
}
q, err = fullSetup(t, true).Get(backend.NewPath("test1", "test2", "test3"), backend.SecretValue)
@@ -176,54 +176,62 @@ func TestRemoves(t *testing.T) {
if err := setup(t).Remove(nil); err.Error() != "entity is empty/invalid" {
t.Errorf("wrong error: %v", err)
}
- if err := setup(t).Remove(&backend.QueryEntity{}); err.Error() != "input paths must contain at LEAST 2 components" {
+ if err := setup(t).Remove(&backend.TransactionEntity{}); err.Error() != "input paths must contain at LEAST 2 components" {
t.Errorf("wrong error: %v", err)
}
- if err := setup(t).Remove(&backend.QueryEntity{Path: backend.NewPath("test1", "test2", "test3")}); err.Error() != "failed to remove entity" {
+ tx := backend.QueryEntity{Path: backend.NewPath("test1", "test2", "test3")}.Transaction()
+ if err := setup(t).Remove(&tx); err.Error() != "failed to remove entity" {
t.Errorf("wrong error: %v", err)
}
setup(t)
for _, i := range []string{"test1", "test2"} {
fullSetup(t, true).Insert(backend.NewPath(i, i, i), "pass")
}
- if err := fullSetup(t, true).Remove(&backend.QueryEntity{Path: backend.NewPath("test1", "test1", "test1")}); err != nil {
+ tx = backend.QueryEntity{Path: backend.NewPath("test1", "test1", "test1")}.Transaction()
+ if err := fullSetup(t, true).Remove(&tx); err != nil {
t.Errorf("wrong error: %v", err)
}
if err := check(t, backend.NewPath("test2", "test2", "test2")); err != nil {
t.Errorf("invalid check: %v", err)
}
- if err := fullSetup(t, true).Remove(&backend.QueryEntity{Path: backend.NewPath("test2", "test2", "test2")}); err != nil {
+ tx = backend.QueryEntity{Path: backend.NewPath("test2", "test2", "test2")}.Transaction()
+ if err := fullSetup(t, true).Remove(&tx); err != nil {
t.Errorf("wrong error: %v", err)
}
setup(t)
for _, i := range []string{backend.NewPath("test", "test", "test1"), backend.NewPath("test", "test", "test2"), backend.NewPath("test", "test", "test3"), backend.NewPath("test", "test1", "test2"), backend.NewPath("test", "test1", "test5")} {
fullSetup(t, true).Insert(i, "pass")
}
- if err := fullSetup(t, true).Remove(&backend.QueryEntity{Path: "test/test/test3"}); err != nil {
+ tx = backend.QueryEntity{Path: "test/test/test3"}.Transaction()
+ if err := fullSetup(t, true).Remove(&tx); err != nil {
t.Errorf("wrong error: %v", err)
}
if err := check(t, backend.NewPath("test", "test", "test2"), backend.NewPath("test", "test", "test1"), backend.NewPath("test", "test1", "test2"), backend.NewPath("test", "test1", "test5")); err != nil {
t.Errorf("invalid check: %v", err)
}
- if err := fullSetup(t, true).Remove(&backend.QueryEntity{Path: "test/test/test1"}); err != nil {
+ tx = backend.QueryEntity{Path: "test/test/test1"}.Transaction()
+ if err := fullSetup(t, true).Remove(&tx); err != nil {
t.Errorf("wrong error: %v", err)
}
if err := check(t, backend.NewPath("test", "test", "test2"), backend.NewPath("test", "test1", "test2"), backend.NewPath("test", "test1", "test5")); err != nil {
t.Errorf("invalid check: %v", err)
}
- if err := fullSetup(t, true).Remove(&backend.QueryEntity{Path: "test/test1/test5"}); err != nil {
+ tx = backend.QueryEntity{Path: "test/test1/test5"}.Transaction()
+ if err := fullSetup(t, true).Remove(&tx); err != nil {
t.Errorf("wrong error: %v", err)
}
if err := check(t, backend.NewPath("test", "test", "test2"), backend.NewPath("test", "test1", "test2")); err != nil {
t.Errorf("invalid check: %v", err)
}
- if err := fullSetup(t, true).Remove(&backend.QueryEntity{Path: "test/test1/test2"}); err != nil {
+ tx = backend.QueryEntity{Path: "test/test1/test2"}.Transaction()
+ if err := fullSetup(t, true).Remove(&tx); err != nil {
t.Errorf("wrong error: %v", err)
}
if err := check(t, backend.NewPath("test", "test", "test2")); err != nil {
t.Errorf("invalid check: %v", err)
}
- if err := fullSetup(t, true).Remove(&backend.QueryEntity{Path: "test/test/test2"}); err != nil {
+ tx = backend.QueryEntity{Path: "test/test/test2"}.Transaction()
+ if err := fullSetup(t, true).Remove(&tx); err != nil {
t.Errorf("wrong error: %v", err)
}
}
@@ -232,14 +240,14 @@ func TestRemoveAlls(t *testing.T) {
if err := setup(t).RemoveAll(nil); err.Error() != "no entities given" {
t.Errorf("wrong error: %v", err)
}
- if err := setup(t).RemoveAll([]backend.QueryEntity{}); err.Error() != "no entities given" {
+ if err := setup(t).RemoveAll([]backend.TransactionEntity{}); err.Error() != "no entities given" {
t.Errorf("wrong error: %v", err)
}
setup(t)
for _, i := range []string{backend.NewPath("test", "test", "test1"), backend.NewPath("test", "test", "test2"), backend.NewPath("test", "test", "test3"), backend.NewPath("test", "test1", "test2"), backend.NewPath("test", "test1", "test5")} {
fullSetup(t, true).Insert(i, "pass")
}
- if err := fullSetup(t, true).RemoveAll([]backend.QueryEntity{{Path: "test/test/test3"}, {Path: "test/test/test1"}}); err != nil {
+ if err := fullSetup(t, true).RemoveAll([]backend.TransactionEntity{backend.QueryEntity{Path: "test/test/test3"}.Transaction(), backend.QueryEntity{Path: "test/test/test1"}.Transaction()}); err != nil {
t.Errorf("wrong error: %v", err)
}
if err := check(t, backend.NewPath("test", "test", "test2"), backend.NewPath("test", "test1", "test2"), backend.NewPath("test", "test1", "test5")); err != nil {
diff --git a/internal/backend/core.go b/internal/backend/core.go
@@ -43,8 +43,18 @@ type (
Value string
backing gokeepasslib.Entry
}
+ // TransactionEntity objects alter the database entities
+ TransactionEntity struct {
+ path string
+ value string
+ }
)
+// Transaction will convert a query entity to a transaction entity
+func (e QueryEntity) Transaction() TransactionEntity {
+ return TransactionEntity{path: e.Path, value: e.Value}
+}
+
// Load will load a kdbx file for transactions
func Load(file string) (*Transaction, error) {
return loadFile(file, true)
diff --git a/internal/backend/core_test.go b/internal/backend/core_test.go
@@ -1,6 +1,7 @@
package backend_test
import (
+ "fmt"
"testing"
"github.com/seanenck/lockbox/internal/backend"
@@ -30,6 +31,14 @@ func TestIsDirectory(t *testing.T) {
}
}
+func TestQueryToTransaction(t *testing.T) {
+ q := backend.QueryEntity{Path: "abc", Value: "xyz"}
+ tx := q.Transaction()
+ if fmt.Sprintf("%v", tx) != "{abc xyz}" {
+ t.Errorf("invalid transaction: %v", tx)
+ }
+}
+
func TestBase(t *testing.T) {
b := backend.Base("")
if b != "" {