@brontosaurus/db
Version:
:ocean: Schema for brontosaurus
374 lines (373 loc) • 11.4 kB
JavaScript
"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);