core: async hash calculation (#779)

This commit is contained in:
Yang Gao authored and GitHub committed 2024-04-09 08:13:50 +08:00
1 parent e207cb4194
commit e9a1ece808
5 files changed
+20 -14

No files matched your search

+4 -4
View File
@@ -216,8 +216,8 @@ class HomeSecurityHandler extends Handler {
if (this.session.sudoUid) { if (this.session.sudoUid) {
const udoc = await user.getById(domainId, this.session.sudoUid); const udoc = await user.getById(domainId, this.session.sudoUid);
if (!udoc) throw new UserNotFoundError(this.session.sudoUid); if (!udoc) throw new UserNotFoundError(this.session.sudoUid);
udoc.checkPassword(current); await udoc.checkPassword(current);
} else this.user.checkPassword(current); } else await this.user.checkPassword(current);
await user.setPassword(this.user._id, password); await user.setPassword(this.user._id, password);
await token.delByUid(this.user._id); await token.delByUid(this.user._id);
this.response.redirect = this.url('user_login'); this.response.redirect = this.url('user_login');
@@ -232,8 +232,8 @@ class HomeSecurityHandler extends Handler {
if (this.session.sudoUid) { if (this.session.sudoUid) {
const udoc = await user.getById(domainId, this.session.sudoUid); const udoc = await user.getById(domainId, this.session.sudoUid);
if (!udoc) throw new UserNotFoundError(this.session.sudoUid); if (!udoc) throw new UserNotFoundError(this.session.sudoUid);
udoc.checkPassword(current); await udoc.checkPassword(current);
} else this.user.checkPassword(current); } else await this.user.checkPassword(current);
const udoc = await user.getByEmail(domainId, email); const udoc = await user.getByEmail(domainId, email);
if (udoc) throw new UserAlreadyExistError(email); if (udoc) throw new UserAlreadyExistError(email);
await this.limitRate('send_mail', 3600, 30); await this.limitRate('send_mail', 3600, 30);
+3 -3
View File
@@ -117,7 +117,7 @@ class UserLoginHandler extends Handler {
await token.del(authnChallenge, token.TYPE_WEBAUTHN); await token.del(authnChallenge, token.TYPE_WEBAUTHN);
} else throw new ValidationError('2FA', 'Authn'); } else throw new ValidationError('2FA', 'Authn');
} }
udoc.checkPassword(password); await udoc.checkPassword(password);
await user.setById(udoc._id, { loginat: new Date(), loginip: this.request.ip }); await user.setById(udoc._id, { loginat: new Date(), loginip: this.request.ip });
if (!udoc.hasPriv(PRIV.PRIV_USER_PROFILE)) throw new BlacklistedError(uname, udoc.banReason); if (!udoc.hasPriv(PRIV.PRIV_USER_PROFILE)) throw new BlacklistedError(uname, udoc.banReason);
this.session.viewLang = ''; this.session.viewLang = '';
@@ -153,7 +153,7 @@ class UserSudoHandler extends Handler {
await token.del(authnChallenge, token.TYPE_WEBAUTHN); await token.del(authnChallenge, token.TYPE_WEBAUTHN);
} else if (this.user.tfa && tfa) { } else if (this.user.tfa && tfa) {
if (!verifyTFA(this.user._tfa, tfa)) throw new InvalidTokenError('2FA'); if (!verifyTFA(this.user._tfa, tfa)) throw new InvalidTokenError('2FA');
} else this.user.checkPassword(password); } else await this.user.checkPassword(password);
this.session.sudo = Date.now(); this.session.sudo = Date.now();
if (this.session.sudoArgs.method.toLowerCase() !== 'get') { if (this.session.sudoArgs.method.toLowerCase() !== 'get') {
this.response.template = 'user_sudo_redirect.html'; this.response.template = 'user_sudo_redirect.html';
@@ -445,7 +445,7 @@ class UserDetailHandler extends Handler {
class UserDeleteHandler extends Handler { class UserDeleteHandler extends Handler {
async post({ password }) { async post({ password }) {
this.user.checkPassword(password); await this.user.checkPassword(password);
const tid = await ScheduleModel.add({ const tid = await ScheduleModel.add({
executeAfter: moment().add(7, 'days').toDate(), executeAfter: moment().add(7, 'days').toDate(),
type: 'script', type: 'script',
+1 -1
View File
@@ -787,7 +787,7 @@ export interface ModuleInterfaces {
get: (this: Handler) => Promise<void>; get: (this: Handler) => Promise<void>;
callback: (this: Handler, args: Record<string, any>) => Promise<OAuthUserResponse>; callback: (this: Handler, args: Record<string, any>) => Promise<OAuthUserResponse>;
}; };
hash: (password: string, salt: string, user: User) => boolean | string; hash: (password: string, salt: string, user: User) => boolean | string | Promise<string>;
render: (name: string, state: any) => string | Promise<string>; render: (name: string, state: any) => string | Promise<string>;
} }
+7 -2
View File
@@ -1,7 +1,12 @@
import crypto from 'crypto'; import crypto from 'crypto';
function hash(password: string, salt: string) { function hash(password: string, salt: string): Promise<string> {
return crypto.pbkdf2Sync(password, salt, 100000, 64, 'sha256').toString('hex').substring(0, 64); return new Promise((resolve, reject) => {
crypto.pbkdf2(password, salt, 100000, 64, 'sha256', (err, key) => {
if (err) reject(err);
else resolve(key.toString('hex').substring(0, 64));
});
});
} }
export = hash; export = hash;
+5 -4
View File
@@ -141,10 +141,10 @@ export class User {
return false; return false;
} }
checkPassword(password: string) { async checkPassword(password: string) {
const h = global.Hydro.module.hash[this.hashType]; const h = global.Hydro.module.hash[this.hashType];
if (!h) throw new Error('Unknown hash method'); if (!h) throw new Error('Unknown hash method');
const result = h(password, this._salt, this); const result = await h(password, this._salt, this);
if (result !== true && result !== this._hash) { if (result !== true && result !== this._hash) {
throw new LoginError(this.uname); throw new LoginError(this.uname);
} }
@@ -290,7 +290,7 @@ class UserModel {
const salt = String.random(); const salt = String.random();
const res = await coll.findOneAndUpdate( const res = await coll.findOneAndUpdate(
{ _id: uid }, { _id: uid },
{ $set: { salt, hash: pwhash(password, salt), hashType: 'hydro' } }, { $set: { salt, hash: await pwhash(password, salt), hashType: 'hydro' } },
{ returnDocument: 'after' }, { returnDocument: 'after' },
); );
deleteUserCache(res.value); deleteUserCache(res.value);
@@ -328,7 +328,8 @@ class UserModel {
mailLower: handleMailLower(mail), mailLower: handleMailLower(mail),
uname, uname,
unameLower: uname.trim().toLowerCase(), unameLower: uname.trim().toLowerCase(),
hash: pwhash(password.toString(), salt), // eslint-disable-next-line no-await-in-loop
hash: await pwhash(password.toString(), salt),
salt, salt,
hashType: 'hydro', hashType: 'hydro',
regat: new Date(), regat: new Date(),