security(relay): minor hardening follow-ups from PR review
- Uniform auth responses remove the session-enumeration oracle: unknown session and wrong password now return an identical 401 at the API layer and an identical WS handshake/close; desktop-status and the 503 "not connected" signal are only exposed after successful auth. - Session-count cap re-checked after bcrypt.hash so concurrent creates can't overshoot maxSessions. - Relay web client reconnect backoff resets only after a successful auth response (an accept-then-close server no longer defeats the backoff). - idGenerator comment corrected to match the rejection-sampling; drop unused recordFailure return value. - DEPLOY.md: document ALLOWED_ORIGINS for reverse-proxy deployments. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -136,6 +136,21 @@ export class SessionManager {
|
||||
} while (this.sessions.has(id));
|
||||
|
||||
const passwordHash = await bcrypt.hash(password, config.bcryptRounds);
|
||||
|
||||
// Re-check the cap AFTER the (awaited) hash. bcrypt.hash is the only
|
||||
// suspension point between the first cap check and the set() below, so
|
||||
// concurrent createSession calls could each have passed the earlier check
|
||||
// and then filled the map while we were hashing. Re-checking here — with
|
||||
// no await between this check and the synchronous set() — makes the
|
||||
// check-and-insert atomic under Node's single-threaded model, so the cap
|
||||
// cannot be overshot.
|
||||
if (this.sessions.size >= config.maxSessions) {
|
||||
this.pruneExpired();
|
||||
if (this.sessions.size >= config.maxSessions) {
|
||||
throw new Error('Session limit reached');
|
||||
}
|
||||
}
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
const session: Session = {
|
||||
|
||||
Reference in New Issue
Block a user