GT2/GT2-Android/node_modules/csrf/index.js

160 lines
3.0 KiB
JavaScript
Raw Normal View History

/*!
* csrf
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
* @private
*/
var rndm = require('rndm')
var uid = require('uid-safe')
var compare = require('tsscmp')
var crypto = require('crypto')
/**
* Module variables.
* @private
*/
var EQUAL_GLOBAL_REGEXP = /=/g
var PLUS_GLOBAL_REGEXP = /\+/g
var SLASH_GLOBAL_REGEXP = /\//g
/**
* Module exports.
* @public
*/
module.exports = Tokens
/**
* Token generation/verification class.
*
* @param {object} [options]
* @param {number} [options.saltLength=8] The string length of the salt
* @param {number} [options.secretLength=18] The byte length of the secret key
* @public
*/
function Tokens (options) {
if (!(this instanceof Tokens)) {
return new Tokens(options)
}
var opts = options || {}
var saltLength = opts.saltLength !== undefined
? opts.saltLength
: 8
if (typeof saltLength !== 'number' || !isFinite(saltLength) || saltLength < 1) {
throw new TypeError('option saltLength must be finite number > 1')
}
var secretLength = opts.secretLength !== undefined
? opts.secretLength
: 18
if (typeof secretLength !== 'number' || !isFinite(secretLength) || secretLength < 1) {
throw new TypeError('option secretLength must be finite number > 1')
}
this.saltLength = saltLength
this.secretLength = secretLength
}
/**
* Create a new CSRF token.
*
* @param {string} secret The secret for the token.
* @public
*/
Tokens.prototype.create = function create (secret) {
if (!secret || typeof secret !== 'string') {
throw new TypeError('argument secret is required')
}
return this._tokenize(secret, rndm(this.saltLength))
}
/**
* Create a new secret key.
*
* @param {function} [callback]
* @public
*/
Tokens.prototype.secret = function secret (callback) {
return uid(this.secretLength, callback)
}
/**
* Create a new secret key synchronously.
* @public
*/
Tokens.prototype.secretSync = function secretSync () {
return uid.sync(this.secretLength)
}
/**
* Tokenize a secret and salt.
* @private
*/
Tokens.prototype._tokenize = function tokenize (secret, salt) {
return salt + '-' + hash(salt + '-' + secret)
}
/**
* Verify if a given token is valid for a given secret.
*
* @param {string} secret
* @param {string} token
* @public
*/
Tokens.prototype.verify = function verify (secret, token) {
if (!secret || typeof secret !== 'string') {
return false
}
if (!token || typeof token !== 'string') {
return false
}
var index = token.indexOf('-')
if (index === -1) {
return false
}
var salt = token.substr(0, index)
var expected = this._tokenize(secret, salt)
return compare(token, expected)
}
/**
* Hash a string with SHA1, returning url-safe base64
* @param {string} str
* @private
*/
function hash (str) {
return crypto
.createHash('sha1')
.update(str, 'ascii')
.digest('base64')
.replace(PLUS_GLOBAL_REGEXP, '-')
.replace(SLASH_GLOBAL_REGEXP, '_')
.replace(EQUAL_GLOBAL_REGEXP, '')
}