refactor: create fast tracks for cookie parsing

This commit is contained in:
Carlos Valente
2025-08-18 20:43:28 +02:00
committed by Carlos Valente
parent 3b38756dda
commit 3c41b40c5f
+26 -9
View File
@@ -1,5 +1,3 @@
import { LogOrigin } from 'ontime-types';
import express, { type Request, type Response, type NextFunction } from 'express';
import type { IncomingMessage } from 'node:http';
import type { WebSocket } from 'ws';
@@ -7,7 +5,6 @@ import { parse as parseCookie } from 'cookie';
import { hashPassword } from '../utils/hash.js';
import { srcFiles } from '../setup/index.js';
import { logger } from '../classes/Logger.js';
import { hashedPassword, hasPassword } from '../api-data/session/session.service.js';
import { noopMiddleware } from './noop.js';
@@ -53,6 +50,9 @@ export function makeAuthenticateMiddleware(prefix: string) {
return { authenticate: noopMiddleware, authenticateAndRedirect: noopMiddleware };
}
// pre-compute the login redirect base URL to avoid string concatenation on every request
const loginRedirectBase = `${prefix}/login?redirect=`;
function authenticate(req: Request, res: Response, next: NextFunction) {
if (req.query.token) {
if (req.query.token === hashedPassword) {
@@ -98,7 +98,7 @@ export function makeAuthenticateMiddleware(prefix: string) {
return next();
}
res.redirect(`${prefix}/login?redirect=${req.originalUrl}`);
res.redirect(loginRedirectBase + req.originalUrl);
}
return { authenticate, authenticateAndRedirect };
@@ -124,14 +124,23 @@ export function authenticateSocket(_ws: WebSocket, req: IncomingMessage, next: (
}
}
// check if token is in the params
const url = new URL(req.url || '', `http://${req.headers.host}`);
const token = url.searchParams.get('token');
if (token === hashedPassword) {
// check if token is in the params - simple string check first
const urlString = req.url || '';
if (urlString.includes(`token=${hashedPassword}`)) {
return next();
}
logger.warning(LogOrigin.Client, 'Unauthorized WebSocket connection attempt');
// fallback to full URL parsing for other formats
try {
const url = new URL(urlString, `http://${req.headers.host}`);
const token = url.searchParams.get('token');
if (token === hashedPassword) {
return next();
}
} catch (_) {
// ignore URL parsing errors
}
return next(new Error('Unauthorized'));
}
@@ -153,6 +162,14 @@ function setSessionCookie(res: Response, token: string) {
* And want to extract its value
*/
function getTokenFromCookie(cookieContents: string): string | undefined {
// Fast path: check if the hashed password is directly in the cookie string
// This avoids JSON parsing for the common case
const cookieTokenString = '"token":"' + hashedPassword + '}"';
if (cookieTokenString && cookieContents.includes(cookieTokenString)) {
return hashedPassword;
}
// Fallback to JSON parsing for other cases or validation
try {
const cookie = JSON.parse(cookieContents);
if (cookie && typeof cookie.token === 'string') {