3 * Copyright(c) 2014 Jonathan Ong
4 * Copyright(c) 2015 Douglas Christopher Wilson
11 * Module dependencies.
15 var rndm = require('rndm')
16 var uid = require('uid-safe')
17 var compare = require('tsscmp')
18 var crypto = require('crypto')
19 var escape = require('base64-url').escape
26 module.exports = Tokens
29 * Token generation/verification class.
31 * @param {object} [options]
32 * @param {number} [options.saltLength=8] The string length of the salt
33 * @param {number} [options.secretLength=18] The byte length of the secret key
37 function Tokens (options) {
38 if (!(this instanceof Tokens)) {
39 return new Tokens(options)
42 var opts = options || {}
44 var saltLength = opts.saltLength !== undefined
48 if (typeof saltLength !== 'number' || !isFinite(saltLength) || saltLength < 1) {
49 throw new TypeError('option saltLength must be finite number > 1')
52 var secretLength = opts.secretLength !== undefined
56 if (typeof secretLength !== 'number' || !isFinite(secretLength) || secretLength < 1) {
57 throw new TypeError('option secretLength must be finite number > 1')
60 this.saltLength = saltLength
61 this.secretLength = secretLength
65 * Create a new CSRF token.
67 * @param {string} secret The secret for the token.
71 Tokens.prototype.create = function create (secret) {
72 if (!secret || typeof secret !== 'string') {
73 throw new TypeError('argument secret is required')
76 return this._tokenize(secret, rndm(this.saltLength))
80 * Create a new secret key.
82 * @param {function} [callback]
86 Tokens.prototype.secret = function secret (callback) {
87 return uid(this.secretLength, callback)
91 * Create a new secret key synchronously.
95 Tokens.prototype.secretSync = function secretSync () {
96 return uid.sync(this.secretLength)
100 * Tokenize a secret and salt.
104 Tokens.prototype._tokenize = function tokenize (secret, salt) {
107 .update(salt + '-' + secret, 'ascii')
109 return escape(salt + '-' + hash)
113 * Verify if a given token is valid for a given secret.
115 * @param {string} secret
116 * @param {string} token
120 Tokens.prototype.verify = function verify (secret, token) {
121 if (!secret || typeof secret !== 'string') {
125 if (!token || typeof token !== 'string') {
129 var index = token.indexOf('-')
135 var salt = token.substr(0, index)
136 var expected = this._tokenize(secret, salt)
138 return compare(token, expected)