password-reset-order.ts 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import mongoose, {
  2. Schema, Model, Document,
  3. } from 'mongoose';
  4. import { addMinutes } from 'date-fns';
  5. import uniqueValidator from 'mongoose-unique-validator';
  6. import crypto from 'crypto';
  7. import { getOrCreateModel } from '@growi/core';
  8. const ObjectId = mongoose.Schema.Types.ObjectId;
  9. export interface IPasswordResetOrder {
  10. token: string,
  11. email: string,
  12. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  13. relatedUser: any,
  14. isRevoked: boolean,
  15. createdAt: Date,
  16. expiredAt: Date,
  17. }
  18. export interface PasswordResetOrderDocument extends IPasswordResetOrder, Document {
  19. isExpired(): Promise<boolean>
  20. revokeOneTimeToken(): Promise<void>
  21. }
  22. export interface PasswordResetOrderModel extends Model<PasswordResetOrderDocument> {
  23. generateOneTimeToken(): string
  24. createPasswordResetOrder(email: string): PasswordResetOrderDocument
  25. }
  26. const expiredAt = (): Date => {
  27. return addMinutes(new Date(), 10);
  28. };
  29. const schema = new Schema<PasswordResetOrderDocument, PasswordResetOrderModel>({
  30. token: { type: String, required: true, unique: true },
  31. email: { type: String, required: true },
  32. relatedUser: { type: ObjectId, ref: 'User' },
  33. isRevoked: { type: Boolean, default: false, required: true },
  34. expiredAt: { type: Date, default: expiredAt, required: true },
  35. }, {
  36. timestamps: {
  37. createdAt: true,
  38. updatedAt: false,
  39. },
  40. });
  41. schema.plugin(uniqueValidator);
  42. schema.statics.generateOneTimeToken = function() {
  43. const buf = crypto.randomBytes(256);
  44. const token = buf.toString('hex');
  45. return token;
  46. };
  47. schema.statics.createPasswordResetOrder = async function(email) {
  48. let token;
  49. let duplicateToken;
  50. do {
  51. token = this.generateOneTimeToken();
  52. // eslint-disable-next-line no-await-in-loop
  53. duplicateToken = await this.findOne({ token });
  54. } while (duplicateToken != null);
  55. const passwordResetOrderData = await this.create({ token, email });
  56. return passwordResetOrderData;
  57. };
  58. schema.methods.isExpired = function() {
  59. return this.expiredAt.getTime() < Date.now();
  60. };
  61. schema.methods.revokeOneTimeToken = async function() {
  62. this.isRevoked = true;
  63. return this.save();
  64. };
  65. export default getOrCreateModel<PasswordResetOrderDocument, PasswordResetOrderModel>('PasswordResetOrder', schema);