commit ceecd65a687989792b00142dcceac15d3f67c541
parent 8d33a511c1e08acddf0350bbe807818367b4b172
Author: Sean Enck <sean@ttypty.com>
Date: Sat, 10 Aug 2024 20:19:54 -0400
rewrite rekey to use a database credential switch
Diffstat:
13 files changed, 173 insertions(+), 311 deletions(-)
diff --git a/cmd/main.go b/cmd/main.go
@@ -97,11 +97,7 @@ func run() error {
}
switch command {
case app.ReKeyCommand:
- keyer, err := app.NewDefaultKeyer()
- if err != nil {
- return err
- }
- return app.ReKey(p, keyer)
+ return app.ReKey(p)
case app.ListCommand:
return app.List(p)
case app.MoveCommand:
diff --git a/internal/app/core.go b/internal/app/core.go
@@ -106,16 +106,8 @@ type (
CompletionsCommand string
CompletionsEnv string
ReKey struct {
- Store string
- KeyFile string
- Key string
- KeyMode string
- ModMode string
- ModModes struct {
- Skip string
- Error string
- None string
- }
+ KeyFile string
+ NoKey string
}
}
)
@@ -169,6 +161,16 @@ func (a *DefaultCommand) IsPipe() bool {
return platform.IsInputFromPipe()
}
+// ReadLine handles a single stdin read
+func (a DefaultCommand) ReadLine() (string, error) {
+ return platform.Stdin(true)
+}
+
+// Password is how a keyer gets the user's password for rekey
+func (a DefaultCommand) Password() (string, error) {
+ return platform.ReadInteractivePassword()
+}
+
// Input will read user input
func (a *DefaultCommand) Input(pipe, multi bool) ([]byte, error) {
return platform.GetUserInputPassword(pipe, multi)
@@ -229,14 +231,8 @@ func Usage(verbose bool, exe string) ([]string, error) {
CompletionsCommand: CompletionsCommand,
CompletionsEnv: config.EnvDefaultCompletionKey,
}
- document.ReKey.Store = setDocFlag(config.ReKeyStoreFlag)
- document.ReKey.Key = setDocFlag(config.ReKeyKeyFlag)
- document.ReKey.KeyMode = setDocFlag(config.ReKeyKeyModeFlag)
- document.ReKey.KeyFile = setDocFlag(config.ReKeyKeyModeFlag)
- document.ReKey.ModMode = setDocFlag(config.ReKeyModModeFlag)
- document.ReKey.ModModes.None = config.ReKeyModModeNone
- document.ReKey.ModModes.Skip = config.ReKeyModModeSkip
- document.ReKey.ModModes.Error = config.ReKeyModModeError
+ document.ReKey.KeyFile = setDocFlag(config.ReKeyKeyFileFlag)
+ document.ReKey.NoKey = config.ReKeyNoKeyFlag
files, err := docs.ReadDir(docDir)
if err != nil {
return nil, err
diff --git a/internal/app/core_test.go b/internal/app/core_test.go
@@ -13,7 +13,7 @@ func TestUsage(t *testing.T) {
t.Errorf("invalid usage, out of date? %d", len(u))
}
u, _ = app.Usage(true, "lb")
- if len(u) != 109 {
+ if len(u) != 106 {
t.Errorf("invalid verbose usage, out of date? %d", len(u))
}
for _, usage := range u {
diff --git a/internal/app/doc/rekey.txt b/internal/app/doc/rekey.txt
@@ -1,11 +1,6 @@
The password store can have the key (and file) changed via the '{{ $.ReKeyCommand }}'
-subcommand. This command requires that '{{ $.ReKey.Store }}' is set and
-a combination of new key settings are configured via '{{ $.ReKey.Key }}', '{{ $.ReKey.KeyMode }}', and '{{ $.ReKey.KeyFile }}' depending on the new database
-credential preferences. The settings correspond to the 'LOCKBOX_'
-settings normally used when running `{{ $.Executable }}`. Additionally
-'{{ $.ReKey.ModMode }}' can be set to `{{ $.ReKey.ModModes.Skip }}` to skip
-modtime issues, `{{ $.ReKey.ModModes.None }}` to disable modtime imports, or
-`{{ $.ReKey.ModModes.Error }}` to ignore missing modification times (the
-default).
+subcommand. This command requires that a combination of new key
+settings are configured via user input (unless `{{ $.ReKey.NoKey }}` is set) and '{{ $.ReKey.KeyFile }}'
+depending on the new database credential preferences.
Note that is an advanced feature and should be used with caution/backups/etc.
diff --git a/internal/app/rekey.go b/internal/app/rekey.go
@@ -1,118 +1,71 @@
package app
import (
- "encoding/json"
"errors"
"fmt"
- "os"
- "os/exec"
- "strings"
- "github.com/seanenck/lockbox/internal/backend"
"github.com/seanenck/lockbox/internal/config"
)
type (
- // Keyer defines how rekeying happens
- Keyer interface {
- JSON() (map[string]backend.JSON, error)
- Insert(ReKeyEntry) error
- }
- // ReKeyEntry is an entry that is being rekeyed
- ReKeyEntry struct {
- Path string
- Env []string
- Data []byte
- }
- // DefaultKeyer is the default keyer for the application
- DefaultKeyer struct {
- exe string
+ // KeyerOptions defines how rekeying happens
+ KeyerOptions interface {
+ CommandOptions
+ IsPipe() bool
+ Password() (string, error)
+ ReadLine() (string, error)
}
)
-// NewDefaultKeyer initializes the default keyer
-func NewDefaultKeyer() (DefaultKeyer, error) {
- exe, err := os.Executable()
- if err != nil {
- return DefaultKeyer{}, err
+func getNewPassword(pipe bool, against string, r KeyerOptions) (string, error) {
+ if pipe {
+ val, err := r.ReadLine()
+ if err != nil {
+ return "", err
+ }
+ return val, nil
}
- return DefaultKeyer{exe: exe}, nil
-}
-
-// JSON will get the JSON backing entries
-func (r DefaultKeyer) JSON() (map[string]backend.JSON, error) {
- out, err := exec.Command(r.exe, JSONCommand).Output()
+ fmt.Print("new ")
+ p, err := r.Password()
if err != nil {
- return nil, err
- }
- var j map[string]backend.JSON
- if err := json.Unmarshal(out, &j); err != nil {
- return nil, err
+ return "", err
}
- return j, nil
-}
-
-// Insert will insert the rekeying entry
-func (r DefaultKeyer) Insert(entry ReKeyEntry) error {
- cmd := exec.Command(r.exe, InsertCommand, entry.Path)
- cmd.Env = append(os.Environ(), entry.Env...)
- in, err := cmd.StdinPipe()
- if nil != err {
- return err
+ if against != "" {
+ if p != against {
+ return "", errors.New("rekey passwords do not match")
+ }
}
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- go func() {
- defer in.Close()
- in.Write(entry.Data)
- }()
- return cmd.Run()
+ return p, nil
}
// ReKey handles entry rekeying
-func ReKey(cmd CommandOptions, r Keyer) error {
+func ReKey(cmd KeyerOptions) error {
args := cmd.Args()
vars, err := config.GetReKey(args)
if err != nil {
return err
}
- if !cmd.Confirm("proceed with rekey") {
- return nil
- }
- if err := config.EnvJSONDataOutput.Set(string(config.JSONDataOutputRaw)); err != nil {
- return err
- }
- entries, err := r.JSON()
- if err != nil {
- return err
+ piping := cmd.IsPipe()
+ if !piping {
+ if !cmd.Confirm("proceed with rekey") {
+ return nil
+ }
}
- writer := cmd.Writer()
- for path, entry := range entries {
- if _, err := fmt.Fprintf(writer, "rekeying: %s\n", path); err != nil {
+ var pass string
+ if !vars.NoKey {
+ first, err := getNewPassword(piping, "", cmd)
+ if err != nil {
return err
}
- var modTime string
- if vars.ModMode != config.ReKeyModModeNone {
- modTime = strings.TrimSpace(entry.ModTime)
- if modTime == "" {
- switch vars.ModMode {
- case config.ReKeyModModeSkip:
- case config.ReKeyModModeError:
- return errors.New("did not read modtime")
- default:
- return errors.New("unknown modtime control")
- }
+ if !piping {
+ if _, err := getNewPassword(piping, first, cmd); err != nil {
+ return err
}
}
-
- var insertEnv []string
- insertEnv = append(insertEnv, vars.Env...)
- if modTime != "" {
- insertEnv = append(insertEnv, config.EnvModTime.KeyValue(modTime))
- }
- if err := r.Insert(ReKeyEntry{Path: path, Env: insertEnv, Data: []byte(entry.Data)}); err != nil {
- return err
+ pass = first
+ if pass == "" {
+ return errors.New("password required but not given")
}
}
- return nil
+ return cmd.Transaction().ReKey(pass, vars.KeyFile)
}
diff --git a/internal/app/rekey_test.go b/internal/app/rekey_test.go
@@ -2,9 +2,7 @@ package app_test
import (
"bytes"
- "errors"
- "fmt"
- "strings"
+ "io"
"testing"
"github.com/seanenck/lockbox/internal/app"
@@ -13,142 +11,77 @@ import (
type (
mockKeyer struct {
- data map[string][]byte
- err error
- items map[string]backend.JSON
- rekeys [][]string
+ pass string
+ secondPass string
+ confirm bool
+ args []string
+ buf bytes.Buffer
+ t *testing.T
+ pipe bool
}
)
-func (m *mockKeyer) JSON() (map[string]backend.JSON, error) {
- if m.err != nil {
- return nil, m.err
- }
- return m.items, nil
+func (m *mockKeyer) Confirm(string) bool {
+ return m.confirm
}
-func (m *mockKeyer) Insert(entry app.ReKeyEntry) error {
- m.rekeys = append(m.rekeys, entry.Env)
- if entry.Path == "error" {
- return errors.New("bad insert")
- }
- return nil
+func (m *mockKeyer) Transaction() *backend.Transaction {
+ return fullSetup(m.t, true)
}
-func TestErrors(t *testing.T) {
- cmd := &mockCommand{}
- cmd.confirm = false
- cmd.buf = bytes.Buffer{}
- m := &mockKeyer{}
- cmd.args = []string{"-store", "store", "-key", "abc"}
- if err := app.ReKey(cmd, m); err != nil {
- t.Errorf("invalid error: %v", err)
- }
- cmd.confirm = true
- m.err = errors.New("invalid call")
- if err := app.ReKey(cmd, m); err == nil || err.Error() != "invalid call" {
- t.Errorf("invalid error: %v", err)
- }
- m.err = nil
- m.items = map[string]backend.JSON{"test": {ModTime: ""}}
- if err := app.ReKey(cmd, m); err == nil || err.Error() != "did not read modtime" {
- t.Errorf("invalid error: %v", err)
- }
- m.data = make(map[string][]byte)
- m.data["test1"] = []byte{1}
- m.data["error"] = []byte{2}
- m.items = map[string]backend.JSON{"error": {ModTime: "2"}}
- if err := app.ReKey(cmd, m); err == nil || err.Error() != "bad insert" {
- t.Errorf("invalid error: %v", err)
- }
+func (m *mockKeyer) Args() []string {
+ return m.args
+}
+
+func (m *mockKeyer) ReadLine() (string, error) {
+ return m.Password()
+}
+
+func (m *mockKeyer) Password() (string, error) {
+ p := m.pass
+ m.pass = m.secondPass
+ m.secondPass = ""
+ return p, nil
+}
+
+func (m *mockKeyer) IsPipe() bool {
+ return m.pipe
+}
+
+func (m *mockKeyer) Writer() io.Writer {
+ return &m.buf
}
func TestReKey(t *testing.T) {
- cmd := &mockCommand{}
- cmd.confirm = true
- cmd.buf = bytes.Buffer{}
- cmd.args = []string{"-store", "store", "-key", "abc"}
- if err := app.ReKey(cmd, &mockKeyer{}); err != nil {
+ newMockCommand(t)
+ mock := &mockKeyer{}
+ if err := app.ReKey(mock); err != nil {
t.Errorf("invalid error: %v", err)
}
- if cmd.buf.String() != "" {
- t.Error("no data")
- }
- m := &mockKeyer{}
- m.items = map[string]backend.JSON{
- "test1": {ModTime: "1"},
- "test2": {ModTime: "2"},
- }
- m.data = make(map[string][]byte)
- m.data["test1"] = []byte{1}
- m.data["test2"] = []byte{2}
- cmd.buf = bytes.Buffer{}
- if err := app.ReKey(cmd, m); err != nil {
+ mock.confirm = true
+ if err := app.ReKey(mock); err == nil || err.Error() != "password required but not given" {
t.Errorf("invalid error: %v", err)
}
- if cmd.buf.String() == "" {
- t.Error("invalid data")
- }
- if len(m.rekeys) != 2 {
- t.Errorf("invalid results")
- }
- obj := fmt.Sprintf("%v", m.rekeys)
- for _, idx := range []int{1, 2} {
- if !strings.Contains(obj, fmt.Sprintf("LOCKBOX_SET_MODTIME=%d", idx)) {
- t.Errorf("missing converted modtime: %s", obj)
- }
- }
-}
-
-func modTimeKey(t *testing.T, mode string, modSet int) {
- cmd := &mockCommand{}
- cmd.confirm = true
- cmd.buf = bytes.Buffer{}
- cmd.args = []string{"-store", "store", "-key", "abc"}
- m := &mockKeyer{}
- m.items = map[string]backend.JSON{
- "test1": {ModTime: "1"},
- "test2": {ModTime: ""},
- }
- m.data = make(map[string][]byte)
- m.data["test1"] = []byte{1}
- m.data["test2"] = []byte{2}
- cmd.buf = bytes.Buffer{}
- cmd.args = []string{"-store", "store", "-key", "abc", "-modtime", mode}
- if err := app.ReKey(cmd, m); err != nil {
+ mock.pass = "abc"
+ if err := app.ReKey(mock); err == nil || err.Error() != "rekey passwords do not match" {
t.Errorf("invalid error: %v", err)
}
- if len(m.rekeys) != 2 {
- t.Errorf("invalid results")
- }
- if strings.Count(fmt.Sprintf("%v", m.rekeys), "LOCKBOX_SET_MODTIME=") != modSet {
- t.Errorf("invalid object: %v", m.rekeys)
+ mock.pass = "xyz"
+ mock.secondPass = "xyz"
+ if err := app.ReKey(mock); err != nil {
+ t.Errorf("invalid error: %v", err)
}
}
-func TestReKeyModTime(t *testing.T) {
- cmd := &mockCommand{}
- cmd.confirm = true
- cmd.buf = bytes.Buffer{}
- cmd.args = []string{"-store", "store", "-key", "abc"}
- m := &mockKeyer{}
- m.items = map[string]backend.JSON{
- "test1": {ModTime: "1"},
- "test3": {ModTime: "a"},
- "test2": {ModTime: ""},
- }
- m.data = make(map[string][]byte)
- m.data["test1"] = []byte{1}
- m.data["test2"] = []byte{2}
- m.data["test3"] = []byte{4}
- cmd.buf = bytes.Buffer{}
- if err := app.ReKey(cmd, m); err == nil || err.Error() != "did not read modtime" {
+func TestReKeyPipe(t *testing.T) {
+ newMockCommand(t)
+ mock := &mockKeyer{}
+ mock.pipe = true
+ if err := app.ReKey(mock); err == nil || err.Error() != "password required but not given" {
t.Errorf("invalid error: %v", err)
}
- cmd.args = []string{"-store", "store", "-key", "abc", "-modtime", "xyz"}
- if err := app.ReKey(cmd, m); err == nil || err.Error() != "unknown modtime setting for import: xyz" {
+ mock.pass = "abc"
+ if err := app.ReKey(mock); err != nil {
t.Errorf("invalid error: %v", err)
}
- modTimeKey(t, "none", 0)
- modTimeKey(t, "skip", 1)
}
diff --git a/internal/backend/actions.go b/internal/backend/actions.go
@@ -83,6 +83,18 @@ func (t *Transaction) act(cb action) error {
return err
}
+// ReKey will change the credentials on a database
+func (t *Transaction) ReKey(pass, keyFile string) error {
+ creds, err := getCredentials(pass, keyFile)
+ if err != nil {
+ return err
+ }
+ return t.change(func(c Context) error {
+ c.db.Credentials = creds
+ return nil
+ })
+}
+
func (t *Transaction) change(cb action) error {
if t.readonly {
return errors.New("unable to alter database in readonly mode")
diff --git a/internal/backend/actions_test.go b/internal/backend/actions_test.go
@@ -300,3 +300,27 @@ func keyAndOrKeyFile(t *testing.T, key, keyFile bool) {
}
}
}
+
+func TestReKey(t *testing.T) {
+ os.Clearenv()
+ f := "rekey_test.kdbx"
+ file := testFile(f)
+ defer os.Remove(filepath.Join(testDir, f))
+ os.Setenv("LOCKBOX_READONLY", "no")
+ os.Setenv("LOCKBOX_STORE", file)
+ os.Setenv("LOCKBOX_KEY", "test")
+ os.Setenv("LOCKBOX_KEYMODE", "plaintext")
+ os.Setenv("LOCKBOX_TOTP", "totp")
+ os.Setenv("LOCKBOX_HOOKDIR", "")
+ os.Setenv("LOCKBOX_SET_MODTIME", "")
+ tr, err := backend.NewTransaction()
+ if err != nil {
+ t.Errorf("failed: %v", err)
+ }
+ if err := tr.ReKey("", ""); err == nil || err.Error() != "key and/or keyfile must be set" {
+ t.Errorf("no error: %v", err)
+ }
+ if err := tr.ReKey("abc", ""); err != nil {
+ t.Errorf("no error: %v", err)
+ }
+}
diff --git a/internal/config/core.go b/internal/config/core.go
@@ -33,27 +33,15 @@ const (
// WindowsLinuxPlatform for WSL subsystems
WindowsLinuxPlatform = "wsl"
unknownPlatform = ""
- // ReKeyStoreFlag is the flag used for rekey to set the store
- ReKeyStoreFlag = "store"
// ReKeyKeyFileFlag is the flag used for rekey to set the keyfile
ReKeyKeyFileFlag = "keyfile"
- // ReKeyKeyFlag is the flag used for rekey to set the key
- ReKeyKeyFlag = "key"
- // ReKeyKeyModeFlag is the flag used for rekey to set the key mode
- ReKeyKeyModeFlag = "keymode"
- // ReKeyModModeFlag indicates how to control modtime inserts
- ReKeyModModeFlag = "modtime"
+ // ReKeyNoKeyFlag indicates no key is used for rekeying (e.g. keyfile only)
+ ReKeyNoKeyFlag = "nokey"
// sub categories
clipCategory keyCategory = "CLIP_"
totpCategory keyCategory = "TOTP_"
// YesValue are yes (on) values
YesValue = yes
- // ReKeyModModeSkip will skip modtime import issues
- ReKeyModModeSkip = "skip"
- // ReKeyModModeNone will not attempt to import modtimes at all
- ReKeyModModeNone = "none"
- // ReKeyModModeError will error on modtime import issues
- ReKeyModModeError = "error"
)
var (
@@ -124,8 +112,8 @@ type (
}
// ReKeyArgs are the arguments for rekeying
ReKeyArgs struct {
- Env []string
- ModMode string
+ NoKey bool
+ KeyFile string
}
)
diff --git a/internal/config/vars.go b/internal/config/vars.go
@@ -2,11 +2,11 @@
package config
import (
+ "errors"
"flag"
"fmt"
"net/url"
"os"
- "slices"
"sort"
"strings"
"time"
@@ -210,40 +210,17 @@ This value can NOT be an expansion itself.`,
// GetReKey will get the rekey environment settings
func GetReKey(args []string) (ReKeyArgs, error) {
set := flag.NewFlagSet("rekey", flag.ExitOnError)
- store := set.String(ReKeyStoreFlag, "", "new store")
- key := set.String(ReKeyKeyFlag, "", "new key")
keyFile := set.String(ReKeyKeyFileFlag, "", "new keyfile")
- keyMode := set.String(ReKeyKeyModeFlag, "", "new keymode")
- modSetting := set.String(ReKeyModModeFlag, ReKeyModModeError, "import setting for modtime")
+ noKey := set.Bool(ReKeyNoKeyFlag, false, "disable password/key credential")
if err := set.Parse(args); err != nil {
return ReKeyArgs{}, err
}
- mod := *modSetting
- if !slices.Contains([]string{ReKeyModModeError, ReKeyModModeSkip, ReKeyModModeNone}, mod) {
- return ReKeyArgs{}, fmt.Errorf("unknown modtime setting for import: %s", mod)
+ noPass := *noKey
+ file := *keyFile
+ if strings.TrimSpace(file) == "" && noPass {
+ return ReKeyArgs{}, errors.New("a key or keyfile must be passed for rekey")
}
- type keyer struct {
- env EnvironmentString
- has bool
- in string
- }
- check := func(in string, e EnvironmentString) keyer {
- val := strings.TrimSpace(in)
- return keyer{has: val != "", env: e, in: in}
- }
- inStore := check(*store, EnvStore)
- inKey := check(*key, envKey)
- inKeyFile := check(*keyFile, EnvKeyFile)
- inKeyMode := check(*keyMode, envKeyMode)
- var out []string
- for _, k := range []keyer{inStore, inKey, inKeyFile, inKeyMode} {
- out = append(out, k.env.KeyValue(k.in))
- }
- if !inStore.has || (!inKey.has && !inKeyFile.has) {
- return ReKeyArgs{}, fmt.Errorf("missing required arguments for rekey:\n -help for information on the flags or the lockbox help documentation for detailed usage")
- }
- sort.Strings(out)
- return ReKeyArgs{Env: out, ModMode: mod}, nil
+ return ReKeyArgs{KeyFile: file, NoKey: noPass}, nil
}
// ListEnvironmentVariables will print information about env variables
diff --git a/internal/config/vars_test.go b/internal/config/vars_test.go
@@ -99,42 +99,23 @@ func TestListVariables(t *testing.T) {
}
func TestReKey(t *testing.T) {
- _, err := config.GetReKey([]string{})
- if err == nil || !strings.HasPrefix(err.Error(), "missing required arguments for rekey") {
+ if _, err := config.GetReKey([]string{"-nokey"}); err == nil || err.Error() != "a key or keyfile must be passed for rekey" {
t.Errorf("failed: %v", err)
}
- _, err = config.GetReKey([]string{"-store", "abc"})
- if err == nil || !strings.HasPrefix(err.Error(), "missing required arguments for rekey") {
- t.Errorf("failed: %v", err)
- }
- _, err = config.GetReKey([]string{"-store", "abc", "-key", "aaa", "-modtime", "xyz"})
- if err == nil || !strings.HasPrefix(err.Error(), "unknown modtime setting for import: xyz") {
- t.Errorf("failed: %v", err)
- }
- out, err := config.GetReKey([]string{"-store", "abc", "-key", "aaa"})
+ out, err := config.GetReKey([]string{})
if err != nil {
t.Errorf("failed: %v", err)
}
- if fmt.Sprintf("%v", out.Env) != "[LOCKBOX_KEY=aaa LOCKBOX_KEYFILE= LOCKBOX_KEYMODE= LOCKBOX_STORE=abc]" {
- t.Errorf("invalid env: %v", out)
- }
- if out.ModMode != "error" {
- t.Errorf("invalid modtime setting: %v", out)
+ if out.NoKey || out.KeyFile != "" {
+ t.Errorf("invalid args: %v", out)
}
- out, err = config.GetReKey([]string{"-store", "abc", "-keyfile", "aaa", "-modtime", "none"})
+ out, err = config.GetReKey([]string{"-keyfile", "vars.go", "-nokey"})
if err != nil {
t.Errorf("failed: %v", err)
}
- if fmt.Sprintf("%v", out.Env) != "[LOCKBOX_KEY= LOCKBOX_KEYFILE=aaa LOCKBOX_KEYMODE= LOCKBOX_STORE=abc]" {
- t.Errorf("invalid env: %v", out)
- }
- if out.ModMode != "none" {
- t.Errorf("invalid modtime setting: %v", out)
+ if !out.NoKey || out.KeyFile != "vars.go" {
+ t.Errorf("invalid args: %v", out)
}
- os.Setenv("LOCKBOX_KEY_NEW", "")
- os.Setenv("LOCKBOX_STORE_NEW", "")
- os.Setenv("LOCKBOX_KEY_NEW", "")
- os.Setenv("LOCKBOX_KEYFILE_NEW", "")
}
func TestFormatTOTP(t *testing.T) {
diff --git a/tests/expected.log b/tests/expected.log
@@ -141,7 +141,6 @@ CALLED
keys/k/one2
-proceed with rekey? (y/N) rekeying: keys/k/one2
keys/k/one2
test2
diff --git a/tests/run.sh b/tests/run.sh
@@ -153,14 +153,22 @@ printf "%-10s ... " "$1"
${LB_BINARY} ls
echo
# rekeying
- REKEY="$LOCKBOX_STORE.rekey.kdbx"
- REKEYFILE=""
+ REKEY_ARGS=""
+ NEWKEY="newkey$1"
export LOCKBOX_HOOKDIR=""
if [ -n "$LOCKBOX_KEYFILE" ]; then
REKEYFILE="$DATA/newkeyfile"
+ REKEY_ARGS="-keyfile $REKEYFILE"
echo "thisisanewkey" > "$REKEYFILE"
+ if [ -z "$LOCKBOX_KEY" ]; then
+ REKEY_ARGS="$REKEY_ARGS -nokey"
+ NEWKEY=""
+ fi
fi
- echo y |${LB_BINARY} rekey -store="$REKEY" -key="newkey$1" -keymode="plaintext" -keyfile="$REKEYFILE"
+ # shellcheck disable=SC2086
+ echo "$NEWKEY" | ${LB_BINARY} rekey $REKEY_ARGS
+ export LOCKBOX_KEY="$NEWKEY"
+ export LOCKBOX_KEYFILE="$REKEYFILE"
echo
${LB_BINARY} ls
${LB_BINARY} show keys/k/one2