mirror of
https://github.com/anotherhadi/spilltea.git
synced 2026-05-20 01:32:33 +02:00
check if trufflehog is installed on_start
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
This commit is contained in:
+26
-5
@@ -31,14 +31,14 @@ Plugin = {
|
|||||||
|
|
||||||
### Hook reference
|
### Hook reference
|
||||||
|
|
||||||
| Hook | When called | Sync/async | Return value (sync only) |
|
| Hook | When called | Sync/async | Return value |
|
||||||
| ------------------------- | ------------------------------------- | ------------ | ----------------------------------------------- |
|
| ------------------------- | ------------------------------------- | ------------ | ----------------------------------------------- |
|
||||||
| `on_config(config_text)` | At startup and on config save | always sync | ignored |
|
| `on_config(config_text)` | At startup and on config save | always sync | ignored |
|
||||||
| `on_start()` | Once at startup, after `on_config` | configurable | ignored |
|
| `on_start()` | Once at startup, after `on_config` | configurable | `false` to self-disable the plugin, otherwise ignored |
|
||||||
| `on_quit()` | When the app exits | always sync | ignored |
|
| `on_quit()` | When the app exits | always sync | ignored |
|
||||||
| `on_request(req)` | Every request, before auto-forward | configurable | `"drop"`, `"forward"`, or `nil` |
|
| `on_request(req)` | Every request, before auto-forward | configurable | `"drop"`, `"forward"`, or `nil` (sync only) |
|
||||||
| `on_response(req, res)` | Every response | configurable | `"drop"`, `"forward"`, or `nil` |
|
| `on_response(req, res)` | Every response | configurable | `"drop"`, `"forward"`, or `nil` (sync only) |
|
||||||
| `on_history_entry(entry)` | Sync: before DB insert / Async: after | configurable | `"skip"` (don't save), `"keep"` or `nil` (save) |
|
| `on_history_entry(entry)` | Sync: before DB insert / Async: after | configurable | `"skip"` (don't save), `"keep"` or `nil` (save) -- sync only |
|
||||||
|
|
||||||
## Request and response objects
|
## Request and response objects
|
||||||
|
|
||||||
@@ -141,6 +141,27 @@ Each plugin gets a **config textarea** on the Plugins page. The raw text is pass
|
|||||||
|
|
||||||
### Return values for sync hooks
|
### Return values for sync hooks
|
||||||
|
|
||||||
|
**`on_start`:**
|
||||||
|
|
||||||
|
| Return value | Effect |
|
||||||
|
| ------------ | -------------------------------------------------------------------------------------------- |
|
||||||
|
| `false` | The plugin is disabled immediately and the state is persisted (equivalent to toggling it off). |
|
||||||
|
| anything else | Ignored. |
|
||||||
|
|
||||||
|
This is useful for prerequisite checks (binary not found, config invalid, etc.) so the plugin does not silently run in a broken state:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_start()
|
||||||
|
local h = io.popen("command -v mytool 2>/dev/null")
|
||||||
|
local result = h and h:read("*a") or ""
|
||||||
|
if h then h:close() end
|
||||||
|
if result:match("^%s*$") then
|
||||||
|
notif("MyPlugin", "mytool not found, plugin disabled", "error")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
**`on_request` and `on_response`:**
|
**`on_request` and `on_response`:**
|
||||||
|
|
||||||
| Return value | Effect |
|
| Return value | Effect |
|
||||||
|
|||||||
@@ -292,22 +292,19 @@ func pushEntry(L *lua.LState, e db.Entry) *lua.LTable {
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func callHook(p *Plugin, hookName string, args ...lua.LValue) (string, error) {
|
func callHook(p *Plugin, hookName string, args ...lua.LValue) (lua.LValue, error) {
|
||||||
fn := p.L.GetGlobal(hookName)
|
fn := p.L.GetGlobal(hookName)
|
||||||
if fn == lua.LNil {
|
if fn == lua.LNil {
|
||||||
return "", nil
|
return lua.LNil, nil
|
||||||
}
|
}
|
||||||
if err := p.L.CallByParam(lua.P{
|
if err := p.L.CallByParam(lua.P{
|
||||||
Fn: fn,
|
Fn: fn,
|
||||||
NRet: 1,
|
NRet: 1,
|
||||||
Protect: true,
|
Protect: true,
|
||||||
}, args...); err != nil {
|
}, args...); err != nil {
|
||||||
return "", err
|
return lua.LNil, err
|
||||||
}
|
}
|
||||||
ret := p.L.Get(-1)
|
ret := p.L.Get(-1)
|
||||||
p.L.Pop(1)
|
p.L.Pop(1)
|
||||||
if s, ok := ret.(lua.LString); ok {
|
return ret, nil
|
||||||
return string(s), nil
|
|
||||||
}
|
|
||||||
return "", nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,17 +191,31 @@ func (m *Manager) TogglePlugin(name string) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
disableIfFalse := func(p *Plugin, ret lua.LValue) {
|
||||||
|
if ret == lua.LFalse {
|
||||||
|
p.Enabled = false
|
||||||
|
if m.db != nil {
|
||||||
|
_ = m.db.SavePluginState(p.Name, false, p.ConfigText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if hc.Sync {
|
if hc.Sync {
|
||||||
found.mu.Lock()
|
found.mu.Lock()
|
||||||
if _, err := callHook(found, "on_start"); err != nil {
|
ret, err := callHook(found, "on_start")
|
||||||
|
if err != nil {
|
||||||
log.Printf("plugin %s on_start: %v", found.Name, err)
|
log.Printf("plugin %s on_start: %v", found.Name, err)
|
||||||
|
} else {
|
||||||
|
disableIfFalse(found, ret)
|
||||||
}
|
}
|
||||||
found.mu.Unlock()
|
found.mu.Unlock()
|
||||||
} else {
|
} else {
|
||||||
go func() {
|
go func() {
|
||||||
found.mu.Lock()
|
found.mu.Lock()
|
||||||
if _, err := callHook(found, "on_start"); err != nil {
|
ret, err := callHook(found, "on_start")
|
||||||
|
if err != nil {
|
||||||
log.Printf("plugin %s on_start: %v", found.Name, err)
|
log.Printf("plugin %s on_start: %v", found.Name, err)
|
||||||
|
} else {
|
||||||
|
disableIfFalse(found, ret)
|
||||||
}
|
}
|
||||||
found.mu.Unlock()
|
found.mu.Unlock()
|
||||||
}()
|
}()
|
||||||
@@ -264,17 +278,31 @@ func (m *Manager) RunOnStart() {
|
|||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
disableIfFalse := func(p *Plugin, ret lua.LValue) {
|
||||||
|
if ret == lua.LFalse {
|
||||||
|
p.Enabled = false
|
||||||
|
if m.db != nil {
|
||||||
|
_ = m.db.SavePluginState(p.Name, false, p.ConfigText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if hc.Sync {
|
if hc.Sync {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
if _, err := callHook(p, "on_start"); err != nil {
|
ret, err := callHook(p, "on_start")
|
||||||
|
if err != nil {
|
||||||
log.Printf("plugin %s on_start: %v", p.Name, err)
|
log.Printf("plugin %s on_start: %v", p.Name, err)
|
||||||
|
} else {
|
||||||
|
disableIfFalse(p, ret)
|
||||||
}
|
}
|
||||||
p.mu.Unlock()
|
p.mu.Unlock()
|
||||||
} else {
|
} else {
|
||||||
go func(p *Plugin) {
|
go func(p *Plugin) {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
if _, err := callHook(p, "on_start"); err != nil {
|
ret, err := callHook(p, "on_start")
|
||||||
|
if err != nil {
|
||||||
log.Printf("plugin %s on_start: %v", p.Name, err)
|
log.Printf("plugin %s on_start: %v", p.Name, err)
|
||||||
|
} else {
|
||||||
|
disableIfFalse(p, ret)
|
||||||
}
|
}
|
||||||
p.mu.Unlock()
|
p.mu.Unlock()
|
||||||
}(p)
|
}(p)
|
||||||
@@ -316,13 +344,15 @@ func (m *Manager) runSyncDecisionForPlugins(hookName string, argsFor func(*Plugi
|
|||||||
log.Printf("plugin %s %s: %v", p.Name, hookName, err)
|
log.Printf("plugin %s %s: %v", p.Name, hookName, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch result {
|
if s, ok := result.(lua.LString); ok {
|
||||||
|
switch string(s) {
|
||||||
case "drop":
|
case "drop":
|
||||||
return intercept.Drop
|
return intercept.Drop
|
||||||
case "forward":
|
case "forward":
|
||||||
return intercept.Forward
|
return intercept.Forward
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return intercept.Intercept
|
return intercept.Intercept
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,7 +418,7 @@ func (m *Manager) RunSyncOnHistoryEntry(e db.Entry) bool {
|
|||||||
log.Printf("plugin %s on_history_entry: %v", p.Name, err)
|
log.Printf("plugin %s on_history_entry: %v", p.Name, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if result == "skip" {
|
if s, ok := result.(lua.LString); ok && string(s) == "skip" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,23 @@ Requires `trufflehog` v3+ to be installed and available in PATH.
|
|||||||
Each finding is stored on the **Findings** page with the matched detector output.
|
Each finding is stored on the **Findings** page with the matched detector output.
|
||||||
Findings are deduplicated per host+path+body content so repeated requests do not create duplicates.
|
Findings are deduplicated per host+path+body content so repeated requests do not create duplicates.
|
||||||
]],
|
]],
|
||||||
|
on_start = { sync = false },
|
||||||
on_request = { sync = false },
|
on_request = { sync = false },
|
||||||
on_response = { sync = false },
|
on_response = { sync = false },
|
||||||
disable_by_default = true,
|
disable_by_default = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function on_start()
|
||||||
|
local handle = io.popen("command -v trufflehog 2>/dev/null")
|
||||||
|
local result = handle and handle:read("*a") or ""
|
||||||
|
if handle then handle:close() end
|
||||||
|
if not result or result:match("^%s*$") then
|
||||||
|
log("trufflehog is not installed or not in PATH")
|
||||||
|
notif("TruffleHog", "trufflehog is not installed or not in PATH, plugin disabled", "error")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function scan(label, content, host, path)
|
local function scan(label, content, host, path)
|
||||||
if not content or content == "" then return end
|
if not content or content == "" then return end
|
||||||
local out, err = shell_pipe("f=$(mktemp) && cat > \"$f\" && trufflehog filesystem --no-color \"$f\"; rc=$?; rm -f \"$f\"; exit $rc", content)
|
local out, err = shell_pipe("f=$(mktemp) && cat > \"$f\" && trufflehog filesystem --no-color \"$f\"; rc=$?; rm -f \"$f\"; exit $rc", content)
|
||||||
|
|||||||
Reference in New Issue
Block a user