UNPKG

csrf-guard

Version:

Simple Anti-CSRF Token implementation for Express applications.

138 lines (113 loc) 3.61 kB
const { SynchronizerPattern, HMACBasedPattern } = require('./lib/token'); class CSRFGuard { /** * Set up the main middleware * @constructor * @param {Object} [options] - Custom options (optional) * @returns {Function} - CSRF Guard middleware */ constructor(options = {}) { this.secret = options.secret; this.expiryTime = options.expiryTime || null; this.synchronizer = typeof options.synchronizer === 'boolean' ? options.synchronizer : true; this.errorMessages = { noSecret: 'Secret key must be included.', noSession: 'Session object is not available.', }; if (!this.secret) { throw new Error(this.errorMessages.noSecret); } return this.middleware.bind(this); } /** * @property {Function} middleware - The main Anti-CSRF middleware * @param {Object} req - Express request object * @param {Object} res - Express response object * @param {Function} next - Express next middleware * @returns {void} - Call the next middleware */ async middleware(req, res, next) { /** * Generate and set the token * @param {Boolean} [forced] - Force to generate a new token (optional) * @returns {String} - Generated token for the client */ const getToken = async (forced = false) => { /** * Forced option can be used only with Synchronizer pattern. * With HMAC Based pattern, a new token is generated anyway. */ if (!req.session) { throw new Error(this.errorMessages.noSession); } /** * Using Synchronizer Token Pattern */ if (this.synchronizer) { if (!forced) { const token = req.session.csrf_token; if (token) { const signedToken = SynchronizerPattern.signToken( token, this.secret ); return signedToken; } } const { serverToken, clientToken } = await SynchronizerPattern.getToken( this.secret ); req.session.csrf_token = serverToken; return clientToken; } /** * Using HMAC Based Token Pattern */ const sid = req.session.id; const token = HMACBasedPattern.generateToken(sid, this.secret); return token; }; const isTokenValid = () => { if (!req.session) { throw new Error(this.errorMessages.noSession); } const clientToken = (req.body && req.body.csrf_token) || (req.query && req.query.csrf_token) || req.get('csrf-token') || req.get('xsrf-token') || req.get('x-csrf-token') || req.get('x-xsrf-token'); if (!clientToken) return false; /** * Using Synchronizer Token Pattern */ if (this.synchronizer) { if (!req.session.csrf_token) return false; const serverToken = req.session.csrf_token; const isValid = SynchronizerPattern.verifyToken( serverToken, clientToken, this.secret ); return isValid; } /** * Using HMAC Based Token Pattern */ const sid = req.session.id; const isValid = HMACBasedPattern.verifyToken( clientToken, sid, this.secret, this.expiryTime ); return isValid; }; req.getToken = getToken; req.isTokenValid = isTokenValid; return next(); } } module.exports = CSRFGuard;