diff --git a/packages/api/src/utils/auth.ts b/packages/api/src/utils/auth.ts index 44eac2f4e..5dfb0e9b1 100644 --- a/packages/api/src/utils/auth.ts +++ b/packages/api/src/utils/auth.ts @@ -68,22 +68,28 @@ export const getClaimsByToken = async ( try { jwt.verify(token, env.server.jwtSecret) && (claims = jwt.decode(token) as Claims) - } catch (e) { - if (e instanceof jwt.JsonWebTokenError) { - console.log(`not a jwt token, checking api key`, { token }) - claims = await claimsFromApiKey(token) - } else { - throw e - } - } - return claims + return claims + } catch (e) { + if ( + e instanceof jwt.JsonWebTokenError && + !(e instanceof jwt.TokenExpiredError) + ) { + console.log(`not a jwt token, checking api key`, { token }) + return claimsFromApiKey(token) + } + + throw e + } } -export const generateVerificationToken = (userId: string): string => { +export const generateVerificationToken = ( + userId: string, + expireInDays = 1 +): string => { const iat = Math.floor(Date.now() / 1000) const exp = Math.floor( - new Date(Date.now() + 1000 * 60 * 60 * 24).getTime() / 1000 + new Date(Date.now() + 1000 * 60 * 60 * 24 * expireInDays).getTime() / 1000 ) return jwt.sign({ uid: userId, iat, exp }, env.server.jwtSecret) diff --git a/packages/api/test/routers/auth.test.ts b/packages/api/test/routers/auth.test.ts index a3ea6fa59..925e9c587 100644 --- a/packages/api/test/routers/auth.test.ts +++ b/packages/api/test/routers/auth.test.ts @@ -1,5 +1,5 @@ import { createTestUser, deleteTestUser } from '../db' -import { request } from '../util' +import { generateFakeUuid, request } from '../util' import { expect } from 'chai' import { StatusType } from '../../src/datalayer/user/model' import { getRepository } from '../../src/entity/utils' @@ -8,7 +8,7 @@ import { MailDataRequired } from '@sendgrid/helpers/classes/mail' import sinon from 'sinon' import * as util from '../../src/utils/sendEmail' import supertest from 'supertest' -import { hashPassword } from '../../src/utils/auth' +import { generateVerificationToken, hashPassword } from '../../src/utils/auth' describe('auth router', () => { const route = '/api/auth' @@ -260,4 +260,78 @@ describe('auth router', () => { }) }) }) + + describe('confirm-email', () => { + const confirmEmailRequest = (token: string): supertest.Test => { + return request.get(`${route}/confirm-email/${token}`).send() + } + + let user: User + let token: string + + before(async () => { + user = await createTestUser('pendingUser', undefined, 'password', true) + }) + + after(async () => { + await deleteTestUser(user.name) + }) + + context('when token is valid', () => { + before(() => { + token = generateVerificationToken(user.id) + }) + + it('redirects to email-login page', async () => { + const res = await confirmEmailRequest(token).expect(302) + expect(res.header.location).to.endWith( + '/email-login?message=EMAIL_VERIFIED' + ) + }) + + it('sets user as active', async () => { + await confirmEmailRequest(token).expect(302) + const updatedUser = await getRepository(User).findOneBy({ + name: user.name, + }) + expect(updatedUser?.status).to.eql(StatusType.Active) + }) + }) + + context('when token is invalid', () => { + it('redirects to confirm-email with error code InvalidToken', async () => { + const res = await confirmEmailRequest('invalid_token').expect(302) + expect(res.header.location).to.endWith( + '/confirm-email?errorCodes=INVALID_TOKEN' + ) + }) + }) + + context('when token is expired', () => { + before(() => { + token = generateVerificationToken(user.id, -1) + }) + + it('redirects to confirm-email page with error code TokenExpired', async () => { + const res = await confirmEmailRequest(token).expect(302) + expect(res.header.location).to.endWith( + '/confirm-email?errorCodes=TOKEN_EXPIRED' + ) + }) + }) + + context('when user is not found', () => { + before(() => { + const nonExistsUserId = generateFakeUuid() + token = generateVerificationToken(nonExistsUserId) + }) + + it('redirects to confirm-email page with error code UserNotFound', async () => { + const res = await confirmEmailRequest(token).expect(302) + expect(res.header.location).to.endWith( + '/confirm-email?errorCodes=USER_NOT_FOUND' + ) + }) + }) + }) })