Turn off auto delete and manual check ttl for token

This commit is contained in:
Maidul Islam
2023-02-11 11:08:46 -08:00
parent 8fd2578a6d
commit 2fb4b261a8
5 changed files with 29 additions and 16 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
const PORT = process.env.PORT || 4000; const PORT = process.env.PORT || 4000;
const EMAIL_TOKEN_LIFETIME = process.env.EMAIL_TOKEN_LIFETIME! || '86400'; const EMAIL_TOKEN_LIFETIME = parseInt(process.env.EMAIL_TOKEN_LIFETIME! || '86400');
const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY!; const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY!;
const SALT_ROUNDS = parseInt(process.env.SALT_ROUNDS!) || 10; const SALT_ROUNDS = parseInt(process.env.SALT_ROUNDS!) || 10;
const JWT_AUTH_LIFETIME = process.env.JWT_AUTH_LIFETIME! || '10d'; const JWT_AUTH_LIFETIME = process.env.JWT_AUTH_LIFETIME! || '10d';
@@ -24,7 +24,7 @@ const CLIENT_SECRET_HEROKU = process.env.CLIENT_SECRET_HEROKU!;
const CLIENT_SECRET_VERCEL = process.env.CLIENT_SECRET_VERCEL!; const CLIENT_SECRET_VERCEL = process.env.CLIENT_SECRET_VERCEL!;
const CLIENT_SECRET_NETLIFY = process.env.CLIENT_SECRET_NETLIFY!; const CLIENT_SECRET_NETLIFY = process.env.CLIENT_SECRET_NETLIFY!;
const CLIENT_SECRET_GITHUB = process.env.CLIENT_SECRET_GITHUB!; const CLIENT_SECRET_GITHUB = process.env.CLIENT_SECRET_GITHUB!;
const CLIENT_SLUG_VERCEL= process.env.CLIENT_SLUG_VERCEL!; const CLIENT_SLUG_VERCEL = process.env.CLIENT_SLUG_VERCEL!;
const POSTHOG_HOST = process.env.POSTHOG_HOST! || 'https://app.posthog.com'; const POSTHOG_HOST = process.env.POSTHOG_HOST! || 'https://app.posthog.com';
const POSTHOG_PROJECT_API_KEY = const POSTHOG_PROJECT_API_KEY =
process.env.POSTHOG_PROJECT_API_KEY! || process.env.POSTHOG_PROJECT_API_KEY! ||
@@ -1,7 +1,7 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import crypto from 'crypto'; import crypto from 'crypto';
import { SITE_URL, JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET } from '../../config'; import { SITE_URL, JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET, EMAIL_TOKEN_LIFETIME } from '../../config';
import { MembershipOrg, Organization, User, Token } from '../../models'; import { MembershipOrg, Organization, User, Token } from '../../models';
import { deleteMembershipOrg as deleteMemberFromOrg } from '../../helpers/membershipOrg'; import { deleteMembershipOrg as deleteMemberFromOrg } from '../../helpers/membershipOrg';
import { checkEmailVerification } from '../../helpers/signup'; import { checkEmailVerification } from '../../helpers/signup';
@@ -170,7 +170,8 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
{ {
email: inviteeEmail, email: inviteeEmail,
token, token,
createdAt: new Date() createdAt: new Date(),
ttl: Math.floor(+new Date() / 1000) + EMAIL_TOKEN_LIFETIME // time in seconds, i.e unix
}, },
{ upsert: true, new: true } { upsert: true, new: true }
); );
@@ -241,7 +242,7 @@ export const verifyUserToOrganization = async (req: Request, res: Response) => {
message: 'Successfully verified email', message: 'Successfully verified email',
user, user,
}); });
} }
if (!user) { if (!user) {
// initialize user account // initialize user account
@@ -8,7 +8,7 @@ import { User, Token, BackupPrivateKey, LoginSRPDetail } from '../../models';
import { checkEmailVerification } from '../../helpers/signup'; import { checkEmailVerification } from '../../helpers/signup';
import { createToken } from '../../helpers/auth'; import { createToken } from '../../helpers/auth';
import { sendMail } from '../../helpers/nodemailer'; import { sendMail } from '../../helpers/nodemailer';
import { JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET, SITE_URL } from '../../config'; import { EMAIL_TOKEN_LIFETIME, JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET, SITE_URL } from '../../config';
import { BadRequestError } from '../../utils/errors'; import { BadRequestError } from '../../utils/errors';
/** /**
@@ -39,7 +39,8 @@ export const emailPasswordReset = async (req: Request, res: Response) => {
{ {
email, email,
token, token,
createdAt: new Date() createdAt: new Date(),
ttl: Math.floor(+new Date() / 1000) + EMAIL_TOKEN_LIFETIME // time in seconds, i.e unix
}, },
{ upsert: true, new: true } { upsert: true, new: true }
); );
+13 -2
View File
@@ -7,6 +7,7 @@ import { createWorkspace } from './workspace';
import { addMemberships } from './membership'; import { addMemberships } from './membership';
import { OWNER, ADMIN, ACCEPTED } from '../variables'; import { OWNER, ADMIN, ACCEPTED } from '../variables';
import { sendMail } from '../helpers/nodemailer'; import { sendMail } from '../helpers/nodemailer';
import { EMAIL_TOKEN_LIFETIME } from '../config';
/** /**
* Send magic link to verify email to [email] * Send magic link to verify email to [email]
@@ -25,7 +26,8 @@ const sendEmailVerification = async ({ email }: { email: string }) => {
{ {
email, email,
token, token,
createdAt: new Date() createdAt: new Date(),
ttl: Math.floor(+new Date() / 1000) + EMAIL_TOKEN_LIFETIME // time in seconds, i.e unix
}, },
{ upsert: true, new: true } { upsert: true, new: true }
); );
@@ -62,11 +64,20 @@ const checkEmailVerification = async ({
code: string; code: string;
}) => { }) => {
try { try {
const token = await Token.findOneAndDelete({ const token = await Token.findOne({
email, email,
token: code token: code
}); });
if (token && Math.floor(Date.now() / 1000) > token.ttl) {
await Token.deleteOne({
email,
token: code
});
throw new Error('Verification token has expired')
}
if (!token) throw new Error('Failed to find email verification token'); if (!token) throw new Error('Failed to find email verification token');
} catch (err) { } catch (err) {
Sentry.setUser(null); Sentry.setUser(null);
+5 -5
View File
@@ -5,6 +5,7 @@ export interface IToken {
email: string; email: string;
token: string; token: string;
createdAt: Date; createdAt: Date;
ttl: Number;
} }
const tokenSchema = new Schema<IToken>({ const tokenSchema = new Schema<IToken>({
@@ -19,14 +20,13 @@ const tokenSchema = new Schema<IToken>({
createdAt: { createdAt: {
type: Date, type: Date,
default: Date.now default: Date.now
},
ttl: {
type: Number,
} }
}); });
tokenSchema.index({ tokenSchema.index({ email: 1 });
createdAt: 1
}, {
expireAfterSeconds: parseInt(EMAIL_TOKEN_LIFETIME)
});
const Token = model<IToken>('Token', tokenSchema); const Token = model<IToken>('Token', tokenSchema);