password-reset-order.ts 2.2 KB

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