Files
auth-db/src/schema/auth.ts
2023-05-24 16:48:47 +00:00

81 lines
2.6 KiB
TypeScript

import { Document, InferSchemaType, Model, Schema, StringSchemaDefinition, Types } from 'mongoose';
import { Status } from '../constants/auth';
import { COLL_STRATEGY } from '../constants/db';
import { STRATEGIES } from '../constants/strategies';
import { StrategyDocument } from './strategy';
import { verify } from '../utils/password';
export interface Auth {
is2FA?: boolean;
record: StringSchemaDefinition;
username: string;
status: Status;
strategies: Types.ObjectId[] | StrategyDocument[];
}
interface AuthBaseDocument extends Auth, Document {
authenticate(password: string): Promise<boolean>;
getStrategy(method?: STRATEGIES): Promise<StrategyDocument | null>;
}
export interface AuthDocument extends AuthBaseDocument {
strategies: Types.ObjectId[];
}
export interface AuthPopulatedDocument extends AuthBaseDocument {
strategies: StrategyDocument[];
}
export interface AuthModel extends Model<AuthDocument> {
findByUsername(username: string): Promise<AuthDocument>;
getLocalStrategyForUsername(username: string): Promise<StrategyDocument>;
isUsernameAvailable(username: string): Promise<boolean>;
}
export const AuthSchema = new Schema<AuthDocument, AuthModel>(
{
is2FA: { type: Boolean, default: false },
record: { type: Types.ObjectId, unique: true },
status: {
type: Number,
enum: Status,
default: Status.UNVERIFIED,
index: true,
},
strategies: [{ type: Types.ObjectId, ref: COLL_STRATEGY, default: [] }],
username: { type: String, required: true, unique: true },
},
{
minimize: true,
timestamps: true,
},
);
AuthSchema.methods.authenticate = async function (this: AuthBaseDocument, password: string) {
const strategy = await this.getStrategy();
return !!strategy && verify(password, strategy.key);
};
AuthSchema.methods.getStrategy = async function (this: AuthBaseDocument, method = STRATEGIES.LOCAL) {
const doc = await this.populate<{ strategies: StrategyDocument[] }>('strategies');
return doc.strategies.filter((strategy) => strategy.method === method).pop() || null;
};
AuthSchema.statics = {
async findByUsername(username) {
return this.findOne({ username });
},
async getLocalStrategyForUsername(username) {
const doc = await this.findByUsername(username);
return !!doc && doc.getStrategy();
},
async isUsernameAvailable(username) {
return !this.findByUsername(username);
},
};
export type AuthSchema = InferSchemaType<typeof AuthSchema>;