aboutsummaryrefslogtreecommitdiff
path: root/node_modules/csurf/index.js
diff options
context:
space:
mode:
authornanalelfe <nargiza.nosirova@mail.utoronto.ca>2016-07-21 06:29:31 +0000
committernanalelfe <nargiza.nosirova@mail.utoronto.ca>2016-07-21 06:29:31 +0000
commitee8e1a13b60a6adfdc691b2a9b57289188397641 (patch)
tree096633208d9b8b6b59b67f4034a0cbb41e1f4c5d /node_modules/csurf/index.js
parent689df70a38ace2f88cfef6ab50f10dc546b48f00 (diff)
need pull
Diffstat (limited to 'node_modules/csurf/index.js')
-rw-r--r--node_modules/csurf/index.js306
1 files changed, 306 insertions, 0 deletions
diff --git a/node_modules/csurf/index.js b/node_modules/csurf/index.js
new file mode 100644
index 0000000..9b8c19e
--- /dev/null
+++ b/node_modules/csurf/index.js
@@ -0,0 +1,306 @@
+/*!
+ * csurf
+ * Copyright(c) 2011 Sencha Inc.
+ * Copyright(c) 2014 Jonathan Ong
+ * Copyright(c) 2014-2016 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var Cookie = require('cookie')
+var createError = require('http-errors')
+var sign = require('cookie-signature').sign
+var Tokens = require('csrf')
+
+/**
+ * Module exports.
+ * @public
+ */
+
+module.exports = csurf
+
+/**
+ * CSRF protection middleware.
+ *
+ * This middleware adds a `req.csrfToken()` function to make a token
+ * which should be added to requests which mutate
+ * state, within a hidden form field, query-string etc. This
+ * token is validated against the visitor's session.
+ *
+ * @param {Object} options
+ * @return {Function} middleware
+ * @public
+ */
+
+function csurf (options) {
+ var opts = options || {}
+
+ // get cookie options
+ var cookie = getCookieOptions(opts.cookie)
+
+ // get session options
+ var sessionKey = opts.sessionKey || 'session'
+
+ // get value getter
+ var value = opts.value || defaultValue
+
+ // token repo
+ var tokens = new Tokens(opts)
+
+ // ignored methods
+ var ignoreMethods = opts.ignoreMethods === undefined
+ ? ['GET', 'HEAD', 'OPTIONS']
+ : opts.ignoreMethods
+
+ if (!Array.isArray(ignoreMethods)) {
+ throw new TypeError('option ignoreMethods must be an array')
+ }
+
+ // generate lookup
+ var ignoreMethod = getIgnoredMethods(ignoreMethods)
+
+ return function csrf (req, res, next) {
+ // validate the configuration against request
+ if (!verifyConfiguration(req, sessionKey, cookie)) {
+ return next(new Error('misconfigured csrf'))
+ }
+
+ // get the secret from the request
+ var secret = getSecret(req, sessionKey, cookie)
+ var token
+
+ // lazy-load token getter
+ req.csrfToken = function csrfToken () {
+ var sec = !cookie
+ ? getSecret(req, sessionKey, cookie)
+ : secret
+
+ // use cached token if secret has not changed
+ if (token && sec === secret) {
+ return token
+ }
+
+ // generate & set new secret
+ if (sec === undefined) {
+ sec = tokens.secretSync()
+ setSecret(req, res, sessionKey, sec, cookie)
+ }
+
+ // update changed secret
+ secret = sec
+
+ // create new token
+ token = tokens.create(secret)
+
+ return token
+ }
+
+ // generate & set secret
+ if (!secret) {
+ secret = tokens.secretSync()
+ setSecret(req, res, sessionKey, secret, cookie)
+ }
+
+ // verify the incoming token
+ if (!ignoreMethod[req.method] && !tokens.verify(secret, value(req))) {
+ return next(createError(403, 'invalid csrf token', {
+ code: 'EBADCSRFTOKEN'
+ }))
+ }
+
+ next()
+ }
+}
+
+/**
+ * Default value function, checking the `req.body`
+ * and `req.query` for the CSRF token.
+ *
+ * @param {IncomingMessage} req
+ * @return {String}
+ * @api private
+ */
+
+function defaultValue (req) {
+ return (req.body && req.body._csrf) ||
+ (req.query && req.query._csrf) ||
+ (req.headers['csrf-token']) ||
+ (req.headers['xsrf-token']) ||
+ (req.headers['x-csrf-token']) ||
+ (req.headers['x-xsrf-token'])
+}
+
+/**
+ * Get options for cookie.
+ *
+ * @param {boolean|object} [options]
+ * @returns {object}
+ * @api private
+ */
+
+function getCookieOptions (options) {
+ if (options !== true && typeof options !== 'object') {
+ return undefined
+ }
+
+ var opts = {
+ key: '_csrf',
+ path: '/'
+ }
+
+ if (options && typeof options === 'object') {
+ for (var prop in options) {
+ var val = options[prop]
+
+ if (val !== undefined) {
+ opts[prop] = val
+ }
+ }
+ }
+
+ return opts
+}
+
+/**
+ * Get a lookup of ignored methods.
+ *
+ * @param {array} methods
+ * @returns {object}
+ * @api private
+ */
+
+function getIgnoredMethods (methods) {
+ var obj = Object.create(null)
+
+ for (var i = 0; i < methods.length; i++) {
+ var method = methods[i].toUpperCase()
+ obj[method] = true
+ }
+
+ return obj
+}
+
+/**
+ * Get the token secret from the request.
+ *
+ * @param {IncomingMessage} req
+ * @param {String} sessionKey
+ * @param {Object} [cookie]
+ * @api private
+ */
+
+function getSecret (req, sessionKey, cookie) {
+ // get the bag & key
+ var bag = getSecretBag(req, sessionKey, cookie)
+ var key = cookie ? cookie.key : 'csrfSecret'
+
+ if (!bag) {
+ /* istanbul ignore next: should never actually run */
+ throw new Error('misconfigured csrf')
+ }
+
+ // return secret from bag
+ return bag[key]
+}
+
+/**
+ * Get the token secret bag from the request.
+ *
+ * @param {IncomingMessage} req
+ * @param {String} sessionKey
+ * @param {Object} [cookie]
+ * @api private
+ */
+
+function getSecretBag (req, sessionKey, cookie) {
+ if (cookie) {
+ // get secret from cookie
+ var cookieKey = cookie.signed
+ ? 'signedCookies'
+ : 'cookies'
+
+ return req[cookieKey]
+ } else {
+ // get secret from session
+ return req[sessionKey]
+ }
+}
+
+/**
+ * Set a cookie on the HTTP response.
+ *
+ * @param {OutgoingMessage} res
+ * @param {string} name
+ * @param {string} val
+ * @param {Object} [options]
+ * @api private
+ */
+
+function setCookie (res, name, val, options) {
+ var data = Cookie.serialize(name, val, options)
+
+ var prev = res.getHeader('set-cookie') || []
+ var header = Array.isArray(prev) ? prev.concat(data)
+ : Array.isArray(data) ? [prev].concat(data)
+ : [prev, data]
+
+ res.setHeader('set-cookie', header)
+}
+
+/**
+ * Set the token secret on the request.
+ *
+ * @param {IncomingMessage} req
+ * @param {OutgoingMessage} res
+ * @param {string} sessionKey
+ * @param {string} val
+ * @param {Object} [cookie]
+ * @api private
+ */
+
+function setSecret (req, res, sessionKey, val, cookie) {
+ if (cookie) {
+ // set secret on cookie
+ if (cookie.signed) {
+ var secret = req.secret
+
+ if (!secret) {
+ /* istanbul ignore next: should never actually run */
+ throw new Error('misconfigured csrf')
+ }
+
+ val = 's:' + sign(val, secret)
+ }
+
+ setCookie(res, cookie.key, val, cookie)
+ } else if (req[sessionKey]) {
+ // set secret on session
+ req[sessionKey].csrfSecret = val
+ } else {
+ /* istanbul ignore next: should never actually run */
+ throw new Error('misconfigured csrf')
+ }
+}
+
+/**
+ * Verify the configuration against the request.
+ * @private
+ */
+
+function verifyConfiguration (req, sessionKey, cookie) {
+ if (!getSecretBag(req, sessionKey, cookie)) {
+ return false
+ }
+
+ if (cookie && cookie.signed && !req.secret) {
+ return false
+ }
+
+ return true
+}