Repository navigation
Conversation
Next.js hands the catch-all proxy already percent-decoded segments, so `DELETE /v1/safelist/8.9.8.9%2F32` was re-sent as `/v1/safelist/8.9.8.9/32` and missed the single-segment route: the dashboard reported "API error 404" and the prefix stayed safelisted. Re-encode each segment before forwarding, and make the backend route a wildcard capture so clients and proxies that decode `%2F` (curl, other reverse proxies) work against it too. Verified: proxied `%2F` delete 404 -> 204, add/remove of 203.0.113.77/32 through the dashboard UI, plus regression tests for both slash forms. Fixes #146
/v1/auth/login and /v1/auth/me return the operator flat
({operator_id, username, role}), but the client read `data.operator`, which is
undefined. The user menu (user-menu.tsx returns null without an operator) never
rendered, so a signed-in user had no way to sign out or switch roles, and every
`usePermissions` role check denied admin actions to real admins.
Map the wire shape into the client Operator and make isAuthenticated a strict
boolean so a partial payload cannot read as authenticated.
Verified in a browser: header shows the username with Notifications/Sign out,
sign-out lands on /login, a viewer login shows the viewer role and hides the
Admin nav.
Fixes #147
…vector Vector inference matched the first protocol word anywhere in FastNetMon's details, so the idle line `outgoing udp traffic: 0 mbps` won over the actual attack type and SYN floods were reported as udp_flood. Ignore lines that report a zero metric, match tokens on word boundaries (so `ack` no longer matches inside "packets"), and prefer TCP flag vectors over udp. Verified: the reporter's details yield udp_flood with the old logic and syn_flood with the new one; covered by tests/fastnetmon_vector.rs, which drives the script with a stub curl. Fixes #145
…ying navigator.clipboard only exists in secure contexts, so copy buttons on a plain-HTTP dashboard threw a TypeError, copied nothing and said nothing -- "incident report not in clipboard" with no visible error. Route every copy through lib/clipboard.ts: use the Clipboard API when the context allows it, fall back to a hidden textarea, and check the clipboard-write permission first, because Chrome reports `denied` for insecure origins and still returns true from the legacy copy command. Callers now surface "Copy failed -- clipboard unavailable". Chrome blocks clipboard writes for plain-HTTP origins other than localhost, so production dashboards need HTTPS; documented in docs/deployment.md. Verified in Chrome: on a secure origin the incident report is copied verbatim (read back off the X11 clipboard), on an HTTP origin the failure toast shows and nothing is claimed as copied. Refs #144
This was referenced Sep 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes four reported issues, each root-caused in the running stack rather than patched at the symptom. No release/tag intended here.
#146 — removing a safelist prefix returned "API error 404"
nginxis not involved: it preserves%2Fin everyproxy_passform (verified against a stub upstream). The Next.js catch-all proxy receives percent-decoded route segments and rejoined them with/, soDELETE /v1/safelist/8.9.8.9%2F32reached the backend as/v1/safelist/8.9.8.9/32, missed the single-segment route and 404'd — the prefix stayed safelisted.frontend/app/api/prefixd/[...path]/route.ts: re-encode each segment (upstreamPath), preserving the search string for GET.src/api/routes.rs:DELETE /v1/safelist/{*prefix}so a literal slash also matches (curl users, proxies that decode%2F).tests/integration.rs: regression tests for the encoded and literal-slash forms;docs/api.mddocuments both.#147 — no way to sign out (and no role-based permissions)
/v1/auth/loginand/v1/auth/mereturn the operator flat (operator_id,username,role), but the client readdata.operator, which isundefined.UserMenureturnsnullwithout an operator, so a signed-in user saw no menu and could not sign out or switch roles;rolewas also undefined, sousePermissionsdenied admin actions (safelist, users, playbooks, reload) to real admins.frontend/lib/auth.ts: map the wire shape to the clientOperator;getCurrentUserreturnsnullfor an unexpected payload.frontend/hooks/use-auth.tsx:isAuthenticated: Boolean(operator).frontend/__tests__/auth-lib.test.ts: covers both endpoints, the 401 case, and a wrong-shape payload.#145 — FastNetMon SYN floods reported as
udp_floodVector inference matched the first protocol word anywhere in the details, so FastNetMon's idle line
outgoing udp traffic: 0 mbpsbeat the actual attack type.scripts/prefixd-fastnetmon.sh: drop lines that report a zero metric, match tokens on word boundaries (ackno longer matches inside "packets"), prefer TCP flag vectors overudp.tests/fastnetmon_vector.rs: drives the script with a stubcurland asserts the payload vector — covers the reporter's details, a real udp flood,tcp_ackwith "packets per second" text, and all-zero details.docs/detectors/fastnetmon.md: table + matching rules.#144 — incident report not in the clipboard
navigator.clipboardonly exists in secure contexts, so the copy handlers threw on a plain-HTTP dashboard: nothing copied, no error shown.frontend/lib/clipboard.ts: Clipboard API in secure contexts, hidden-textarea fallback otherwise,clipboard-writepermission check, boolean result.Copy failed — clipboard unavailable.docs/deployment.md: clipboard requires a secure context.Measured in Chrome: insecure non-localhost origins report
clipboard-write: deniedand Chrome silently ignores even the legacyexecCommand("copy")(returns true, clipboard unchanged), so production dashboards need HTTPS for clipboard actions — the reporter's workaround was the right one. The fallback still helps browsers that permit legacy writes.Verification
cargo test --features test-utils: 250 unit + 4 script + 162 integration + 16 postgres pass (17 ignored: GoBGP/Docker).bun run test: 97 tests.bun run build(production) succeeds.cargo fmt --checkandcargo clippy --all-targets --features test-utils -- -D warningsclean.Fixes #146
Fixes #147
Fixes #145
Refs #144