commit 90cb4a9e7a17df9cc6c2c382fa01bda7b10019df
parent b54fe27136dd33aa16375572c209ceee96d94f07
Author: Sean Enck <sean@ttypty.com>
Date: Sat, 7 Jun 2025 16:01:03 -0400
hooks are gone, if they come back - it will be different
Diffstat:
13 files changed, 10 insertions(+), 274 deletions(-)
diff --git a/cmd/lb/main_test.go b/cmd/lb/main_test.go
@@ -28,7 +28,6 @@ const (
reKeyKeyData = "rekeyfile"
clipWait = 1
clipTries = 6
- hookDir = "hooks"
)
var (
@@ -132,13 +131,7 @@ func unpackDir(dir, under string, mode os.FileMode) error {
for _, d := range dirs {
name := d.Name()
if d.IsDir() {
- if name != hookDir {
- return fmt.Errorf("unexpected embedded dir: %s", name)
- }
- if err := unpackDir(filepath.Join(dir, name), filepath.Join(under, name), 0o755); err != nil {
- return err
- }
- continue
+ return fmt.Errorf("unexpected embedded dir: %s", name)
}
data, err := testingFiles.ReadFile(filepath.Join(dir, name))
if err != nil {
diff --git a/cmd/lb/tests/hooks/all.sh b/cmd/lb/tests/hooks/all.sh
@@ -1,2 +0,0 @@
-#!/bin/sh
-echo "$@"
diff --git a/cmd/lb/tests/hooks/test.sh b/cmd/lb/tests/hooks/test.sh
@@ -1,2 +0,0 @@
-#!/bin/sh
-echo "CALLED"
diff --git a/internal/app/help/core.go b/internal/app/help/core.go
@@ -11,7 +11,6 @@ import (
"text/template"
"git.sr.ht/~enckse/lockbox/internal/app/commands"
- "git.sr.ht/~enckse/lockbox/internal/backend"
"git.sr.ht/~enckse/lockbox/internal/config"
"git.sr.ht/~enckse/lockbox/internal/output"
)
@@ -44,17 +43,6 @@ type (
KeyFile string
NoKey string
}
- Hooks struct {
- Mode struct {
- Pre string
- Post string
- }
- Action struct {
- Remove string
- Insert string
- Move string
- }
- }
}
)
@@ -127,11 +115,6 @@ func Usage(verbose bool, exe string) ([]string, error) {
document.Config.XDG = config.ConfigXDG
document.ReKey.KeyFile = setDocFlag(commands.ReKeyFlags.KeyFile)
document.ReKey.NoKey = commands.ReKeyFlags.NoKey
- document.Hooks.Mode.Pre = string(backend.HookPre)
- document.Hooks.Mode.Post = string(backend.HookPost)
- document.Hooks.Action.Insert = string(backend.InsertAction)
- document.Hooks.Action.Remove = string(backend.RemoveAction)
- document.Hooks.Action.Move = string(backend.MoveAction)
files, err := docs.ReadDir(docDir)
if err != nil {
return nil, err
diff --git a/internal/app/help/core_test.go b/internal/app/help/core_test.go
@@ -13,7 +13,7 @@ func TestUsage(t *testing.T) {
t.Errorf("invalid usage, out of date? %d", len(u))
}
u, _ = help.Usage(true, "lb")
- if len(u) != 102 {
+ if len(u) != 92 {
t.Errorf("invalid verbose usage, out of date? %d", len(u))
}
for _, usage := range u {
diff --git a/internal/app/help/doc/hooks.txt b/internal/app/help/doc/hooks.txt
@@ -1,9 +0,0 @@
-When hooks are enabled the files in the specified hook directory
-are executed with the following parameters (in this order):
-
-- string: "{{ .Hooks.Mode.Pre }}" or "{{ .Hooks.Mode.Post }}" representing when the hook is executing.
-
-- string: "{{ .Hooks.Action.Move }}", "{{ .Hooks.Action.Insert }}", or "{{
- .Hooks.Action.Remove }}" indicating the user action
-
-- string: the path to the entry being operated on
diff --git a/internal/backend/actions.go b/internal/backend/actions.go
@@ -14,18 +14,7 @@ import (
)
type (
- // ActionMode represents activities performed via transactions
- ActionMode string
- action func(t Context) error
-)
-
-const (
- // MoveAction represents changes via moves, like the Move command
- MoveAction ActionMode = "mv"
- // InsertAction represents changes via inserts, like the Insert command
- InsertAction ActionMode = "insert"
- // RemoveAction represents changes via deletions, like Remove or globbed remove commands
- RemoveAction ActionMode = "rm"
+ action func(t Context) error
)
func (t *Transaction) act(cb action) error {
@@ -224,20 +213,10 @@ func (t *Transaction) Move(src *Entity, dst string) error {
if err != nil {
return err
}
- action := MoveAction
- if dst == src.Path {
- action = InsertAction
- }
- hook, err := NewHook(src.Path, action)
- if err != nil {
- return err
- }
- if err := hook.Run(HookPre); err != nil {
- return err
- }
- err = t.change(func(c Context) error {
+ isMove := dst != src.Path
+ return t.change(func(c Context) error {
c.removeEntity(sOffset, sTitle)
- if action == MoveAction {
+ if isMove {
c.removeEntity(dOffset, dTitle)
}
e := gokeepasslib.NewEntry()
@@ -259,10 +238,6 @@ func (t *Transaction) Move(src *Entity, dst string) error {
c.alterEntities(true, dOffset, dTitle, &e)
return nil
})
- if err != nil {
- return err
- }
- return hook.Run(HookPost)
}
// Insert is a move to the same location
@@ -284,30 +259,18 @@ func (t *Transaction) RemoveAll(entities []Entity) error {
return errors.New("no entities given")
}
type removal struct {
- parts []string
title string
- hook Hook
+ parts []string
}
removals := []removal{}
- hasHooks := false
for _, entity := range entities {
offset, title, err := splitComponents(entity.Path)
if err != nil {
return err
}
- hook, err := NewHook(entity.Path, RemoveAction)
- if err != nil {
- return err
- }
- if err := hook.Run(HookPre); err != nil {
- return err
- }
- if hook.enabled {
- hasHooks = true
- }
- removals = append(removals, removal{parts: offset, title: title, hook: hook})
+ removals = append(removals, removal{parts: offset, title: title})
}
- err := t.change(func(c Context) error {
+ return t.change(func(c Context) error {
for _, entity := range removals {
if ok := c.removeEntity(entity.parts, entity.title); !ok {
return errors.New("failed to remove entity")
@@ -315,15 +278,4 @@ func (t *Transaction) RemoveAll(entities []Entity) error {
}
return nil
})
- if err != nil {
- return err
- }
- if hasHooks {
- for _, entity := range removals {
- if err := entity.hook.Run(HookPost); err != nil {
- return err
- }
- }
- }
- return nil
}
diff --git a/internal/backend/hooks.go b/internal/backend/hooks.go
@@ -1,83 +0,0 @@
-// Package backend handles kdbx interactions
-package backend
-
-import (
- "errors"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
-
- "git.sr.ht/~enckse/lockbox/internal/config"
- "git.sr.ht/~enckse/lockbox/internal/platform"
-)
-
-type (
- // HookMode are hook operations the user can tie to
- HookMode string
- // Hook represents a runnable user-defined hook
- Hook struct {
- path string
- mode ActionMode
- scripts []string
- enabled bool
- }
-)
-
-const (
- internalHookEnv = "___HOOK___CALLED___"
- // HookPre are triggers BEFORE an action is performed on an entity
- HookPre HookMode = "pre"
- // HookPost are triggers AFTER an action is performed on an entity
- HookPost HookMode = "post"
-)
-
-// NewHook will create a new hook type
-func NewHook(path string, a ActionMode) (Hook, error) {
- enabled := config.EnvHooksEnabled.Get()
- if !enabled || os.Getenv(internalHookEnv) != "" {
- return Hook{enabled: false}, nil
- }
- if strings.TrimSpace(path) == "" {
- return Hook{}, errors.New("empty path is not allowed for hooks")
- }
- dir := config.EnvHookDir.Get()
- if dir == "" {
- return Hook{enabled: false}, nil
- }
- if !platform.PathExists(dir) {
- return Hook{}, errors.New("hook directory does NOT exist")
- }
- entries, err := os.ReadDir(dir)
- if err != nil {
- return Hook{}, err
- }
- scripts := []string{}
- for _, e := range entries {
- if e.IsDir() {
- return Hook{}, errors.New("found subdirectory in hookdir")
- }
- scripts = append(scripts, filepath.Join(dir, e.Name()))
- }
- return Hook{path: path, mode: a, enabled: len(scripts) > 0, scripts: scripts}, nil
-}
-
-// Run will execute any scripts configured as hooks
-func (h Hook) Run(mode HookMode) error {
- if !h.enabled {
- return nil
- }
- env := os.Environ()
- env = append(env, fmt.Sprintf("%s=1", internalHookEnv))
- for _, s := range h.scripts {
- c := exec.Command(s, string(mode), string(h.mode), h.path)
- c.Stdout = os.Stdout
- c.Stderr = os.Stderr
- c.Env = env
- if err := c.Run(); err != nil {
- return err
- }
- }
- return nil
-}
diff --git a/internal/backend/hooks_test.go b/internal/backend/hooks_test.go
@@ -1,71 +0,0 @@
-package backend_test
-
-import (
- "os"
- "path/filepath"
- "strings"
- "testing"
-
- "git.sr.ht/~enckse/lockbox/internal/backend"
- "git.sr.ht/~enckse/lockbox/internal/config/store"
-)
-
-func TestHooks(t *testing.T) {
- store.Clear()
- h, err := backend.NewHook("a", backend.InsertAction)
- if err != nil {
- t.Errorf("invalid error: %v", err)
- }
- if err := h.Run(backend.HookPre); err != nil {
- t.Errorf("invalid error: %v", err)
- }
- if _, err := backend.NewHook("", backend.InsertAction); err.Error() != "empty path is not allowed for hooks" {
- t.Errorf("wrong error: %v", err)
- }
- store.SetString("LOCKBOX_HOOKS_DIRECTORY", "is_garbage")
- if _, err := backend.NewHook("b", backend.InsertAction); err.Error() != "hook directory does NOT exist" {
- t.Errorf("wrong error: %v", err)
- }
- testPath := filepath.Join("testdata", "hooks.kdbx")
- os.RemoveAll(testPath)
- if err := os.MkdirAll(testPath, 0o755); err != nil {
- t.Errorf("failed, mkdir: %v", err)
- }
- store.SetString("LOCKBOX_HOOKS_DIRECTORY", testPath)
- h, err = backend.NewHook("a", backend.InsertAction)
- if err != nil {
- t.Errorf("invalid error: %v", err)
- }
- if err := h.Run(backend.HookPre); err != nil {
- t.Errorf("invalid error: %v", err)
- }
- sub := filepath.Join(testPath, "subdir")
- if err := os.MkdirAll(sub, 0o755); err != nil {
- t.Errorf("failed, mkdir sub: %v", err)
- }
- if _, err := backend.NewHook("b", backend.InsertAction); err.Error() != "found subdirectory in hookdir" {
- t.Errorf("wrong error: %v", err)
- }
- if err := os.RemoveAll(sub); err != nil {
- t.Errorf("failed rmdir: %v", err)
- }
- script := filepath.Join(testPath, "testscript")
- if err := os.WriteFile(script, []byte{}, 0o644); err != nil {
- t.Errorf("unable to write script: %v", err)
- }
- h, err = backend.NewHook("a", backend.InsertAction)
- if err != nil {
- t.Errorf("invalid error: %v", err)
- }
- if err := h.Run(backend.HookPre); strings.Contains("fork/exec", err.Error()) {
- t.Errorf("wrong error: %v", err)
- }
- store.SetBool("LOCKBOX_HOOKS_ENABLED", false)
- h, err = backend.NewHook("a", backend.InsertAction)
- if err != nil {
- t.Errorf("invalid error: %v", err)
- }
- if err := h.Run(backend.HookPre); err != nil {
- t.Errorf("wrong error: %v", err)
- }
-}
diff --git a/internal/config/core.go b/internal/config/core.go
@@ -22,7 +22,6 @@ const (
jsonCategory = "JSON_"
credsCategory = "CREDENTIALS_"
defaultCategory = "DEFAULTS_"
- hookCategory = "HOOKS_"
environmentPrefix = "LOCKBOX_"
commandArgsExample = "[cmd args...]"
fileExample = "<file>"
diff --git a/internal/config/toml_test.go b/internal/config/toml_test.go
@@ -251,7 +251,7 @@ func TestDefaultTOMLToLoadFile(t *testing.T) {
if err := config.LoadConfigFile(file); err != nil {
t.Errorf("invalid error: %v", err)
}
- if len(store.List()) != 27 {
+ if len(store.List()) != 25 {
t.Errorf("invalid environment after load")
}
}
diff --git a/internal/config/vars.go b/internal/config/vars.go
@@ -69,14 +69,6 @@ var (
description: "Enable terminal colors.",
}),
})
- // EnvHooksEnabled indicates if hooks are enabled
- EnvHooksEnabled = environmentRegister(EnvironmentBool{
- environmentDefault: newDefaultedEnvironment(true,
- environmentBase{
- key: hookCategory + "ENABLED",
- description: "Enable hooks",
- }),
- })
// EnvInteractive indicates if operating in interactive mode
EnvInteractive = environmentRegister(EnvironmentBool{
environmentDefault: newDefaultedEnvironment(true,
@@ -118,18 +110,6 @@ var (
flags: []stringsFlags{canExpandFlag},
},
})
- // EnvHookDir is the directory of hooks to execute
- EnvHookDir = environmentRegister(EnvironmentString{
- environmentStrings: environmentStrings{
- environmentDefault: newDefaultedEnvironment("",
- environmentBase{
- key: hookCategory + "DIRECTORY",
- description: "The path to a directory of hooks to execute on actions against the database.",
- }),
- allowed: []string{"<directory>"},
- flags: []stringsFlags{canDefaultFlag, canExpandFlag},
- },
- })
// EnvClipCopy allows overriding the clipboard copy command
EnvClipCopy = environmentRegister(EnvironmentArray{
environmentStrings: environmentStrings{
diff --git a/internal/config/vars_test.go b/internal/config/vars_test.go
@@ -28,10 +28,6 @@ func TestColorSetting(t *testing.T) {
checkYesNo("LOCKBOX_COLOR_ENABLED", t, config.EnvColorEnabled, true)
}
-func TestNoHook(t *testing.T) {
- checkYesNo("LOCKBOX_HOOKS_ENABLED", t, config.EnvHooksEnabled, true)
-}
-
func TestInteractiveSetting(t *testing.T) {
checkYesNo("LOCKBOX_INTERACTIVE", t, config.EnvInteractive, true)
}