UNPKG

@brontosaurus/db

Version:
374 lines (373 loc) 11.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AccountModel = void 0; const random_1 = require("@sudoo/bark/random"); const random_2 = require("@sudoo/random"); const mongoose_1 = require("mongoose"); const account_1 = require("../interface/account"); const _2fa_1 = require("../util/2fa"); const auth_1 = require("../util/auth"); const verify_1 = require("../util/verify"); const common_1 = require("./common"); const PreviousPasswordSchema = new mongoose_1.Schema({ password: { type: String, required: true, }, reason: { type: String, required: true, }, changedAt: { type: Date, required: true, }, }, { _id: false }); const AccountSchema = new mongoose_1.Schema({ active: { type: Boolean, required: true, default: true, }, anchor: { type: String, required: true, index: true, }, username: { type: String, required: true, }, avatar: { type: String, required: false, }, namespace: { type: mongoose_1.Schema.Types.ObjectId, index: true, required: true, }, displayName: { type: String, required: false, }, attemptPoints: { type: Number, required: true, default: account_1.defaultInitialAttemptPoints, }, limbo: { type: Boolean, required: true, default: false, }, twoFA: { type: String, required: false, }, decorators: { type: [mongoose_1.Schema.Types.ObjectId], required: true, default: [], }, password: { type: String, required: true, }, previousPasswords: { type: [PreviousPasswordSchema], required: true, default: [], }, resetTokens: { type: [common_1.ResetTokenSchema], required: true, default: [], }, temporaryPasswords: { type: [common_1.SpecialPasswordSchema], required: true, default: [], }, applicationPasswords: { type: [common_1.SpecialPasswordSchema], required: true, default: [], }, phone: { type: String, required: false, index: true, }, email: { type: String, required: false, unique: true, index: true, }, infos: { type: [String], required: true, default: [], }, beacons: { type: [String], required: true, default: [], }, organization: { type: mongoose_1.Schema.Types.ObjectId, index: true, }, groups: { type: [mongoose_1.Schema.Types.ObjectId], required: true, default: [], }, tags: { type: [mongoose_1.Schema.Types.ObjectId], required: true, default: [], }, mint: { type: String, required: true, }, salt: { type: String, required: true, }, }, { timestamps: { createdAt: true, updatedAt: true, }, }); AccountSchema.methods.useAttemptPoint = function (point) { this.attemptPoints = this.attemptPoints - Math.abs(point); return this; }; AccountSchema.methods.addAttemptPoint = function (point) { this.attemptPoints = this.attemptPoints + Math.abs(point); return this; }; AccountSchema.methods.resetAttempt = function (amount = account_1.defaultInitialAttemptPoints) { this.attemptPoints = amount; return this; }; AccountSchema.methods.generateAndSetTwoFA = function (systemName = 'Brontosaurus Authorization') { const key = verify_1.generateKey(); const url = _2fa_1.generateURL(systemName, this.username, key); this.twoFA = key; return url; }; AccountSchema.methods.verifyTwoFA = function (code) { const key = this.twoFA; if (!key) { return false; } return verify_1.verifyCode(key, code); }; AccountSchema.methods.getInfoRecords = function () { return this.infos.reduce((previous, current) => { const splited = current.split(account_1.INFOS_SPLITTER); if (splited.length === 2) { return Object.assign(Object.assign({}, previous), { [splited[0]]: splited[1] }); } return previous; }, {}); }; AccountSchema.methods.getBeaconRecords = function () { return this.beacons.reduce((previous, current) => { const splited = current.split(account_1.INFOS_SPLITTER); if (splited.length === 2) { return Object.assign(Object.assign({}, previous), { [splited[0]]: splited[1] }); } return previous; }, {}); }; AccountSchema.methods.addGroup = function (id) { if (this.groups.some((group) => group.equals(id))) { return this; } this.groups = [...this.groups, id]; return this; }; AccountSchema.methods.removeGroup = function (id) { this.groups = this.groups.reduce((previous, current) => { if (current.equals(id)) { return previous; } return [...previous, current]; }, []); return this; }; AccountSchema.methods.setTempPassword = function (length = 8) { const tempPassword = random_1._Random.random(length); this.setPassword(tempPassword, 'temp'); return this; }; AccountSchema.methods.setPassword = function (password, reason) { const oldPassword = this.password; const saltedPassword = auth_1.garblePassword(password, this.salt); this.password = saltedPassword; this.addPreviousPassword(oldPassword, reason); this.resetMint(); return this; }; AccountSchema.methods.addPreviousPassword = function (password, reason) { this.previousPasswords = [ ...this.previousPasswords, { password, reason, changedAt: new Date(), }, ]; return this; }; AccountSchema.methods.resetMint = function () { this.mint = random_1._Random.unique(); return this; }; AccountSchema.methods.generateApplicationPassword = function (by, expireAt, tails = 3) { const password = random_2.randomApiKey(tails); const saltedPassword = auth_1.garblePassword(password, this.salt); const specialPassword = { passwordId: random_2.randomUnique(), by, expireAt, createdAt: new Date(), password: saltedPassword, }; this.applicationPasswords = [ ...this.applicationPasswords, specialPassword, ]; return password; }; AccountSchema.methods.suspendApplicationPassword = function (id, by) { const specialPasswords = this.applicationPasswords.map((each) => ({ passwordId: each.passwordId, by: each.by, expireAt: each.expireAt, createdAt: each.createdAt, password: each.password, suspendedBy: each.suspendedBy, suspendedAt: each.suspendedAt, })); for (const applicationPassword of specialPasswords) { if (applicationPassword.passwordId === id) { if (Boolean(applicationPassword.suspendedAt)) { return false; } applicationPassword.suspendedAt = new Date(); applicationPassword.suspendedBy = by; this.applicationPasswords = specialPasswords; return true; } } return false; }; AccountSchema.methods.generateTemporaryPassword = function (by, expireAt, tails = 3) { const password = random_2.randomApiKey(tails); const saltedPassword = auth_1.garblePassword(password, this.salt); const specialPassword = { passwordId: random_2.randomUnique(), by, expireAt, createdAt: new Date(), password: saltedPassword, }; this.temporaryPasswords = [ ...this.temporaryPasswords, specialPassword, ]; return password; }; AccountSchema.methods.generateResetToken = function (expireAt) { const password = random_2.randomString(); const saltedPassword = auth_1.garblePassword(password, this.salt); const resetToken = { expireAt, createdAt: new Date(), password: saltedPassword, }; this.resetTokens = [ ...this.resetTokens, resetToken, ]; return password; }; AccountSchema.methods.suspendTemporaryPassword = function (id, by) { const specialPasswords = this.temporaryPasswords.map((each) => ({ passwordId: each.passwordId, by: each.by, expireAt: each.expireAt, createdAt: each.createdAt, password: each.password, suspendedBy: each.suspendedBy, suspendedAt: each.suspendedAt, })); for (const applicationPassword of specialPasswords) { if (applicationPassword.passwordId === id) { if (Boolean(applicationPassword.suspendedAt)) { return false; } applicationPassword.suspendedAt = new Date(); applicationPassword.suspendedBy = by; this.temporaryPasswords = specialPasswords; return true; } } return false; }; AccountSchema.methods.verifyPassword = function (password) { const saltedPassword = auth_1.garblePassword(password, this.salt); return this.password === saltedPassword; }; AccountSchema.methods.verifyPreviousPassword = function (password) { const saltedPassword = auth_1.garblePassword(password, this.salt); for (const previousPassword of this.previousPasswords) { if (auth_1.verifyPreviousPassword(saltedPassword, previousPassword)) { return previousPassword; } } return null; }; AccountSchema.methods.verifyTemporaryPassword = function (password) { const saltedPassword = auth_1.garblePassword(password, this.salt); for (const temporaryPassword of this.temporaryPasswords) { if (auth_1.verifySpecialPassword(saltedPassword, temporaryPassword)) { return true; } } return false; }; AccountSchema.methods.verifyApplicationPassword = function (password) { const saltedPassword = auth_1.garblePassword(password, this.salt); for (const applicationPassword of this.applicationPasswords) { if (auth_1.verifySpecialPassword(saltedPassword, applicationPassword)) { return true; } } return false; }; AccountSchema.methods.verifySpecialPasswords = function (password) { return this.verifyTemporaryPassword(password) || this.verifyApplicationPassword(password); }; AccountSchema.methods.verifyResetToken = function (password) { const saltedPassword = auth_1.garblePassword(password, this.salt); for (const resetToken of this.resetTokens) { if (auth_1.verifyResetToken(saltedPassword, resetToken)) { return true; } } return false; }; AccountSchema.methods.clearResetTokens = function () { this.resetTokens = []; return this; }; exports.AccountModel = mongoose_1.model('Account', AccountSchema);