From e49b5361c6442aa727e3718ea813ba413e506ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulises=20Gasc=C3=B3n?= Date: Thu, 1 Aug 2024 13:38:48 +0200 Subject: [PATCH] feat: refactor Timing Safe Equal comparative using crypto library - Removed dependency tsscmp --- README.md | 2 ++ index.js | 28 ++++++++++++++++++++++------ package.json | 3 --- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 3cfb376..d04b1e7 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,8 @@ app.listen(3000, () => { Async callback verification, accepting `fn(err, user)`. +Note: It is recommended to use `crypto.timingSafeEqual(a, b)` [(Doc)](https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b) to compare the user and password strings. + ```js connect() .use(basicAuth(function(user, pass, fn){ diff --git a/index.js b/index.js index f2bb33e..e8f292b 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ -const timingSafeCompare = require('tsscmp'); const http = require('http'); +const crypto = require('crypto'); /*! * Connect - basicAuth @@ -26,8 +26,10 @@ const http = require('http'); * * connect() * .use(connect.basicAuth(function(user, pass){ - * return 'tj' == user && 'wahoo' == pass; + * return 'tj' === user && 'wahoo' === pass; * })) + * + * Note: it is recommended to use `crypto.timingSafeEqual(a, b)` https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b * * Async callback verification, accepting `fn(err, user)`. * @@ -50,11 +52,25 @@ module.exports = function basicAuth(callback, realm) { password = realm; if (typeof password !== 'string') throw new Error('password argument required'); realm = arguments[2]; - callback = function(user, pass){ - const usernameValid = timingSafeCompare(user, username); - const passwordValid = timingSafeCompare(pass, password); + + callback = (user, pass) => { + const buffers = [ + Buffer.from(user), + Buffer.from(pass), + Buffer.from(username), + Buffer.from(password) + ]; + + // Determine the maximum length among all buffers + const maxLength = Math.max(...buffers.map(buf => buf.length)); + + // Pad each buffer to the maximum length + const paddedBuffers = buffers.map(buf => Buffer.concat([buf, Buffer.alloc(maxLength - buf.length)])); + + const usernameValid = crypto.timingSafeEqual(paddedBuffers[0], paddedBuffers[2]) + const passwordValid = crypto.timingSafeEqual(paddedBuffers[1], paddedBuffers[3]) return usernameValid && passwordValid; - } + }; } realm = realm || 'Authorization Required'; diff --git a/package.json b/package.json index d36eb81..9829d7e 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,5 @@ }, "scripts": { "test": "make test" - }, - "dependencies": { - "tsscmp": "^1.0.6" } }