- Updated CSRF middleware to enhance cookie value decoding. - Reformatted OAuth proxy token store initialization for better clarity. - Adjusted Challonge proxy router for consistent line breaks and readability. - Enhanced OAuth router error handling and response formatting. - Improved session router for better readability and consistency in fetching provider records. - Refactored OAuth token store to improve key derivation logging. - Cleaned up cookie options utility for better readability. - Enhanced Challonge client credentials composable for consistent API calls. - Streamlined OAuth composable for improved logging. - Refactored main.js for better readability in session initialization. - Improved Challonge v2.1 service error handling for better clarity. - Cleaned up API client utility for improved readability. - Enhanced ApiKeyManager.vue for better text formatting. - Refactored ChallongeTest.vue for improved readability in composable usage.
75 lines
2.1 KiB
JavaScript
75 lines
2.1 KiB
JavaScript
import { COOKIE_NAMES } from '../utils/cookie-options.js';
|
|
|
|
const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
|
|
|
|
function getCookieValuesFromHeader(cookieHeader, name) {
|
|
if (!cookieHeader || typeof cookieHeader !== 'string') return [];
|
|
const values = [];
|
|
const pattern = new RegExp(`(?:^|;\\s*)${name}=([^;]*)`, 'g');
|
|
let match;
|
|
while ((match = pattern.exec(cookieHeader)) !== null) {
|
|
values.push(match[1]);
|
|
}
|
|
return values;
|
|
}
|
|
|
|
export function csrfMiddleware(options = {}) {
|
|
const {
|
|
cookieName = COOKIE_NAMES.csrf,
|
|
headerName = 'x-csrf-token',
|
|
requireOriginCheck = false,
|
|
allowedOrigin = null
|
|
} = options;
|
|
|
|
return function csrf(req, res, next) {
|
|
if (SAFE_METHODS.has(req.method)) return next();
|
|
|
|
// Optional origin check hardening (recommended in production)
|
|
if (requireOriginCheck && allowedOrigin) {
|
|
const origin = req.headers.origin;
|
|
const referer = req.headers.referer;
|
|
const ok =
|
|
(origin && origin === allowedOrigin) ||
|
|
(!origin && referer && referer.startsWith(allowedOrigin));
|
|
|
|
if (!ok) {
|
|
return res.status(403).json({
|
|
error: 'CSRF origin check failed',
|
|
code: 'CSRF_ORIGIN_FAILED'
|
|
});
|
|
}
|
|
}
|
|
|
|
const csrfCookie = req.cookies?.[cookieName];
|
|
const csrfHeader = req.headers[headerName];
|
|
|
|
// Handle duplicate cookies with the same name (e.g. legacy '/api' path plus
|
|
// current '/' path). cookie-parser will pick one value, but the browser may
|
|
// send both. Accept if the header matches ANY provided cookie value.
|
|
const rawHeader = req.headers?.cookie || '';
|
|
const rawValues = getCookieValuesFromHeader(rawHeader, cookieName).map(
|
|
v => {
|
|
try {
|
|
return decodeURIComponent(v);
|
|
} catch {
|
|
return v;
|
|
}
|
|
}
|
|
);
|
|
const anyMatch = csrfHeader && rawValues.includes(csrfHeader);
|
|
|
|
if (
|
|
!csrfHeader ||
|
|
(!csrfCookie && !anyMatch) ||
|
|
(csrfCookie !== csrfHeader && !anyMatch)
|
|
) {
|
|
return res.status(403).json({
|
|
error: 'CSRF validation failed',
|
|
code: 'CSRF_FAILED'
|
|
});
|
|
}
|
|
|
|
return next();
|
|
};
|
|
}
|