diff --git a/.eslintrc.yml b/.eslintrc.yml index 1eece14..b87eb43 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,2 +1,4 @@ root: true -extends: standard +extends: + - standard + - plugin:markdown/recommended diff --git a/HISTORY.md b/HISTORY.md deleted file mode 100644 index f3c0bb3..0000000 --- a/HISTORY.md +++ /dev/null @@ -1,113 +0,0 @@ -3.1.0 / 2019-04-09 -================== - - * Include a TypeScript definition file - * deps: tsscmp@1.0.6 - - Use `crypto.timingSafeEqual` when available - * deps: uid-safe@2.1.5 - - perf: remove only trailing `=` - -3.0.6 / 2017-03-14 -================== - - * Remove `base64-url` dependency - -3.0.5 / 2017-03-07 -================== - - * deps: uid-safe@2.1.4 - - Remove `base64-url` dependency - -3.0.4 / 2016-11-13 -================== - - * deps: base64-url@1.3.3 - * deps: uid-safe@2.1.3 - - deps: base64-url@1.3.3 - -3.0.3 / 2016-05-26 -================== - - * deps: tsscmp@1.0.5 - -3.0.2 / 2016-05-22 -================== - - * Use `tsscmp` module for timing-safe token verification - * deps: base64-url@1.2.2 - * deps: uid-safe@2.1.1 - - deps: base64-url@1.2.2 - -3.0.1 / 2016-01-28 -================== - - * deps: rndm@1.2.0 - * deps: uid-safe@2.1.0 - - Use `random-bytes` for byte source - -3.0.0 / 2015-05-09 -================== - - * Remove `tokenize` export - * Remove `tokenize` option - * Return a prototype-based object rather than functions - - This means the resulting functions need to be called as methods - * Throw when missing secret to `tokens.create()` - * deps: uid-safe@~2.0.0 - - Use global `Promise` when returning a promise - -2.0.7 / 2015-05-03 -================== - - * Fix compatibility with `crypto.DEFAULT_ENCODING` global changes - -2.0.6 / 2015-02-13 -================== - - * deps: base64-url@1.2.1 - * deps: uid-safe@~1.1.0 - - Use `crypto.randomBytes`, if available - - deps: base64-url@1.2.1 - -2.0.5 / 2015-01-31 -================== - - * deps: base64-url@1.2.0 - * deps: uid-safe@~1.0.3 - - Fix error branch that would throw - - deps: base64-url@1.2.0 - -2.0.4 / 2015-01-08 -================== - - * deps: uid-safe@~1.0.2 - - Remove dependency on `mz` - -2.0.3 / 2014-12-30 -================== - - * Slight speed improvement for `verify` - * deps: base64-url@1.1.0 - * deps: rndm@~1.1.0 - -2.0.2 / 2014-11-09 -================== - - * deps: scmp@1.0.0 - -2.0.1 / 2014-08-22 -================== - - * Rename module to `csrf` - -2.0.0 / 2014-06-18 -================== - - * Use `uid-safe` module - * Use `base64-url` module - * Remove sync `.secret()` -- use `.secretSync()` instead - -1.0.4 / 2014-06-11 -================== - - * Make sure CSRF tokens are URL safe diff --git a/README.md b/README.md index fa60b4d..e3f0a6d 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ information for TypeScript projects. ```js -var Tokens = require('@fastify/csrf') +const Tokens = require('@fastify/csrf') ``` ### new Tokens([options]) @@ -75,8 +75,8 @@ expect the user's browser to provide back. ```js -var secret = tokens.secretSync() -var token = tokens.create(secret) +const secret = tokens.secretSync() +const token = tokens.create(secret) ``` The `userInfo` parameter can be used to protect against cookie tossing @@ -124,7 +124,7 @@ A synchronous version of `tokens.secret(callback)`. Please see ```js -var secret = tokens.secretSync() +const secret = tokens.secretSync() ``` #### tokens.verify(secret, token[, userInfo]) diff --git a/benchmark/create.js b/benchmark/create.js index a6e4fdc..b1aa6da 100644 --- a/benchmark/create.js +++ b/benchmark/create.js @@ -3,9 +3,9 @@ * Module dependencies. */ -var benchmark = require('benchmark') -var benchmarks = require('beautify-benchmark') -var Tokens = require('..') +const benchmark = require('benchmark') +const benchmarks = require('beautify-benchmark') +const Tokens = require('..') /** * Globals for benchmark.js @@ -14,7 +14,7 @@ var Tokens = require('..') global.tokens = new Tokens() global.secret = global.tokens.secretSync() -var suite = new benchmark.Suite() +const suite = new benchmark.Suite() suite.add({ name: 'create', diff --git a/benchmark/index.js b/benchmark/index.js index 2cd213c..fb820ca 100644 --- a/benchmark/index.js +++ b/benchmark/index.js @@ -1,11 +1,11 @@ -var fs = require('fs') -var path = require('path') -var spawn = require('child_process').spawn +const fs = require('fs') +const path = require('path') +const spawn = require('child_process').spawn -var exe = process.argv[0] -var cwd = process.cwd() +const exe = process.argv[0] +const cwd = process.cwd() -for (var dep in process.versions) { +for (const dep in process.versions) { console.log(' %s@%s', dep, process.versions[dep]) } @@ -14,17 +14,17 @@ console.log('') runScripts(fs.readdirSync(__dirname)) function runScripts (fileNames) { - var fileName = fileNames.shift() + const fileName = fileNames.shift() if (!fileName) return if (!/\.js$/i.test(fileName)) return runScripts(fileNames) if (fileName.toLowerCase() === 'index.js') return runScripts(fileNames) - var fullPath = path.join(__dirname, fileName) + const fullPath = path.join(__dirname, fileName) console.log('> %s %s', exe, path.relative(cwd, fullPath)) - var proc = spawn(exe, [fullPath], { + const proc = spawn(exe, [fullPath], { stdio: 'inherit' }) diff --git a/benchmark/secret.js b/benchmark/secret.js index 280d2e9..9c413f8 100644 --- a/benchmark/secret.js +++ b/benchmark/secret.js @@ -3,9 +3,9 @@ * Module dependencies. */ -var benchmark = require('benchmark') -var benchmarks = require('beautify-benchmark') -var Tokens = require('..') +const benchmark = require('benchmark') +const benchmarks = require('beautify-benchmark') +const Tokens = require('..') /** * Globals for benchmark.js @@ -13,7 +13,7 @@ var Tokens = require('..') global.tokens = new Tokens() -var suite = new benchmark.Suite() +const suite = new benchmark.Suite() suite.add({ name: 'secretSync', diff --git a/benchmark/verify.js b/benchmark/verify.js index 0a34291..d5e1657 100644 --- a/benchmark/verify.js +++ b/benchmark/verify.js @@ -3,9 +3,9 @@ * Module dependencies. */ -var benchmark = require('benchmark') -var benchmarks = require('beautify-benchmark') -var Tokens = require('..') +const benchmark = require('benchmark') +const benchmarks = require('beautify-benchmark') +const Tokens = require('..') /** * Globals for benchmark.js @@ -14,7 +14,7 @@ var Tokens = require('..') global.tokens = new Tokens() global.secret = global.tokens.secretSync() -var suite = new benchmark.Suite() +const suite = new benchmark.Suite() suite.add({ name: 'verify - valid', diff --git a/index.js b/index.js index 46bff77..545b67b 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,7 @@ * csrf * Copyright(c) 2014 Jonathan Ong * Copyright(c) 2015 Douglas Christopher Wilson + * Copyright(c) 2021-2022 Fastify Collaborators * MIT Licensed */ @@ -12,20 +13,20 @@ * @private */ -var rndm = require('rndm') -var uid = require('uid-safe') -var compare = require('tsscmp') -var crypto = require('crypto') +const rndm = require('rndm') +const uid = require('uid-safe') +const compare = require('tsscmp') +const crypto = require('crypto') /** * Module variables. * @private */ -var EQUAL_GLOBAL_REGEXP = /=/g -var PLUS_GLOBAL_REGEXP = /\+/g -var SLASH_GLOBAL_REGEXP = /\//g -var MINUS_GLOBAL_REGEXP = /-/g +const EQUAL_GLOBAL_REGEXP = /=/g +const PLUS_GLOBAL_REGEXP = /\+/g +const SLASH_GLOBAL_REGEXP = /\//g +const MINUS_GLOBAL_REGEXP = /-/g /** * Module exports. @@ -50,9 +51,9 @@ function Tokens (options) { return new Tokens(options) } - var opts = options || {} + const opts = options || {} - var saltLength = opts.saltLength !== undefined + const saltLength = opts.saltLength !== undefined ? opts.saltLength : 8 @@ -60,7 +61,7 @@ function Tokens (options) { throw new TypeError('option saltLength must be finite number > 1') } - var secretLength = opts.secretLength !== undefined + const secretLength = opts.secretLength !== undefined ? opts.secretLength : 18 @@ -68,7 +69,7 @@ function Tokens (options) { throw new TypeError('option secretLength must be finite number > 1') } - var validity = opts.validity !== undefined + const validity = opts.validity !== undefined ? opts.validity : 0 @@ -76,7 +77,7 @@ function Tokens (options) { throw new TypeError('option validity must be finite number > 0') } - var userInfo = opts.userInfo !== undefined + const userInfo = opts.userInfo !== undefined ? opts.userInfo : false @@ -101,7 +102,7 @@ Tokens.prototype.create = function create (secret, userInfo) { if (!secret || typeof secret !== 'string') { throw new TypeError('argument secret is required') } - var date = this.validity > 0 ? Date.now() : null + const date = this.validity > 0 ? Date.now() : null if (this.userInfo) { if (typeof userInfo !== 'string') { @@ -138,7 +139,7 @@ Tokens.prototype.secretSync = function secretSync () { */ Tokens.prototype._tokenize = function tokenize (secret, salt, date, userInfo) { - var toHash = '' + let toHash = '' if (date !== null) { toHash += date.toString(36) + '-' @@ -173,10 +174,9 @@ Tokens.prototype.verify = function verify (secret, token, userInfo) { return false } - var index = token.indexOf('-') - var toCompare = token - var date = null - var userInfo + let index = token.indexOf('-') + const toCompare = token + let date = null if (index === -1) { return false @@ -214,8 +214,8 @@ Tokens.prototype.verify = function verify (secret, token, userInfo) { } } - var salt = token.substr(0, index) - var expected = this._tokenize(secret, salt, date, userInfo) + const salt = token.substr(0, index) + const expected = this._tokenize(secret, salt, date, userInfo) return compare(toCompare, expected) } diff --git a/package.json b/package.json index cad07d9..fa026b4 100644 --- a/package.json +++ b/package.json @@ -24,13 +24,12 @@ "devDependencies": { "beautify-benchmark": "^0.2.4", "benchmark": "^2.1.4", - "bluebird": "^3.7.2", - "eslint": "^7.17.0", - "eslint-config-standard": "^16.0.2", + "eslint": "^8.0.0", + "eslint-config-standard": "^17.0.0", "eslint-plugin-import": "^2.22.1", "eslint-plugin-markdown": "^2.0.0", "eslint-plugin-node": "^11.0.0", - "eslint-plugin-promise": "^5.1.0", + "eslint-plugin-promise": "^6.0.0", "mocha": "^10.0.0", "nyc": "^15.0.0" }, @@ -41,9 +40,6 @@ "index.d.ts", "index.js" ], - "engines": { - "node": ">= 10.0" - }, "scripts": { "bench": "node benchmark/index.js", "lint": "eslint --plugin markdown --ext js,md .", diff --git a/test/test.js b/test/test.js index 8dade57..9a0ca49 100644 --- a/test/test.js +++ b/test/test.js @@ -1,8 +1,7 @@ -var assert = require('assert') -var crypto = require('crypto') +'use strict' -var Promise = global.Promise || require('bluebird') -var Tokens = require('..') +const assert = require('assert') +const Tokens = require('..') // Add Promise to mocha's global list // eslint-disable-next-line no-self-assign @@ -101,48 +100,27 @@ describe('Tokens', function () { }) it('should create a token', function () { - var token = this.tokens.create(this.secret) + const token = this.tokens.create(this.secret) assert.ok(typeof token === 'string') }) it('should always be the same length', function () { - var token = this.tokens.create(this.secret) + const token = this.tokens.create(this.secret) assert.ok(token.length > 0) - for (var i = 0; i < 1000; i++) { + for (let i = 0; i < 1000; i++) { assert.strictEqual(this.tokens.create(this.secret).length, token.length) } }) it('should not contain /, +, or =', function () { - for (var i = 0; i < 1000; i++) { - var token = this.tokens.create(this.secret) + for (let i = 0; i < 1000; i++) { + const token = this.tokens.create(this.secret) assert(!~token.indexOf('/')) assert(!~token.indexOf('+')) assert(!~token.indexOf('=')) } }) - - describe('when crypto.DEFAULT_ENCODING altered', function () { - before(function () { - // eslint-disable-next-line node/no-deprecated-api - this.defaultEncoding = crypto.DEFAULT_ENCODING - - // eslint-disable-next-line node/no-deprecated-api - crypto.DEFAULT_ENCODING = 'hex' - }) - - after(function () { - // eslint-disable-next-line node/no-deprecated-api - crypto.DEFAULT_ENCODING = this.defaultEncoding - }) - - it('should create a token', function () { - var token = this.tokens.create(this.secret) - assert.ok(typeof token === 'string') - assert.ok(token.length > 0) - }) - }) }) describe('.secret(callback)', function () { @@ -217,7 +195,7 @@ describe('Tokens', function () { }) it('should create a secret', function () { - var secret = this.tokens.secretSync() + const secret = this.tokens.secretSync() assert.ok(typeof secret === 'string') assert.ok(secret.length > 0) }) @@ -230,12 +208,12 @@ describe('Tokens', function () { }) it('should return `true` with valid tokens', function () { - var token = this.tokens.create(this.secret) + const token = this.tokens.create(this.secret) assert.ok(this.tokens.verify(this.secret, token)) }) it('should return `false` with invalid tokens', function () { - var token = this.tokens.create(this.secret) + const token = this.tokens.create(this.secret) assert.ok(!this.tokens.verify(this.tokens.secretSync(), token)) assert.ok(!this.tokens.verify('asdfasdfasdf', token)) }) @@ -261,32 +239,32 @@ describe('Tokens', function () { }) it('should return `true` with valid tokens', function () { - var token = this.tokens.create(this.secret) + const token = this.tokens.create(this.secret) assert.ok(this.tokens.verify(this.secret, token)) }) it('should return `false` if current time is outside the validity interval', function () { - var token = this.tokens.create(this.secret) - var now = Date.now() - var fn = Date.now + const token = this.tokens.create(this.secret) + const now = Date.now() + const fn = Date.now Date.now = function () { return now + 1 + 60 * 60 } - var valid = this.tokens.verify(this.secret, token) + const valid = this.tokens.verify(this.secret, token) Date.now = fn assert.ok(!valid) }) it('should return `true` if current time is at the max of the validity interval', function () { - var token = this.tokens.create(this.secret) - var now = Date.now() - var fn = Date.now + const token = this.tokens.create(this.secret) + const now = Date.now() + const fn = Date.now Date.now = function () { return now + 60 * 60 } - var valid = this.tokens.verify(this.secret, token) + const valid = this.tokens.verify(this.secret, token) Date.now = fn assert.ok(valid) }) it('should return `false` for tokens with no date', function () { - var token = this.tokens.create(this.secret) + let token = this.tokens.create(this.secret) token = token.substring(token.indexOf('-') + 1) assert.ok(!this.tokens.verify(this.secret, token)) }) @@ -301,22 +279,22 @@ describe('Tokens', function () { }) it('should return `true` with valid tokens', function () { - var token = this.tokens.create(this.secret, 'foobar') + const token = this.tokens.create(this.secret, 'foobar') assert.ok(this.tokens.verify(this.secret, token, 'foobar')) }) it('should return `false` if userInfo does not match', function () { - var token = this.tokens.create(this.secret, 'foo') + const token = this.tokens.create(this.secret, 'foo') assert.ok(!this.tokens.verify(this.secret, token, 'foobar')) }) it('should return `false` if userInfo is not set in verify', function () { - var token = this.tokens.create(this.secret, 'foo') + const token = this.tokens.create(this.secret, 'foo') assert.ok(!this.tokens.verify(this.secret, token)) }) it('should return `false` if userInfo is not a string in verify', function () { - var token = this.tokens.create(this.secret, 'foo') + const token = this.tokens.create(this.secret, 'foo') assert.ok(!this.tokens.verify(this.secret, token, {})) }) @@ -327,7 +305,7 @@ describe('Tokens', function () { }) it('should return `false` for tokens with no userInfo', function () { - var token = this.tokens.create(this.secret, 'foo') + let token = this.tokens.create(this.secret, 'foo') token = token.substring(token.indexOf('-') + 1) assert.ok(!this.tokens.verify(this.secret, token, 'foo')) })