import { InferSchemaType, Model, Schema, StringSchemaDefinition, Types } from 'mongoose'; import { TokenType } from '@mifi/auth-common/lib/enums/tokens'; import { getDefaultExpiresFor } from '@mifi/auth-common/lib/helpers/getDefaultExpiresFor'; import { sign, verify } from '@mifi/auth-common/lib/utils/jwt'; import { SignProps } from '@mifi/auth-common/lib/utils/jwt/sign'; export interface Token { auth: StringSchemaDefinition; expires?: number; type: TokenType; } export interface TokenModel extends Model { cleanupExpiredTokens(): { success: boolean; deletedCount: number }; getToken(type: TokenType, auth: Types.ObjectId, expires?: number): string; validateResetToken(token: string): Types.ObjectId | false; } export const TokenSchema = new Schema( { auth: { type: Types.ObjectId, index: true }, expires: { type: Number, required: true }, type: { type: String, enum: TokenType, required: true }, }, { minimize: true, timestamps: true, }, ); TokenSchema.statics = { async cleanupExpiredTokens() { const { acknowledged, deletedCount } = await this.deleteMany({ expires: { $lte: Date.now() }, }); return { success: acknowledged, deletedCount }; }, async getToken(type: TokenType, auth: StringSchemaDefinition, expires?: number) { const existing = await this.findOne({ type, auth }); if (existing) { await existing.deleteOne(); } const doc = await this.create({ type, auth, expires: expires || getDefaultExpiresFor(type), }); return sign({ sub: `${doc._id}`, exp: doc.expires, } as SignProps); }, async validateResetToken(token: string) { const { sub } = verify(token); if (sub) { const record = await this.findById(sub); if (record) { await record.deleteOne(); return !!record?.expires && record.expires >= Date.now() && record.auth; } } return false; }, }; export type TokenSchema = InferSchemaType;