fix(security,reliability): address code-review findings
HIGH
- async handlers: Express 4 does not catch rejected promises and Node 22
exits on unhandled rejections — a malformed body ({} to /cropper/dequeue
etc.) could hang a request or kill the process. Every cropper route is
now wrapped (throw → 500 via next), request bodies are validated up
front (400), and JSON.parse of queue items is guarded. Server-wide
error middleware added, honouring err.status (413 for oversized bodies).
- error pages HTML-escape all interpolated values — the login failure page
rendered upstream (portal) error text raw.
MEDIUM
- outbound calls carry AbortSignal timeouts (5s OpenFGA verify, 15s
cropper upstreams) — a hung upstream can no longer pin a request.
- body limits scoped: /cropper gets 50mb (picture data URLs), everything
else 1mb (previously 50mb globally, memory-DoS surface pre-auth).
- cropper save validates the client-supplied domain against the catalog;
picture fetches validate the Minio object key (id-domains/ prefix, no ..).
LOW
- static assets served before the session middleware (no PocketBase load
per asset); landing header builds DOM nodes with textContent instead of
innerHTML; picture load checks upstream ok.
5 new tests (40 total) covering malformed bodies, malformed queue items,
unknown domains, object-key traversal, and error-page escaping.
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
// Results are cached per operator phone for DOMAIN_TTL_MS.
|
||||
export const DOMAIN_TTL_MS = 5 * 60 * 1000;
|
||||
export const CACHE_FRESH = 'CACHE_FRESH';
|
||||
/** Outbound OpenFGA verify timeout — a hung portal must not pin a request. */
|
||||
export const VERIFY_TIMEOUT_MS = 5000;
|
||||
|
||||
export function stripPhonePrefix(phone) {
|
||||
return (phone || '').replace(/^\+/, '');
|
||||
@@ -19,6 +21,7 @@ async function verifyOnce(fetchImpl, portalUrl, phone, object, relation = 'captu
|
||||
relation,
|
||||
object,
|
||||
}),
|
||||
signal: AbortSignal.timeout(VERIFY_TIMEOUT_MS),
|
||||
});
|
||||
if (r.status !== 200) throw new Error(`verify status ${r.status}`);
|
||||
const out = await r.json();
|
||||
|
||||
Reference in New Issue
Block a user