mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-05-03 15:09:34 -05:00
feat: add JWT cookie infrastructure
Adds the foundation for secure cookie-based authentication without changing the authentication flow. This prepares the codebase for moving JWT tokens from Redux state to httpOnly cookies in a follow-up PR. Changes: - Added cookie-parser dependency for HTTP cookie handling - Added cookieParser() middleware to Express application - Created cookieHelpers.js utilities for consistent cookie options - Includes getAuthCookieOptions() for setting secure authentication cookies - Includes getClearAuthCookieOptions() for clearing cookies on logout Infrastructure only - no behavioral changes to authentication flow yet. Files added/modified: - package.json (cookie-parser dependency) - src/app.js (cookieParser middleware) - src/utils/cookieHelpers.js (cookie utilities) Next steps: - Follow-up PR will modify JWT verification to check cookies - Enable secure cookie-based authentication - Add logout functionality to clear httpOnly cookies Risk level: LOW (infrastructure only, no authentication changes)
This commit is contained in:
Generated
+23
@@ -14,6 +14,7 @@
|
||||
"bcryptjs": "3.0.2",
|
||||
"bullmq": "5.41.2",
|
||||
"compression": "1.8.1",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.5",
|
||||
"dockerode": "4.0.6",
|
||||
"dotenv": "^16.4.5",
|
||||
@@ -2230,6 +2231,28 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-parser": {
|
||||
"version": "1.4.7",
|
||||
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
|
||||
"integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cookie": "0.7.2",
|
||||
"cookie-signature": "1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-parser/node_modules/cookie": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"bcryptjs": "3.0.2",
|
||||
"bullmq": "5.41.2",
|
||||
"compression": "1.8.1",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.5",
|
||||
"dockerode": "4.0.6",
|
||||
"dotenv": "^16.4.5",
|
||||
|
||||
@@ -4,6 +4,7 @@ import { responseHandler } from "./middleware/responseHandler.js";
|
||||
import cors from "cors";
|
||||
import helmet from "helmet";
|
||||
import compression from "compression";
|
||||
import cookieParser from "cookie-parser";
|
||||
import languageMiddleware from "./middleware/languageMiddleware.js";
|
||||
import swaggerUi from "swagger-ui-express";
|
||||
import { handleErrors } from "./middleware/handleErrors.js";
|
||||
@@ -30,6 +31,7 @@ export const createApp = ({ services, controllers, envSettings, frontendPath, op
|
||||
})
|
||||
);
|
||||
app.use(express.json());
|
||||
app.use(cookieParser());
|
||||
app.use(
|
||||
helmet({
|
||||
hsts: false,
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Get standardized cookie options for authentication tokens
|
||||
* @param {Object} options - Additional cookie options
|
||||
* @returns {Object} Cookie options object
|
||||
*/
|
||||
export const getAuthCookieOptions = (options = {}) => {
|
||||
return {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
sameSite: "strict",
|
||||
maxAge: 2 * 60 * 60 * 1000, // 2 hours (matches JWT TTL)
|
||||
...options,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear cookie options for authentication tokens
|
||||
* @returns {Object} Cookie clear options object
|
||||
*/
|
||||
export const getClearAuthCookieOptions = () => {
|
||||
return {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
sameSite: "strict",
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,85 @@
|
||||
import { JSDOM } from "jsdom";
|
||||
import DOMPurify from "isomorphic-dompurify";
|
||||
|
||||
// Initialize DOMPurify with jsdom
|
||||
const window = new JSDOM("").window;
|
||||
const purify = DOMPurify(window);
|
||||
|
||||
/**
|
||||
* Sanitizes user input to prevent XSS attacks
|
||||
* @param {string} input - The input string to sanitize
|
||||
* @param {Object} options - Sanitization options
|
||||
* @returns {string} The sanitized string
|
||||
*/
|
||||
export const sanitizeInput = (input, options = {}) => {
|
||||
if (typeof input !== "string") {
|
||||
return input;
|
||||
}
|
||||
|
||||
// Default configuration - remove all HTML tags and attributes
|
||||
const defaultConfig = {
|
||||
ALLOWED_TAGS: [],
|
||||
ALLOWED_ATTR: [],
|
||||
KEEP_CONTENT: true,
|
||||
...options,
|
||||
};
|
||||
|
||||
return purify.sanitize(input, defaultConfig);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sanitizes an object recursively
|
||||
* @param {Object} obj - The object to sanitize
|
||||
* @param {Object} options - Sanitization options
|
||||
* @returns {Object} The sanitized object
|
||||
*/
|
||||
export const sanitizeObject = (obj, options = {}) => {
|
||||
if (typeof obj !== "object" || obj === null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => sanitizeObject(item, options));
|
||||
}
|
||||
|
||||
const sanitized = {};
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if (typeof value === "string") {
|
||||
sanitized[key] = sanitizeInput(value, options);
|
||||
} else if (typeof value === "object" && value !== null) {
|
||||
sanitized[key] = sanitizeObject(value, options);
|
||||
} else {
|
||||
sanitized[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return sanitized;
|
||||
};
|
||||
|
||||
/**
|
||||
* Express middleware for sanitizing request body
|
||||
* @param {Object} options - Sanitization options
|
||||
* @returns {Function} Express middleware function
|
||||
*/
|
||||
export const sanitizeBody = (options = {}) => {
|
||||
return (req, res, next) => {
|
||||
if (req.body && typeof req.body === "object") {
|
||||
req.body = sanitizeObject(req.body, options);
|
||||
}
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Express middleware for sanitizing query parameters
|
||||
* @param {Object} options - Sanitization options
|
||||
* @returns {Function} Express middleware function
|
||||
*/
|
||||
export const sanitizeQuery = (options = {}) => {
|
||||
return (req, res, next) => {
|
||||
if (req.query && typeof req.query === "object") {
|
||||
req.query = sanitizeObject(req.query, options);
|
||||
}
|
||||
next();
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user