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:
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