lockbox

password manager
Log | Files | Refs | README | LICENSE

commit 2c1b44750cec31c186e830c037b308d009c2fb9b
parent 15f8a410c7d3847051f827e286f72d757f40292b
Author: Sean Enck <sean@ttypty.com>
Date:   Thu, 30 Mar 2023 20:11:24 -0400

stats has been replaced by json

Diffstat:
Mcmd/main.go | 4++--
Minternal/app/conv.go | 22+++++++++++++++++-----
Ainternal/app/json.go | 29+++++++++++++++++++++++++++++
Ainternal/app/json_test.go | 34++++++++++++++++++++++++++++++++++
Minternal/app/rekey.go | 54++++++++++++++++++------------------------------------
Minternal/app/rekey_test.go | 48++++++++++++++----------------------------------
Dinternal/app/stats.go | 26--------------------------
Dinternal/app/stats_test.go | 30------------------------------
Minternal/backend/query.go | 9+--------
Minternal/backend/query_test.go | 53+++++++++++++++++++++--------------------------------
Minternal/backend/types.go | 9+++------
Minternal/cli/completions.bash | 2+-
Minternal/cli/core.go | 12++++++------
Mtests/expected.log | 68++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mtests/run.sh | 7+++++--
15 files changed, 201 insertions(+), 206 deletions(-)

diff --git a/cmd/main.go b/cmd/main.go @@ -84,8 +84,8 @@ func run() error { return app.Insert(p, mode) case cli.RemoveCommand: return app.Remove(p) - case cli.StatsCommand: - return app.Stats(p) + case cli.JSONCommand: + return app.JSON(p) case cli.ShowCommand, cli.ClipCommand: return app.ShowClip(p, command == cli.ShowCommand) case cli.ConvCommand: diff --git a/internal/app/conv.go b/internal/app/conv.go @@ -3,7 +3,7 @@ package app import ( "errors" "fmt" - "strings" + "io" "github.com/enckse/lockbox/internal/backend" ) @@ -20,13 +20,25 @@ func Conv(cmd CommandOptions) error { if err != nil { return err } - e, err := t.QueryCallback(backend.QueryOptions{Mode: backend.ListMode, Values: backend.HashedValue}) - if err != nil { + if err := serialize(w, t); err != nil { return err } - for _, item := range e { - fmt.Fprintf(w, "%s:\n %s\n\n", item.Path, strings.ReplaceAll(item.Value, "\n", "\n ")) + } + return nil +} + +func serialize(w io.Writer, tx *backend.Transaction) error { + e, err := tx.QueryCallback(backend.QueryOptions{Mode: backend.ListMode, Values: backend.JSONValue}) + if err != nil { + return err + } + fmt.Fprintf(w, "[") + for idx, item := range e { + if idx > 0 { + fmt.Fprint(w, ",") } + fmt.Fprintf(w, "\n%s\n", item.Value) } + fmt.Fprintf(w, "]") return nil } diff --git a/internal/app/json.go b/internal/app/json.go @@ -0,0 +1,29 @@ +// Package app can get stats +package app + +import ( + "errors" + "fmt" + + "github.com/enckse/lockbox/internal/backend" +) + +// JSON will get entries (1 or ALL) in JSON format +func JSON(cmd CommandOptions) error { + args := cmd.Args() + if len(args) > 1 { + return errors.New("invalid arguments") + } + if len(args) == 0 { + return serialize(cmd.Writer(), cmd.Transaction()) + } + entry := args[0] + v, err := cmd.Transaction().Get(entry, backend.JSONValue) + if err != nil { + return fmt.Errorf("unable to get stats: %w", err) + } + if v != nil { + fmt.Fprintln(cmd.Writer(), v.Value) + } + return nil +} diff --git a/internal/app/json_test.go b/internal/app/json_test.go @@ -0,0 +1,34 @@ +package app_test + +import ( + "bytes" + "testing" + + "github.com/enckse/lockbox/internal/app" +) + +func TestJSON(t *testing.T) { + m := newMockCommand(t) + if err := app.JSON(m); err != nil { + t.Errorf("invalid error: %v", err) + } + m.args = []string{"test", "test2"} + if err := app.JSON(m); err.Error() != "invalid arguments" { + t.Errorf("invalid error: %v", err) + } + m.args = []string{"test/test2/test1"} + if err := app.JSON(m); err != nil { + t.Errorf("invalid error: %v", err) + } + if m.buf.String() == "" { + t.Error("no stats") + } + m.buf = bytes.Buffer{} + m.args = []string{"tsest/test2/test1"} + if err := app.JSON(m); err != nil { + t.Errorf("invalid error: %v", err) + } + if m.buf.String() != "" { + t.Error("no stats") + } +} diff --git a/internal/app/rekey.go b/internal/app/rekey.go @@ -1,6 +1,7 @@ package app import ( + "encoding/json" "errors" "fmt" "io" @@ -16,8 +17,7 @@ import ( type ( // Keyer defines how rekeying happens Keyer interface { - List() ([]string, error) - Stats(string) ([]string, error) + JSON() ([]backend.JSON, error) Show(string) ([]byte, error) Insert(ReKeyEntry) error } @@ -42,27 +42,22 @@ func NewDefaultKeyer() (DefaultKeyer, error) { return DefaultKeyer{exe: exe}, nil } -// List will get the list of keys in the store -func (r DefaultKeyer) List() ([]string, error) { - return r.getCommandLines(cli.ListCommand) -} - -// Stats will get stats for an entry -func (r DefaultKeyer) Stats(entry string) ([]string, error) { - return r.getCommandLines(cli.StatsCommand, entry) +// Show will get entry payload +func (r DefaultKeyer) Show(entry string) ([]byte, error) { + return exec.Command(r.exe, cli.ShowCommand, entry).Output() } -func (r DefaultKeyer) getCommandLines(args ...string) ([]string, error) { - out, err := exec.Command(r.exe, args...).Output() +// JSON will get the JSON backing entries +func (r DefaultKeyer) JSON() ([]backend.JSON, error) { + out, err := exec.Command(r.exe, cli.JSONCommand).Output() if err != nil { return nil, err } - return strings.Split(strings.TrimSpace(string(out)), "\n"), nil -} - -// Show will get entry payload -func (r DefaultKeyer) Show(entry string) ([]byte, error) { - return exec.Command(r.exe, cli.ShowCommand, entry).Output() + var j []backend.JSON + if err := json.Unmarshal(out, &j); err != nil { + return nil, err + } + return j, nil } // Insert will insert the rekeying entry @@ -88,39 +83,26 @@ func ReKey(writer io.Writer, r Keyer) error { if err != nil { return err } - entries, err := r.List() + entries, err := r.JSON() if err != nil { return err } for _, entry := range entries { - if _, err := fmt.Fprintf(writer, "rekeying: %s\n", entry); err != nil { + if _, err := fmt.Fprintf(writer, "rekeying: %s\n", entry.Path); err != nil { return err } - stats, err := r.Stats(entry) - if err != nil { - return fmt.Errorf("failed to get modtime, command failed: %w", err) - } - modTime := "" - for _, stat := range stats { - if strings.HasPrefix(stat, backend.ModTimeField) { - if modTime != "" { - return errors.New("unable to read modtime, too many values") - } - modTime = strings.TrimPrefix(stat, backend.ModTimeField) - } - } - modTime = strings.TrimSpace(modTime) + modTime := strings.TrimSpace(entry.ModTime) if modTime == "" { return errors.New("did not read modtime") } - data, err := r.Show(entry) + data, err := r.Show(entry.Path) if err != nil { return err } var insertEnv []string insertEnv = append(insertEnv, env...) insertEnv = append(insertEnv, fmt.Sprintf("%s=%s", inputs.ModTimeEnv, modTime)) - if err := r.Insert(ReKeyEntry{Path: entry, Env: insertEnv, Data: data}); err != nil { + if err := r.Insert(ReKeyEntry{Path: entry.Path, Env: insertEnv, Data: data}); err != nil { return err } } diff --git a/internal/app/rekey_test.go b/internal/app/rekey_test.go @@ -8,23 +8,23 @@ import ( "testing" "github.com/enckse/lockbox/internal/app" + "github.com/enckse/lockbox/internal/backend" ) type ( mockKeyer struct { - entries []string - data map[string][]byte - stats map[string][]string - err error - rekeys []app.ReKeyEntry + data map[string][]byte + err error + rekeys []app.ReKeyEntry + items []backend.JSON } ) -func (m *mockKeyer) List() ([]string, error) { +func (m *mockKeyer) JSON() ([]backend.JSON, error) { if m.err != nil { return nil, m.err } - return m.entries, nil + return m.items, nil } func (m *mockKeyer) Show(entry string) ([]byte, error) { @@ -35,14 +35,6 @@ func (m *mockKeyer) Show(entry string) ([]byte, error) { return val, nil } -func (m *mockKeyer) Stats(entry string) ([]string, error) { - val, ok := m.stats[entry] - if !ok { - return nil, errors.New("no stats") - } - return val, nil -} - func (m *mockKeyer) Insert(entry app.ReKeyEntry) error { m.rekeys = append(m.rekeys, entry) if entry.Path == "error" { @@ -60,32 +52,23 @@ func TestErrors(t *testing.T) { setupReKey() var buf bytes.Buffer m := &mockKeyer{} - m.err = errors.New("invalid ls") - if err := app.ReKey(&buf, m); err == nil || err.Error() != "invalid ls" { + m.err = errors.New("invalid call") + if err := app.ReKey(&buf, m); err == nil || err.Error() != "invalid call" { t.Errorf("invalid error: %v", err) } m.err = nil - m.entries = []string{"test1", "error"} - if err := app.ReKey(&buf, m); err == nil || err.Error() != "failed to get modtime, command failed: no stats" { - t.Errorf("invalid error: %v", err) - } - m.stats = make(map[string][]string) - m.stats["test1"] = []string{"modtime"} - m.stats["error"] = []string{"modtime: 3"} + m.items = []backend.JSON{{Path: "test1", ModTime: ""}} if err := app.ReKey(&buf, m); err == nil || err.Error() != "did not read modtime" { t.Errorf("invalid error: %v", err) } - m.stats["test1"] = []string{"modtime: 1", "modtime: 2"} - if err := app.ReKey(&buf, m); err == nil || err.Error() != "unable to read modtime, too many values" { - t.Errorf("invalid error: %v", err) - } - m.stats["test1"] = []string{"modtime: 1"} + m.items = []backend.JSON{{Path: "test1", ModTime: "2"}} if err := app.ReKey(&buf, m); err == nil || err.Error() != "no data" { t.Errorf("invalid error: %v", err) } m.data = make(map[string][]byte) m.data["test1"] = []byte{1} m.data["error"] = []byte{2} + m.items = []backend.JSON{{Path: "error", ModTime: "2"}} if err := app.ReKey(&buf, m); err == nil || err.Error() != "bad insert" { t.Errorf("invalid error: %v", err) } @@ -101,13 +84,10 @@ func TestReKey(t *testing.T) { t.Error("no data") } m := &mockKeyer{} - m.entries = []string{"test1", "test2"} + m.items = []backend.JSON{{Path: "test1", ModTime: "2"}, {Path: "test1", ModTime: "2"}} m.data = make(map[string][]byte) m.data["test1"] = []byte{1} m.data["test2"] = []byte{2} - m.stats = make(map[string][]string) - m.stats["test1"] = []string{"modtime: 1", "modtime2"} - m.stats["test2"] = []string{"moime: 1", "modtime: 2"} if err := app.ReKey(&buf, m); err != nil { t.Errorf("invalid error: %v", err) } @@ -117,7 +97,7 @@ func TestReKey(t *testing.T) { if len(m.rekeys) != 2 { t.Error("invalid rekeys") } - if fmt.Sprintf("%v", m.rekeys) != `[{test1 [LOCKBOX_KEYMODE= LOCKBOX_KEY=abc LOCKBOX_KEYFILE= LOCKBOX_STORE=store LOCKBOX_SET_MODTIME=1] [1]} {test2 [LOCKBOX_KEYMODE= LOCKBOX_KEY=abc LOCKBOX_KEYFILE= LOCKBOX_STORE=store LOCKBOX_SET_MODTIME=2] [2]}]` { + if fmt.Sprintf("%v", m.rekeys) != `[{test1 [LOCKBOX_KEYMODE= LOCKBOX_KEY=abc LOCKBOX_KEYFILE= LOCKBOX_STORE=store LOCKBOX_SET_MODTIME=2] [1]} {test1 [LOCKBOX_KEYMODE= LOCKBOX_KEY=abc LOCKBOX_KEYFILE= LOCKBOX_STORE=store LOCKBOX_SET_MODTIME=2] [1]}]` { t.Errorf("invalid results: %v", m.rekeys) } } diff --git a/internal/app/stats.go b/internal/app/stats.go @@ -1,26 +0,0 @@ -// Package app can get stats -package app - -import ( - "errors" - "fmt" - - "github.com/enckse/lockbox/internal/backend" -) - -// Stats will retrieve entry stats -func Stats(cmd CommandOptions) error { - args := cmd.Args() - if len(args) != 1 { - return errors.New("entry required") - } - entry := args[0] - v, err := cmd.Transaction().Get(entry, backend.StatsValue) - if err != nil { - return fmt.Errorf("unable to get stats: %w", err) - } - if v != nil { - fmt.Fprintln(cmd.Writer(), v.Value) - } - return nil -} diff --git a/internal/app/stats_test.go b/internal/app/stats_test.go @@ -1,30 +0,0 @@ -package app_test - -import ( - "bytes" - "testing" - - "github.com/enckse/lockbox/internal/app" -) - -func TestStats(t *testing.T) { - m := newMockCommand(t) - if err := app.Stats(m); err.Error() != "entry required" { - t.Errorf("invalid error: %v", err) - } - m.args = []string{"test/test2/test1"} - if err := app.Stats(m); err != nil { - t.Errorf("invalid error: %v", err) - } - if m.buf.String() == "" { - t.Error("no stats") - } - m.buf = bytes.Buffer{} - m.args = []string{"tsest/test2/test1"} - if err := app.Stats(m); err != nil { - t.Errorf("invalid error: %v", err) - } - if m.buf.String() != "" { - t.Error("no stats") - } -} diff --git a/internal/backend/query.go b/internal/backend/query.go @@ -132,7 +132,7 @@ func (t *Transaction) QueryCallback(args QueryOptions) ([]QueryEntity, error) { switch args.Values { case JSONValue: t := getValue(e.backing, modTimeKey) - s := JSON{Path: k, ModTime: t} + s := JSON{Path: k, ModTime: t, Hash: fmt.Sprintf("%x", sha512.Sum512([]byte(val)))} m, err := json.MarshalIndent(s, "", " ") if err != nil { return nil, err @@ -140,13 +140,6 @@ func (t *Transaction) QueryCallback(args QueryOptions) ([]QueryEntity, error) { entity.Value = string(m) case SecretValue: entity.Value = val - case HashedValue, StatsValue: - t := getValue(e.backing, modTimeKey) - res := fmt.Sprintf("%s %s", ModTimeField, t) - if args.Values == HashedValue { - res = fmt.Sprintf("%s\nhash: %x", res, sha512.Sum512([]byte(val))) - } - entity.Value = res } } results = append(results, entity) diff --git a/internal/backend/query_test.go b/internal/backend/query_test.go @@ -2,7 +2,6 @@ package backend_test import ( "encoding/json" - "fmt" "os" "strings" "testing" @@ -83,21 +82,19 @@ func TestValueModes(t *testing.T) { if q.Value != "" { t.Errorf("invalid result value: %s", q.Value) } - q, err = fullSetup(t, true).Get("test/test/abc", backend.HashedValue) + q, err = fullSetup(t, true).Get("test/test/abc", backend.JSONValue) if err != nil { t.Errorf("no error: %v", err) } - hash := strings.TrimSpace(q.Value) - parts := strings.Split(hash, "\n") - if len(parts) != 2 { - t.Errorf("invalid hash output: %v", parts) + m := backend.JSON{} + if err := json.Unmarshal([]byte(q.Value), &m); err != nil { + t.Errorf("no error: %v", err) } - if parts[1] != "hash: 44276ba24db13df5568aa6db81e0190ab9d35d2168dce43dca61e628f5c666b1d8b091f1dda59c2359c86e7d393d59723a421d58496d279031e7f858c11d893e" { + if m.Hash != "44276ba24db13df5568aa6db81e0190ab9d35d2168dce43dca61e628f5c666b1d8b091f1dda59c2359c86e7d393d59723a421d58496d279031e7f858c11d893e" { t.Errorf("invalid result value: %s", q.Value) } - dt := parts[0] - if !strings.HasPrefix(dt, "modtime: ") || len(dt) <= 20 { - t.Errorf("invalid date/time: %s", dt) + if len(m.ModTime) < 20 { + t.Errorf("invalid date/time") } q, err = fullSetup(t, true).Get("test/test/ab11c", backend.SecretValue) if err != nil { @@ -106,19 +103,15 @@ func TestValueModes(t *testing.T) { if q.Value != "tdest\ntest" { t.Errorf("invalid result value: %s", q.Value) } - q, err = fullSetup(t, true).Get("test/test/abc", backend.StatsValue) - if err != nil || !strings.HasPrefix(q.Value, "modtime: ") || len(strings.Split(q.Value, "\n")) != 1 { - t.Errorf("invalid stats: %s", q.Value) - } q, err = fullSetup(t, true).Get("test/test/abc", backend.JSONValue) if err != nil { t.Errorf("no error: %v", err) } - m := backend.JSON{} + m = backend.JSON{} if err := json.Unmarshal([]byte(q.Value), &m); err != nil { t.Errorf("no error: %v", err) } - if strings.TrimSpace(m.ModTime) == "" || m.Path != "test/test/abc" { + if len(m.ModTime) < 20 || m.Path != "test/test/abc" { t.Errorf("invalid json: %v", m) } } @@ -208,35 +201,31 @@ func TestSetModTime(t *testing.T) { tr := fullSetup(t, false) os.Setenv("LOCKBOX_SET_MODTIME", testDateTime) tr.Insert("test/xyz", "test") - q, err := fullSetup(t, true).Get("test/xyz", backend.HashedValue) + q, err := fullSetup(t, true).Get("test/xyz", backend.JSONValue) if err != nil { t.Errorf("no error: %v", err) } - hash := strings.TrimSpace(q.Value) - parts := strings.Split(hash, "\n") - if len(parts) != 2 { - t.Errorf("invalid hash output: %v", parts) + m := backend.JSON{} + if err := json.Unmarshal([]byte(q.Value), &m); err != nil { + t.Errorf("no error: %v", err) } - dt := parts[0] - if dt != fmt.Sprintf("modtime: %s", testDateTime) { - t.Errorf("invalid date/time: %s", dt) + if m.ModTime != testDateTime { + t.Errorf("invalid date/time") } tr = fullSetup(t, false) os.Setenv("LOCKBOX_SET_MODTIME", "") tr.Insert("test/xyz", "test") - q, err = fullSetup(t, true).Get("test/xyz", backend.HashedValue) + q, err = fullSetup(t, true).Get("test/xyz", backend.JSONValue) if err != nil { t.Errorf("no error: %v", err) } - hash = strings.TrimSpace(q.Value) - parts = strings.Split(hash, "\n") - if len(parts) != 2 { - t.Errorf("invalid hash output: %v", parts) + m = backend.JSON{} + if err := json.Unmarshal([]byte(q.Value), &m); err != nil { + t.Errorf("no error: %v", err) } - dt = parts[0] - if dt == fmt.Sprintf("modtime: %s", testDateTime) { - t.Errorf("invalid date/time: %s", dt) + if m.ModTime == testDateTime { + t.Errorf("invalid date/time") } tr = fullSetup(t, false) diff --git a/internal/backend/types.go b/internal/backend/types.go @@ -55,8 +55,9 @@ type ( } // JSON is an entry as a JSON string JSON struct { - ModTime string `json:"modtime"` Path string `json:"path"` + ModTime string `json:"modtime"` + Hash string `json:"hash"` } ) @@ -90,12 +91,8 @@ const ( const ( // BlankValue will not decrypt secrets, empty value BlankValue ValueMode = iota - // HashedValue will decrypt and then hash the password - HashedValue // SecretValue will have the raw secret onboard SecretValue - // StatsValue will show the last modification time - StatsValue // JSONValue will show entries as a JSON payload JSONValue ) @@ -107,7 +104,7 @@ const ( pathSep = "/" isGlob = pathSep + "*" modTimeKey = "ModTime" - // ModTimeField is the stats field for modification time + // ModTimeField is the field for modification time ModTimeField = "modtime:" ) diff --git a/internal/cli/completions.bash b/internal/cli/completions.bash @@ -31,7 +31,7 @@ _{{ $.Executable }}() { {{- end}} ;; {{- end}} - "{{ $.ShowCommand }}" | "{{ $.StatsCommand }}" {{ if not $.ReadOnly }}| "{{ $.RemoveCommand }}" {{end}} {{ if $.CanClip }} | "{{ $.ClipCommand }}" {{end}}) + "{{ $.ShowCommand }}" | "{{ $.JSONCommand }}" {{ if not $.ReadOnly }}| "{{ $.RemoveCommand }}" {{end}} {{ if $.CanClip }} | "{{ $.ClipCommand }}" {{end}}) opts=$({{ $.DoList }}) ;; esac diff --git a/internal/cli/core.go b/internal/cli/core.go @@ -15,8 +15,6 @@ import ( ) const ( - // StatsCommand will display additional entry stat information - StatsCommand = "stats" // TOTPCommand is the parent of totp and by defaults generates a rotating token TOTPCommand = "totp" // ConvCommand handles text conversion of the data store @@ -67,6 +65,8 @@ const ( TOTPShowCommand = ShowCommand // TOTPInsertCommand is for inserting totp tokens TOTPInsertCommand = InsertCommand + // JSONCommand handles JSON outputs + JSONCommand = "json" ) var ( @@ -96,7 +96,7 @@ type ( DoTOTPList string DoList string Executable string - StatsCommand string + JSONCommand string HelpCommand string HelpAdvancedCommand string } @@ -141,14 +141,14 @@ func BashCompletions(defaults bool) ([]string, error) { ClipCommand: ClipCommand, ShowCommand: ShowCommand, MultiLineCommand: MultiLineCommand, - StatsCommand: StatsCommand, + JSONCommand: JSONCommand, HelpCommand: HelpCommand, HelpAdvancedCommand: HelpAdvancedCommand, TOTPCommand: TOTPCommand, MoveCommand: MoveCommand, DoList: fmt.Sprintf("%s %s", name, ListCommand), DoTOTPList: fmt.Sprintf("%s %s %s", name, TOTPCommand, TOTPListCommand), - Options: []string{MultiLineCommand, EnvCommand, HelpCommand, ListCommand, ShowCommand, VersionCommand, StatsCommand}, + Options: []string{MultiLineCommand, EnvCommand, HelpCommand, ListCommand, ShowCommand, VersionCommand, JSONCommand}, } isReadOnly := false isClip := true @@ -213,12 +213,12 @@ func Usage(verbose bool) ([]string, error) { results = append(results, command(HelpCommand, "", "show this usage information")) results = append(results, subCommand(HelpCommand, HelpAdvancedCommand, "", "display verbose help information")) results = append(results, command(InsertCommand, "entry", "insert a new entry into the store")) + results = append(results, command(JSONCommand, "", "display detailed information")) results = append(results, command(ListCommand, "", "list entries")) results = append(results, command(MoveCommand, "src dst", "move an entry from source to destination")) results = append(results, command(MultiLineCommand, "entry", "insert a multiline entry into the store")) results = append(results, command(RemoveCommand, "entry", "remove an entry from the store")) results = append(results, command(ShowCommand, "entry", "show the entry's value")) - results = append(results, command(StatsCommand, "entry", "display entry detail information")) results = append(results, command(TOTPCommand, "entry", "display an updating totp generated code")) results = append(results, subCommand(TOTPCommand, TOTPClipCommand, "entry", "copy totp code to clipboard")) results = append(results, subCommand(TOTPCommand, TOTPInsertCommand, "entry", "insert a new totp entry into the store")) diff --git a/tests/expected.log b/tests/expected.log @@ -12,31 +12,63 @@ keys2/k/three key/a/one keys/k/one2 keys2/k/three +[ +{ + "path": "key/a/one", + "modtime": "XXXX-XX-XX", + "hash": "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff" +} +, +{ + "path": "keys/k/one2", + "modtime": "XXXX-XX-XX", + "hash": "6d201beeefb589b08ef0672dac82353d0cbd9ad99e1642c83a1601f3d647bcca003257b5e8f31bdc1d73fbec84fb085c79d6e2677b7ff927e823a54e789140d9" +} +, +{ + "path": "keys2/k/three", + "modtime": "XXXX-XX-XX", + "hash": "132ab0244293c495a027cec12d0050598616daca888449920fc652719be0987830827d069ef78cc613e348de37c9b592d3406e2fb8d99a6961bf0c58da8a334f" +} +] test2 test3 test4 -modtime: XXXX-XX-XX +{ + "path": "keys2/k/three", + "modtime": "XXXX-XX-XX", + "hash": "132ab0244293c495a027cec12d0050598616daca888449920fc652719be0987830827d069ef78cc613e348de37c9b592d3406e2fb8d99a6961bf0c58da8a334f" +} + test/k XXXXXX XXXXXX XXXXXX -key/a/one: - modtime: XXXX-XX-XX - hash: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff - -keys/k/one2: - modtime: XXXX-XX-XX - hash: 6d201beeefb589b08ef0672dac82353d0cbd9ad99e1642c83a1601f3d647bcca003257b5e8f31bdc1d73fbec84fb085c79d6e2677b7ff927e823a54e789140d9 - -keys2/k/three: - modtime: XXXX-XX-XX - hash: 132ab0244293c495a027cec12d0050598616daca888449920fc652719be0987830827d069ef78cc613e348de37c9b592d3406e2fb8d99a6961bf0c58da8a334f - -test/k/totp: - modtime: XXXX-XX-XX - hash: 7ef183065ba70aaa417b87ea0a96b7e550a938a52440c640a07537f7794d8a89e50078eca6a7cbcfacabd97a2db06d11e82ddf7556ca909c4df9fc0d006013b1 - -delete entry? (y/N) +[ +{ + "path": "key/a/one", + "modtime": "XXXX-XX-XX", + "hash": "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff" +} +, +{ + "path": "keys/k/one2", + "modtime": "XXXX-XX-XX", + "hash": "6d201beeefb589b08ef0672dac82353d0cbd9ad99e1642c83a1601f3d647bcca003257b5e8f31bdc1d73fbec84fb085c79d6e2677b7ff927e823a54e789140d9" +} +, +{ + "path": "keys2/k/three", + "modtime": "XXXX-XX-XX", + "hash": "132ab0244293c495a027cec12d0050598616daca888449920fc652719be0987830827d069ef78cc613e348de37c9b592d3406e2fb8d99a6961bf0c58da8a334f" +} +, +{ + "path": "test/k/totp", + "modtime": "XXXX-XX-XX", + "hash": "7ef183065ba70aaa417b87ea0a96b7e550a938a52440c640a07537f7794d8a89e50078eca6a7cbcfacabd97a2db06d11e82ddf7556ca909c4df9fc0d006013b1" +} +]delete entry? (y/N) delete entry? (y/N) delete entry? (y/N) unable to remove: no entities given diff --git a/tests/run.sh b/tests/run.sh @@ -28,9 +28,12 @@ _execute() { echo ${LB_BINARY} ls ${LB_BINARY} ls | grep e + ${LB_BINARY} json + echo ${LB_BINARY} show keys/k/one2 ${LB_BINARY} show keys2/k/three - ${LB_BINARY} stats keys2/k/three + ${LB_BINARY} json keys2/k/three + echo echo 5ae472abqdekjqykoyxk7hvc2leklq5n |${LB_BINARY} totp insert test/k echo 5ae472abqdekjqykoyxk7hvc2leklq5n |${LB_BINARY} totp insert test/k/totp ${LB_BINARY} totp ls @@ -121,7 +124,7 @@ _clipboard() { _logtest() { _execute 2>&1 | \ - sed 's/modtime: [0-9].*$/modtime: XXXX-XX-XX/g' | \ + sed 's/"modtime": "[0-9].*$/"modtime": "XXXX-XX-XX",/g' | \ sed 's/^[0-9][0-9][0-9][0-9][0-9][0-9]$/XXXXXX/g' }