import { getModelForClass, index, modelOptions, mongoose, prop, ReturnModelType, Severity } from '@typegoose/typegoose' import { dbconn } from 'decorators/dbconn' import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses' import { BaseModule } from './Base' import { genRandomString, sha512 } from 'zutils/utils/security.util' import { PlatEnum } from '../enums/PlatEnum' /** * copy from wallet-svr */ /** * 生成密码的salt和hash * @param userpassword * @return {{salt: any, passwordHash: string}} */ export function saltHashPassword(userpassword: string) { let salt = genRandomString(16) return sha512(userpassword, salt) } /** * 验证密码 * @param userpassword * @param passwordDb * @param salt * @return {boolean} */ export function verifyPass(userpassword: string, passwordDb: string, salt: string) { let passwordData = sha512(userpassword, salt) return passwordData.passwordHash === passwordDb } export interface AccountClass extends Base, TimeStamps {} @dbconn('wallet') @index({ plat: 1, openId: 1 }, { unique: true }) @modelOptions({ schemaOptions: { collection: 'account', timestamps: true }, options: { allowMixed: Severity.ALLOW } }) export class AccountClass extends BaseModule { @prop({ enum: PlatEnum, default: PlatEnum.GOOGLE }) public plat!: PlatEnum @prop({ required: true }) public openId!: string @prop() public nickname?: string @prop() public avatar?: string /** * 第三方登录信息中返回的email, 会根据返回信息更新 * 实际使用中使用下面的 emailReal */ @prop() public email?: string @prop() public password?: string @prop() public salt?: string /** * 第三方登录信息中返回的email认证信息 */ @prop({ required: true, default: false }) public emailVerified: boolean @prop({ default: 0 }) public sex?: string @prop() public locale?: string @prop({ default: false }) public locked: boolean @prop() public lockedTime?: Date @prop() public comment?: string @prop() public lastLogin?: Date @prop() public accessToken?: string @prop() public accessTokenExpire?: number @prop() public refreshToken?: string @prop() public refreshTokenExpire?: number @prop({ type: mongoose.Schema.Types.Mixed }) public scope?: any /** * 是否通过了邮件认证(我们发起的) */ @prop({ required: true, default: false }) public verified: boolean /** * 认证后的email */ @prop() public emailReal?: string @prop() public emailVerifyTime?: number // 用于标识该账号是否已经重置过 @prop({ default: 0 }) public accountVersion: number @prop() public platform: string public static async findByEmail(this: ReturnModelType, email) { return this.findOne({ email, plat: PlatEnum.EMAIL }).exec() } public updatePassword(password: string) { if (password) { let passData = saltHashPassword(password) this.password = passData.passwordHash this.salt = passData.salt } } public verifyPassword(password: string) { return verifyPass(password, this.password, this.salt) } } export const Account = getModelForClass(AccountClass, { existingConnection: AccountClass.db })