lockbox

password manager
Log | Files | Refs | README | LICENSE

commit b90b47178330c406587cb2eeac219d8fc7cac3b3
parent 4debe5e052b9d17b94540db001718d7cbbc40ee5
Author: Sean Enck <sean@ttypty.com>
Date:   Sun,  2 Oct 2022 11:15:39 -0400

allow operation in readonly mode

Diffstat:
Mcmd/vers.txt | 2+-
Mcontrib/completions.bash | 10++++++++--
Minternal/backend/actions.go | 3+++
Minternal/backend/actions_test.go | 10++++++++++
Minternal/backend/core.go | 6+++++-
Minternal/backend/types.go | 9+++++----
Minternal/inputs/env.go | 6++++++
Mtests/run.sh | 1+
8 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/cmd/vers.txt b/cmd/vers.txt @@ -1 +1 @@ -v22.10.03 +v22.10.04 diff --git a/contrib/completions.bash b/contrib/completions.bash @@ -9,16 +9,22 @@ _is_clip() { } _lb() { - local cur opts clip_enabled needs + local cur opts clip_enabled needs readwrite clip_enabled=" clip" if [ -n "$LOCKBOX_NOCLIP" ]; then if [ "$LOCKBOX_NOCLIP" == "yes" ]; then clip_enabled="" fi fi + readwrite=" insert rm mv" + if [ -n "$LOCKBOX_READONLY" ]; then + if [ "$LOCKBOX_READONLY" == "yes" ]; then + readwrite="" + fi + fi cur=${COMP_WORDS[COMP_CWORD]} if [ "$COMP_CWORD" -eq 1 ]; then - opts="version ls show insert rm totp mv find$clip_enabled" + opts="version ls show totp$readwrite find$clip_enabled" # shellcheck disable=SC2207 COMPREPLY=( $(compgen -W "$opts" -- "$cur") ) else diff --git a/internal/backend/actions.go b/internal/backend/actions.go @@ -61,6 +61,9 @@ func (t *Transaction) act(cb action) error { } func (t *Transaction) change(cb action) error { + if t.readonly { + return errors.New("unable to alter database in readonly mode") + } return t.act(func(c Context) error { if err := c.db.UnlockProtectedEntries(); err != nil { return err diff --git a/internal/backend/actions_test.go b/internal/backend/actions_test.go @@ -13,6 +13,7 @@ func fullSetup(t *testing.T, keep bool) *backend.Transaction { if !keep { os.Remove("test.kdbx") } + os.Setenv("LOCKBOX_READONLY", "no") os.Setenv("LOCKBOX_STORE", "test.kdbx") os.Setenv("LOCKBOX_KEY", "test") os.Setenv("LOCKBOX_KEYMODE", "plaintext") @@ -27,6 +28,15 @@ func setup(t *testing.T) *backend.Transaction { return fullSetup(t, false) } +func TestNoWriteOnRO(t *testing.T) { + setup(t) + os.Setenv("LOCKBOX_READONLY", "yes") + tr, _ := backend.NewTransaction() + if err := tr.Insert("a/a/a", "a"); err.Error() != "unable to alter database in readonly mode" { + t.Errorf("wrong error: %v", err) + } +} + func TestBadAction(t *testing.T) { tr := &backend.Transaction{} if err := tr.Insert("a/a/a", "a"); err.Error() != "invalid transaction" { diff --git a/internal/backend/core.go b/internal/backend/core.go @@ -25,7 +25,11 @@ func loadFile(file string, must bool) (*Transaction, error) { return nil, errors.New("invalid file, does not exists") } } - return &Transaction{valid: true, file: file, exists: exists}, nil + ro, err := inputs.IsReadOnly() + if err != nil { + return nil, err + } + return &Transaction{valid: true, file: file, exists: exists, readonly: ro}, nil } // NewTransaction will use the underlying environment data store location diff --git a/internal/backend/types.go b/internal/backend/types.go @@ -25,10 +25,11 @@ type ( action func(t Context) error // Transaction handles the overall operation of the transaction Transaction struct { - valid bool - file string - exists bool - write bool + valid bool + file string + exists bool + write bool + readonly bool } // Context handles operating on the underlying database Context struct { diff --git a/internal/inputs/env.go b/internal/inputs/env.go @@ -16,6 +16,7 @@ const ( noClipEnv = prefixKey + "NOCLIP" noColorEnv = prefixKey + "NOCOLOR" interactiveEnv = prefixKey + "INTERACTIVE" + readOnlyEnv = prefixKey + "READONLY" // TotpEnv allows for overriding of the special name for totp entries. TotpEnv = prefixKey + "TOTP" // KeyModeEnv indicates what the KEY value is (e.g. command, plaintext). @@ -101,6 +102,11 @@ func isYesNoEnv(defaultValue bool, env string) (bool, error) { return false, fmt.Errorf("invalid yes/no env value for %s", env) } +// IsReadOnly indicates to operate in readonly, no writing to file allowed +func IsReadOnly() (bool, error) { + return isYesNoEnv(false, readOnlyEnv) +} + // IsNoClipEnabled indicates if clipboard mode is enabled. func IsNoClipEnabled() (bool, error) { return isYesNoEnv(false, noClipEnv) diff --git a/tests/run.sh b/tests/run.sh @@ -7,6 +7,7 @@ export LOCKBOX_KEYMODE="plaintext" export LOCKBOX_KEY="plaintextkey" export LOCKBOX_TOTP="totp" export LOCKBOX_INTERACTIVE="no" +export LOCKBOX_READONLY="no" rm -rf $TESTS mkdir -p $TESTS