From 7e76c540127a6bcfd5378dc05cee72550755b13d Mon Sep 17 00:00:00 2001 From: chenos Date: Thu, 10 Feb 2022 19:53:18 +0800 Subject: [PATCH] feat: using crypto.scrypt instead of bcrypt --- packages/database/package.json | 4 - .../database/src/fields/password-field.ts | 38 ++++++-- packages/plugin-users/package.json | 4 +- packages/plugin-users/src/actions/users.ts | 6 +- yarn.lock | 91 ++----------------- 5 files changed, 43 insertions(+), 100 deletions(-) diff --git a/packages/database/package.json b/packages/database/package.json index b9aafd6a8..8f1da5854 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -14,15 +14,11 @@ "dependencies": { "@nocobase/utils": "^0.6.0-alpha.0", "async-mutex": "^0.3.2", - "bcrypt": "^5.0.0", "deepmerge": "^4.2.2", "flat": "^5.0.2", "glob": "^7.1.6", "sequelize": "^6.9.0" }, - "devDependencies": { - "@types/bcrypt": "^5.0.0" - }, "repository": { "type": "git", "url": "git+https://github.com/nocobase/nocobase.git", diff --git a/packages/database/src/fields/password-field.ts b/packages/database/src/fields/password-field.ts index 802c90d13..88c34c04b 100644 --- a/packages/database/src/fields/password-field.ts +++ b/packages/database/src/fields/password-field.ts @@ -1,9 +1,17 @@ +import crypto from 'crypto'; import { DataTypes } from 'sequelize'; import { BaseColumnFieldOptions, Field } from './field'; -import bcrypt from 'bcrypt'; export interface PasswordFieldOptions extends BaseColumnFieldOptions { type: 'password'; + /** + * @default 64 + */ + length?: number; + /** + * @default 8 + */ + randomBytesSize?: number; } export class PasswordField extends Field { @@ -11,8 +19,27 @@ export class PasswordField extends Field { return DataTypes.STRING; } - async verify(data: string | Buffer, encrypted: string) { - return await bcrypt.compare(data, encrypted); + async verify(password: string, hash: string) { + const { length = 64, randomBytesSize = 8 } = this.options; + return new Promise((resolve, reject) => { + const salt = hash.substring(0, randomBytesSize * 2); + const key = hash.substring(randomBytesSize * 2); + crypto.scrypt(password, salt, length / 2 - randomBytesSize, (err, derivedKey) => { + if (err) reject(err); + resolve(key == derivedKey.toString('hex')); + }); + }); + } + + async hash(password: string) { + const { length = 64, randomBytesSize = 8 } = this.options; + return new Promise((resolve, reject) => { + const salt = crypto.randomBytes(randomBytesSize).toString('hex'); + crypto.scrypt(password, salt, length / 2 - randomBytesSize, (err, derivedKey) => { + if (err) reject(err); + resolve(salt + derivedKey.toString('hex')); + }); + }); } init() { @@ -23,10 +50,7 @@ export class PasswordField extends Field { } const value = model.get(name) as string; if (value) { - if (value.startsWith('$2b$10$') && value.length === 60) { - return; - } - const hash = await bcrypt.hash(value, 10); + const hash = await this.hash(value); model.set(name, hash); } else { model.set(name, null); diff --git a/packages/plugin-users/package.json b/packages/plugin-users/package.json index c98709fba..c4bb83c53 100644 --- a/packages/plugin-users/package.json +++ b/packages/plugin-users/package.json @@ -8,9 +8,7 @@ "build:cjs": "tsc --project tsconfig.build.json", "build:esm": "tsc --project tsconfig.build.json --module es2015 --outDir esm" }, - "dependencies": { - "crypto-random-string": "^3.3.0" - }, + "dependencies": {}, "devDependencies": { "@nocobase/test": "^0.6.0-alpha.0" }, diff --git a/packages/plugin-users/src/actions/users.ts b/packages/plugin-users/src/actions/users.ts index 9f346d23b..fac35ee47 100644 --- a/packages/plugin-users/src/actions/users.ts +++ b/packages/plugin-users/src/actions/users.ts @@ -1,6 +1,6 @@ import { Context, Next } from '@nocobase/actions'; import { PasswordField } from '@nocobase/database'; -import cryptoRandomString from 'crypto-random-string'; +import crypto from 'crypto'; export async function check(ctx: Context, next: Next) { if (ctx.state.currentUser) { @@ -33,7 +33,7 @@ export async function signin(ctx: Context, next: Next) { ctx.throw(401, '密码错误,请您重新输入'); } if (!user.token) { - user.token = cryptoRandomString({ length: 20 }); + user.token = crypto.randomBytes(20).toString('hex'); await user.save(); } ctx.body = user.toJSON(); @@ -78,7 +78,7 @@ export async function lostpassword(ctx: Context, next: Next) { if (!user) { ctx.throw(401, '邮箱账号未注册'); } - user.resetToken = cryptoRandomString({ length: 20 }); + user.resetToken = crypto.randomBytes(20).toString('hex'); await user.save(); ctx.body = user; await next(); diff --git a/yarn.lock b/yarn.lock index 731206a05..ef12b47ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2675,21 +2675,6 @@ stringify-entities "^3.0.1" stringify-object "^3.3.0" -"@mapbox/node-pre-gyp@^1.0.0": - version "1.0.7" - resolved "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.7.tgz#a26919cac6595662703330d1820a0ca206f45521" - integrity sha512-PplSvl4pJ5N3BkVjAdDzpPhVUPdC73JgttkR+LnBx2OORC1GCQsBjUeEuipf9uOaAM1SbxcdZFfR3KDTKm2S0A== - dependencies: - detect-libc "^1.0.3" - https-proxy-agent "^5.0.0" - make-dir "^3.1.0" - node-fetch "^2.6.5" - nopt "^5.0.0" - npmlog "^6.0.0" - rimraf "^3.0.2" - semver "^7.3.5" - tar "^6.1.11" - "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -3001,13 +2986,6 @@ dependencies: "@babel/types" "^7.3.0" -"@types/bcrypt@^5.0.0": - version "5.0.0" - resolved "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz#a835afa2882d165aff5690893db314eaa98b9f20" - integrity sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw== - dependencies: - "@types/node" "*" - "@types/body-parser@*": version "1.19.2" resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" @@ -4114,7 +4092,7 @@ aproba@^1.0.3: resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== -"aproba@^1.0.3 || ^2.0.0", aproba@^2.0.0: +aproba@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== @@ -4124,14 +4102,6 @@ arch@^2.1.1: resolved "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== -are-we-there-yet@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" - integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== - dependencies: - delegates "^1.0.0" - readable-stream "^3.6.0" - are-we-there-yet@~1.1.2: version "1.1.7" resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" @@ -4562,14 +4532,6 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -bcrypt@^5.0.0: - version "5.0.1" - resolved "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz#f1a2c20f208e2ccdceea4433df0c8b2c54ecdf71" - integrity sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw== - dependencies: - "@mapbox/node-pre-gyp" "^1.0.0" - node-addon-api "^3.1.0" - before-after-hook@^2.2.0: version "2.2.2" resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" @@ -5289,11 +5251,6 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-support@^1.1.2: - version "1.1.3" - resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - colorette@^2.0.16: version "2.0.16" resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" @@ -5429,7 +5386,7 @@ console-browserify@^1.1.0: resolved "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== -console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: +console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= @@ -5778,13 +5735,6 @@ crypto-random-string@^1.0.0: resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= -crypto-random-string@^3.3.0: - version "3.3.1" - resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-3.3.1.tgz#13cee94cac8001e4842501608ef779e0ed08f82d" - integrity sha512-5j88ECEn6h17UePrLi6pn1JcLtAiANa3KExyr9y9Z5vo2mv56Gh3I4Aja/B9P9uyMwyxNHAHWv+nE72f30T5Dg== - dependencies: - type-fest "^0.8.1" - css-blank-pseudo@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" @@ -6137,7 +6087,7 @@ detect-indent@^6.0.0: resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== -detect-libc@^1.0.2, detect-libc@^1.0.3: +detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= @@ -7394,21 +7344,6 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= -gauge@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/gauge/-/gauge-4.0.0.tgz#afba07aa0374a93c6219603b1fb83eaa2264d8f8" - integrity sha512-F8sU45yQpjQjxKkm1UOAhf0U/O0aFt//Fl7hsrNVto+patMHjs7dPI9mFOGUKbhrgKm0S3EjW3scMFuQmWSROw== - dependencies: - ansi-regex "^5.0.1" - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.2" - console-control-strings "^1.0.0" - has-unicode "^2.0.1" - signal-exit "^3.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - wide-align "^1.1.2" - gauge@~2.7.3: version "2.7.4" resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -10231,7 +10166,7 @@ make-dir@^2.0.0, make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" -make-dir@^3.0.0, make-dir@^3.1.0: +make-dir@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== @@ -11097,7 +11032,7 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -node-addon-api@^3.0.0, node-addon-api@^3.1.0: +node-addon-api@^3.0.0: version "3.2.1" resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== @@ -11109,7 +11044,7 @@ node-dir@^0.1.17: dependencies: minimatch "^3.0.2" -node-fetch@^2.6.1, node-fetch@^2.6.5: +node-fetch@^2.6.1: version "2.6.6" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA== @@ -11459,16 +11394,6 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1: gauge "~2.7.3" set-blocking "~2.0.0" -npmlog@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-6.0.0.tgz#ba9ef39413c3d936ea91553db7be49c34ad0520c" - integrity sha512-03ppFRGlsyUaQFbGC2C8QWJN/C/K7PsfyD9aQdhVKAQIH4sQBc8WASqFBP7O+Ut4d2oo5LoeoboB3cGdBZSp6Q== - dependencies: - are-we-there-yet "^2.0.0" - console-control-strings "^1.1.0" - gauge "^4.0.0" - set-blocking "^2.0.0" - num2fraction@^1.2.2: version "1.2.2" resolved "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" @@ -15233,7 +15158,7 @@ tar@^4, tar@^4.4.12: safe-buffer "^5.2.1" yallist "^3.1.1" -tar@^6.0.2, tar@^6.1.0, tar@^6.1.11: +tar@^6.0.2, tar@^6.1.0: version "6.1.11" resolved "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== @@ -16389,7 +16314,7 @@ wicked-good-xpath@^1.3.0: resolved "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz#81b0e95e8650e49c94b22298fff8686b5553cf6c" integrity sha1-gbDpXoZQ5JyUsiKY//hoa1VTz2w= -wide-align@^1.1.0, wide-align@^1.1.2: +wide-align@^1.1.0: version "1.1.5" resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==