csrf-sync
Version:
A utility package to help implement stateful CSRF protection using the Synchroniser Token Pattern in express.
99 lines (97 loc) • 3.67 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
csrfSync: () => csrfSync
});
module.exports = __toCommonJS(src_exports);
var import_node_crypto = require("crypto");
var import_http_errors = __toESM(require("http-errors"), 1);
var csrfSync = ({
ignoredMethods = ["GET", "HEAD", "OPTIONS"],
getTokenFromRequest = (req) => req.headers["x-csrf-token"],
getTokenFromState = (req) => {
return req.session.csrfToken;
},
storeTokenInState = (req, token) => {
req.session.csrfToken = token;
},
size = 128,
errorConfig: { statusCode = 403, message = "invalid csrf token", code = "EBADCSRFTOKEN" } = {},
skipCsrfProtection
} = {}) => {
const ignoredMethodsSet = new Set(ignoredMethods);
const requiresCsrfProtection = (req) => {
const shouldSkip = typeof skipCsrfProtection === "function" && skipCsrfProtection(req);
return !(ignoredMethodsSet.has(req.method) || typeof shouldSkip === "boolean" && shouldSkip);
};
const invalidCsrfTokenError = (0, import_http_errors.default)(statusCode, message, {
code
});
const generateToken = (req, overwrite = false) => {
if (!overwrite && typeof getTokenFromState(req) === "string") {
return getTokenFromState(req);
}
const newToken = (0, import_node_crypto.randomBytes)(size).toString("hex");
storeTokenInState(req, newToken);
return newToken;
};
const revokeToken = (req) => {
storeTokenInState(req);
};
const isRequestValid = (req) => {
const receivedToken = getTokenFromRequest(req);
const storedToken = getTokenFromState(req);
return typeof receivedToken === "string" && typeof storedToken === "string" && receivedToken === storedToken;
};
const csrfSynchronisedProtection = (req, res, next) => {
req.csrfToken = (overwrite) => generateToken(req, overwrite);
if (!requiresCsrfProtection(req)) {
next();
} else if (isRequestValid(req)) {
next();
} else {
next(invalidCsrfTokenError);
}
};
return {
invalidCsrfTokenError,
csrfSynchronisedProtection,
generateToken,
getTokenFromRequest,
getTokenFromState,
isRequestValid,
storeTokenInState,
revokeToken
};
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
csrfSync
});