Introduces a unified security event store and HTTP API that ingests events from any of the configured sources (API audit, Caddy access log, fail2ban, shared_bans, future remote agents) and surfaces them in the dashboard. New files: src/security/event-store.js JSONL-backed store + in-memory query index src/security/host-registry.js Registered hosts with per-host API keys src/security/event-workers.js Tail-followers for Caddy/fail2ban/shared_bans logs routes/security.js Events, hosts, ingest, SSE stream endpoints status/js/security-center.js Dashboard modal with Overview/Events/Hosts tabs SECURITY-FEATURE.md Full feature documentation DEAD-CODE.md, DUP-CODE.md, HARDENING.md Prior audits Modified: src/app.js Mount /api/v1/security/* src/utilities/middleware.js Add ingest endpoints to PUBLIC_ROUTES src/security/audit-logger.js Mirror audit events into security store server.js Start security workers on boot status/build.js Bundle security-center.js status/index.html Add Security button to nav
4.1 KiB
4.1 KiB
DashCaddy Duplicate Code Report
Generated: 2026-07-13
Functions scanned: 107 (≥200 chars body length)
Exact-duplicate groups: 10
Methodology
- Extract every top-level
function X() { ... }declaration - Skip functions < 200 chars (helpers, getters, trivial wrappers)
- Normalize: strip comments, collapse whitespace, replace all identifiers with placeholder
- SHA-1 the normalized body → identical hashes = duplicate bodies
⚠️ Caveats
- Anonymous functions and arrow functions are not captured (regex matches
function name(only) - Class methods are not captured (would need AST parser)
- Near-duplicates with renamed variables are flagged as the same (that's the point — after normalization, only structure differs)
module.exportsfactory functions are common and look similar — many route files have a 5-line wrapper likemodule.exports = function(ctx) { const router = express.Router(); ... return router; }. These will show as duplicate groups.
Exact Duplicate Groups
Functions whose bodies are byte-identical after normalization (ignoring comments, whitespace, and identifier names).
| Hash | Count | Functions |
|---|---|---|
5a3372b656b7 |
2 | base32Encode, base32Encode |
9550727efdf2 |
2 | base32Decode, base32Decode |
e00959ade524 |
2 | getSecret, getSecret |
09498fd55b60 |
2 | initSecret, initSecret |
0f89a717e703 |
2 | generateCode, generateCode |
d92f81854134 |
2 | parseCode, parseCode |
8c3ecfea7f7d |
2 | parsePayload, parsePayload |
fc844dbaca2f |
2 | verifyCode, verifyCode |
221e46c497d9 |
2 | main, main |
9573dd3cd485 |
2 | formatBytes, formatBytes |
Top Groups (Detail)
Hash 5a3372b656b7 (2 copies)
src/managers/license-keygen.js:33—base32Encode()(374 chars)license-keygen.js:33—base32Encode()(374 chars)
Hash 9550727efdf2 (2 copies)
src/managers/license-keygen.js:48—base32Decode()(415 chars)license-keygen.js:48—base32Decode()(415 chars)
Hash e00959ade524 (2 copies)
src/managers/license-keygen.js:62—getSecret()(216 chars)license-keygen.js:62—getSecret()(216 chars)
Hash 09498fd55b60 (2 copies)
src/managers/license-keygen.js:70—initSecret()(597 chars)license-keygen.js:70—initSecret()(597 chars)
Hash 0f89a717e703 (2 copies)
src/managers/license-keygen.js:83—generateCode()(1331 chars)license-keygen.js:83—generateCode()(1331 chars)
Hash d92f81854134 (2 copies)
src/managers/license-keygen.js:118—parseCode()(523 chars)license-keygen.js:118—parseCode()(523 chars)
Hash 8c3ecfea7f7d (2 copies)
src/managers/license-keygen.js:135—parsePayload()(443 chars)license-keygen.js:135—parsePayload()(443 chars)
Hash fc844dbaca2f (2 copies)
src/managers/license-keygen.js:148—verifyCode()(1367 chars)license-keygen.js:148—verifyCode()(1367 chars)
Hash 221e46c497d9 (2 copies)
src/managers/license-keygen.js:188—main()(4428 chars)license-keygen.js:188—main()(4428 chars)
Hash 9573dd3cd485 (2 copies)
routes/backups.js:693—formatBytes()(259 chars)routes/apps/restore.js:488—formatBytes()(259 chars)
Common Factory Pattern
module.exports = function(ctx) { const router = express.Router(); ... }
49 files use this factory wrapper pattern:
routes/errorlogs.jsroutes/docker-resources.jsroutes/ca.jsroutes/config-drift.jsroutes/containers.jsroutes/context.jsroutes/monitoring.jsroutes/workflows.jsroutes/services.jsroutes/sites.jsroutes/logs.jsroutes/credentials.jsroutes/themes.jsroutes/updates.jsroutes/dns.js- ... and 34 more
Could be extracted to a helper:
// src/utilities/route-factory.js
module.exports = function routeFactory(handlerFn) {
return function(deps) {
const router = require('express').Router();
handlerFn(router, deps);
return router;
};
};