From 5c5ab5bad53866a650e6d18927a39a7f57acc595 Mon Sep 17 00:00:00 2001 From: Balu Babu Date: Wed, 1 Feb 2023 11:58:15 +0530 Subject: [PATCH] fix: changed all refrences to passwordlessVerification to verificationTokens in auth module --- .../migration.sql | 8 +- .../hoppscotch-backend/prisma/schema.prisma | 28 +++---- .../src/auth/auth.service.spec.ts | 80 ++++++++----------- .../src/auth/auth.service.ts | 26 +++--- packages/hoppscotch-backend/src/errors.ts | 8 +- .../src/user/user.service.ts | 4 +- 6 files changed, 69 insertions(+), 85 deletions(-) rename packages/hoppscotch-backend/prisma/migrations/{20230127072439_sdfdcvsf => 20230201061003_init}/migration.sql (93%) diff --git a/packages/hoppscotch-backend/prisma/migrations/20230127072439_sdfdcvsf/migration.sql b/packages/hoppscotch-backend/prisma/migrations/20230201061003_init/migration.sql similarity index 93% rename from packages/hoppscotch-backend/prisma/migrations/20230127072439_sdfdcvsf/migration.sql rename to packages/hoppscotch-backend/prisma/migrations/20230201061003_init/migration.sql index de69e45e9..1f80820f0 100644 --- a/packages/hoppscotch-backend/prisma/migrations/20230127072439_sdfdcvsf/migration.sql +++ b/packages/hoppscotch-backend/prisma/migrations/20230201061003_init/migration.sql @@ -104,7 +104,7 @@ CREATE TABLE "Account" ( ); -- CreateTable -CREATE TABLE "PasswordlessVerification" ( +CREATE TABLE "VerificationToken" ( "deviceIdentifier" TEXT NOT NULL, "token" TEXT NOT NULL, "userUid" TEXT NOT NULL, @@ -164,10 +164,10 @@ CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId"); -- CreateIndex -CREATE UNIQUE INDEX "PasswordlessVerification_token_key" ON "PasswordlessVerification"("token"); +CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token"); -- CreateIndex -CREATE UNIQUE INDEX "PasswordlessVerification_deviceIdentifier_token_key" ON "PasswordlessVerification"("deviceIdentifier", "token"); +CREATE UNIQUE INDEX "VerificationToken_deviceIdentifier_token_key" ON "VerificationToken"("deviceIdentifier", "token"); -- CreateIndex CREATE UNIQUE INDEX "UserSettings_userUid_key" ON "UserSettings"("userUid"); @@ -197,7 +197,7 @@ ALTER TABLE "TeamEnvironment" ADD CONSTRAINT "TeamEnvironment_teamID_fkey" FOREI ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("uid") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey -ALTER TABLE "PasswordlessVerification" ADD CONSTRAINT "PasswordlessVerification_userUid_fkey" FOREIGN KEY ("userUid") REFERENCES "User"("uid") ON DELETE CASCADE ON UPDATE CASCADE; +ALTER TABLE "VerificationToken" ADD CONSTRAINT "VerificationToken_userUid_fkey" FOREIGN KEY ("userUid") REFERENCES "User"("uid") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "UserSettings" ADD CONSTRAINT "UserSettings_userUid_fkey" FOREIGN KEY ("userUid") REFERENCES "User"("uid") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/packages/hoppscotch-backend/prisma/schema.prisma b/packages/hoppscotch-backend/prisma/schema.prisma index 240cdec63..4ab3a1e28 100644 --- a/packages/hoppscotch-backend/prisma/schema.prisma +++ b/packages/hoppscotch-backend/prisma/schema.prisma @@ -79,20 +79,20 @@ model TeamEnvironment { } model User { - uid String @id @default(cuid()) - displayName String? - email String? @unique - photoURL String? - isAdmin Boolean @default(false) - refreshToken String? - providerAccounts Account[] - PasswordlessVerification PasswordlessVerification[] - settings UserSettings? - UserHistory UserHistory[] - UserEnvironments UserEnvironment[] - currentRESTSession Json? - currentGQLSession Json? - createdOn DateTime @default(now()) @db.Timestamp(3) + uid String @id @default(cuid()) + displayName String? + email String? @unique + photoURL String? + isAdmin Boolean @default(false) + refreshToken String? + providerAccounts Account[] + VerificationToken VerificationToken[] + settings UserSettings? + UserHistory UserHistory[] + UserEnvironments UserEnvironment[] + currentRESTSession Json? + currentGQLSession Json? + createdOn DateTime @default(now()) @db.Timestamp(3) } model Account { diff --git a/packages/hoppscotch-backend/src/auth/auth.service.spec.ts b/packages/hoppscotch-backend/src/auth/auth.service.spec.ts index 2445421fa..aca5f166f 100644 --- a/packages/hoppscotch-backend/src/auth/auth.service.spec.ts +++ b/packages/hoppscotch-backend/src/auth/auth.service.spec.ts @@ -1,13 +1,13 @@ import { HttpStatus } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; -import { Account, PasswordlessVerification } from '@prisma/client'; +import { Account, VerificationToken } from '@prisma/client'; import { mockDeep, mockFn } from 'jest-mock-extended'; import { INVALID_EMAIL, INVALID_MAGIC_LINK_DATA, INVALID_REFRESH_TOKEN, MAGIC_LINK_EXPIRED, - PASSWORDLESS_DATA_NOT_FOUND, + VERIFICATION_TOKEN_DATA_NOT_FOUND, USER_NOT_FOUND, } from 'src/errors'; import { MailerService } from 'src/mailer/mailer.service'; @@ -39,9 +39,11 @@ const user: AuthUser = { isAdmin: false, refreshToken: 'hbfvdkhjbvkdvdfjvbnkhjb', createdOn: currentTime, + currentGQLSession: {}, + currentRESTSession: {}, }; -const passwordlessData: PasswordlessVerification = { +const passwordlessData: VerificationToken = { deviceIdentifier: 'k23hb7u7gdcujhb', token: 'jhhj24sdjvl', userUid: user.uid, @@ -85,10 +87,8 @@ describe('signInMagicLink', () => { mockUser.findUserByEmail.mockResolvedValue(O.none); // create new user mockUser.createUserViaMagicLink.mockResolvedValue(user); - // create new entry in passwordlessVerification table - mockPrisma.passwordlessVerification.create.mockResolvedValueOnce( - passwordlessData, - ); + // create new entry in VerificationToken table + mockPrisma.verificationToken.create.mockResolvedValueOnce(passwordlessData); const result = await authService.signInMagicLink( 'dwight@dundermifflin.com', @@ -101,10 +101,8 @@ describe('signInMagicLink', () => { test('should successfully return the passwordless details for a pre-existing user account', async () => { // check to see if user exists, return error mockUser.findUserByEmail.mockResolvedValueOnce(O.some(user)); - // create new entry in passwordlessVerification table - mockPrisma.passwordlessVerification.create.mockResolvedValueOnce( - passwordlessData, - ); + // create new entry in VerificationToken table + mockPrisma.verificationToken.create.mockResolvedValueOnce(passwordlessData); const result = await authService.signInMagicLink( 'dwight@dundermifflin.com', @@ -117,7 +115,7 @@ describe('signInMagicLink', () => { describe('verifyMagicLinkTokens', () => { test('should throw INVALID_MAGIC_LINK_DATA if data is invalid', async () => { - mockPrisma.passwordlessVerification.findUniqueOrThrow.mockRejectedValueOnce( + mockPrisma.verificationToken.findUniqueOrThrow.mockRejectedValueOnce( 'NotFoundError', ); @@ -130,7 +128,7 @@ describe('verifyMagicLinkTokens', () => { test('should throw USER_NOT_FOUND if user is invalid', async () => { // validatePasswordlessTokens - mockPrisma.passwordlessVerification.findUniqueOrThrow.mockResolvedValueOnce( + mockPrisma.verificationToken.findUniqueOrThrow.mockResolvedValueOnce( passwordlessData, ); // findUserById @@ -145,12 +143,10 @@ describe('verifyMagicLinkTokens', () => { test('should successfully return auth token pair with provider account existing', async () => { // validatePasswordlessTokens - mockPrisma.passwordlessVerification.findUniqueOrThrow.mockResolvedValueOnce( - { - ...passwordlessData, - expiresOn: nowPlus30, - }, - ); + mockPrisma.verificationToken.findUniqueOrThrow.mockResolvedValueOnce({ + ...passwordlessData, + expiresOn: nowPlus30, + }); // findUserById mockUser.findUserById.mockResolvedValue(O.some(user)); // checkIfProviderAccountExists @@ -160,9 +156,7 @@ describe('verifyMagicLinkTokens', () => { mockJWT.sign.mockReturnValue(user.refreshToken); mockPrisma.user.update.mockResolvedValueOnce(user); // deletePasswordlessVerificationToken - mockPrisma.passwordlessVerification.delete.mockResolvedValueOnce( - passwordlessData, - ); + mockPrisma.verificationToken.delete.mockResolvedValueOnce(passwordlessData); const result = await authService.verifyMagicLinkTokens(magicLinkVerify); expect(result).toEqualRight({ @@ -173,12 +167,10 @@ describe('verifyMagicLinkTokens', () => { test('should successfully return auth token pair with provider account not existing', async () => { // validatePasswordlessTokens - mockPrisma.passwordlessVerification.findUniqueOrThrow.mockResolvedValueOnce( - { - ...passwordlessData, - expiresOn: nowPlus30, - }, - ); + mockPrisma.verificationToken.findUniqueOrThrow.mockResolvedValueOnce({ + ...passwordlessData, + expiresOn: nowPlus30, + }); // findUserById mockUser.findUserById.mockResolvedValue(O.some(user)); // checkIfProviderAccountExists @@ -188,9 +180,7 @@ describe('verifyMagicLinkTokens', () => { mockJWT.sign.mockReturnValue(user.refreshToken); mockPrisma.user.update.mockResolvedValueOnce(user); // deletePasswordlessVerificationToken - mockPrisma.passwordlessVerification.delete.mockResolvedValueOnce( - passwordlessData, - ); + mockPrisma.verificationToken.delete.mockResolvedValueOnce(passwordlessData); const result = await authService.verifyMagicLinkTokens(magicLinkVerify); expect(result).toEqualRight({ @@ -201,7 +191,7 @@ describe('verifyMagicLinkTokens', () => { test('should throw MAGIC_LINK_EXPIRED if passwordless token is expired', async () => { // validatePasswordlessTokens - mockPrisma.passwordlessVerification.findUniqueOrThrow.mockResolvedValueOnce( + mockPrisma.verificationToken.findUniqueOrThrow.mockResolvedValueOnce( passwordlessData, ); // findUserById @@ -218,12 +208,10 @@ describe('verifyMagicLinkTokens', () => { test('should throw USER_NOT_FOUND when updating refresh tokens fails', async () => { // validatePasswordlessTokens - mockPrisma.passwordlessVerification.findUniqueOrThrow.mockResolvedValueOnce( - { - ...passwordlessData, - expiresOn: nowPlus30, - }, - ); + mockPrisma.verificationToken.findUniqueOrThrow.mockResolvedValueOnce({ + ...passwordlessData, + expiresOn: nowPlus30, + }); // findUserById mockUser.findUserById.mockResolvedValue(O.some(user)); // checkIfProviderAccountExists @@ -242,12 +230,10 @@ describe('verifyMagicLinkTokens', () => { test('should throw PASSWORDLESS_DATA_NOT_FOUND when deleting passwordlessVerification entry from DB', async () => { // validatePasswordlessTokens - mockPrisma.passwordlessVerification.findUniqueOrThrow.mockResolvedValueOnce( - { - ...passwordlessData, - expiresOn: nowPlus30, - }, - ); + mockPrisma.verificationToken.findUniqueOrThrow.mockResolvedValueOnce({ + ...passwordlessData, + expiresOn: nowPlus30, + }); // findUserById mockUser.findUserById.mockResolvedValue(O.some(user)); // checkIfProviderAccountExists @@ -257,13 +243,11 @@ describe('verifyMagicLinkTokens', () => { mockJWT.sign.mockReturnValue(user.refreshToken); mockPrisma.user.update.mockResolvedValueOnce(user); // deletePasswordlessVerificationToken - mockPrisma.passwordlessVerification.delete.mockRejectedValueOnce( - 'RecordNotFound', - ); + mockPrisma.verificationToken.delete.mockRejectedValueOnce('RecordNotFound'); const result = await authService.verifyMagicLinkTokens(magicLinkVerify); expect(result).toEqualLeft({ - message: PASSWORDLESS_DATA_NOT_FOUND, + message: VERIFICATION_TOKEN_DATA_NOT_FOUND, statusCode: HttpStatus.NOT_FOUND, }); }); diff --git a/packages/hoppscotch-backend/src/auth/auth.service.ts b/packages/hoppscotch-backend/src/auth/auth.service.ts index 4d4810514..61e448eb9 100644 --- a/packages/hoppscotch-backend/src/auth/auth.service.ts +++ b/packages/hoppscotch-backend/src/auth/auth.service.ts @@ -13,7 +13,7 @@ import { DeviceIdentifierToken } from 'src/types/Passwordless'; import { INVALID_EMAIL, INVALID_MAGIC_LINK_DATA, - PASSWORDLESS_DATA_NOT_FOUND, + VERIFICATION_TOKEN_DATA_NOT_FOUND, MAGIC_LINK_EXPIRED, USER_NOT_FOUND, INVALID_REFRESH_TOKEN, @@ -27,7 +27,7 @@ import { import { JwtService } from '@nestjs/jwt'; import { AuthError } from 'src/types/AuthError'; import { AuthUser } from 'src/types/AuthUser'; -import { PasswordlessVerification } from '@prisma/client'; +import { VerificationToken } from '@prisma/client'; @Injectable() export class AuthService { @@ -42,7 +42,7 @@ export class AuthService { * Generate Id and token for email Magic-Link auth * * @param user User Object - * @returns Created PasswordlessVerification token + * @returns Created VerificationToken token */ private async generateMagicLinkTokens(user: AuthUser) { const salt = await bcrypt.genSalt( @@ -53,7 +53,7 @@ export class AuthService { .toISO() .toString(); - const idToken = await this.prismaService.passwordlessVerification.create({ + const idToken = await this.prismaService.verificationToken.create({ data: { deviceIdentifier: salt, userUid: user.uid, @@ -65,15 +65,15 @@ export class AuthService { } /** - * Check if passwordlessVerification exist or not + * Check if VerificationToken exist or not * * @param magicLinkTokens Object containing deviceIdentifier and token - * @returns Option of PasswordlessVerification token + * @returns Option of VerificationToken token */ private async validatePasswordlessTokens(magicLinkTokens: verifyMagicDto) { try { const tokens = - await this.prismaService.passwordlessVerification.findUniqueOrThrow({ + await this.prismaService.verificationToken.findUniqueOrThrow({ where: { passwordless_deviceIdentifier_tokens: { deviceIdentifier: magicLinkTokens.deviceIdentifier, @@ -144,17 +144,17 @@ export class AuthService { } /** - * Deleted used PasswordlessVerification tokens + * Deleted used VerificationToken tokens * - * @param passwordlessTokens PasswordlessVerification entry to delete from DB - * @returns Either of deleted PasswordlessVerification token + * @param passwordlessTokens VerificationToken entry to delete from DB + * @returns Either of deleted VerificationToken token */ private async deleteMagicLinkVerificationTokens( - passwordlessTokens: PasswordlessVerification, + passwordlessTokens: VerificationToken, ) { try { const deletedPasswordlessToken = - await this.prismaService.passwordlessVerification.delete({ + await this.prismaService.verificationToken.delete({ where: { passwordless_deviceIdentifier_tokens: { deviceIdentifier: passwordlessTokens.deviceIdentifier, @@ -164,7 +164,7 @@ export class AuthService { }); return E.right(deletedPasswordlessToken); } catch (error) { - return E.left(PASSWORDLESS_DATA_NOT_FOUND); + return E.left(VERIFICATION_TOKEN_DATA_NOT_FOUND); } } diff --git a/packages/hoppscotch-backend/src/errors.ts b/packages/hoppscotch-backend/src/errors.ts index 589297fbd..f53711e84 100644 --- a/packages/hoppscotch-backend/src/errors.ts +++ b/packages/hoppscotch-backend/src/errors.ts @@ -325,11 +325,11 @@ export const BUG_TEAM_ENV_GUARD_NO_ENV_ID = export const INVALID_MAGIC_LINK_DATA = 'auth/magic_link_invalid_data' as const; /** - * Could not find PasswordlessVerification entry in the db + * Could not find VerificationToken entry in the db * (AuthService) */ -export const PASSWORDLESS_DATA_NOT_FOUND = - 'auth/passwordless_token_data_not_found' as const; +export const VERIFICATION_TOKEN_DATA_NOT_FOUND = + 'auth/verification_token_data_not_found' as const; /** * Auth Tokens expired @@ -338,7 +338,7 @@ export const PASSWORDLESS_DATA_NOT_FOUND = export const TOKEN_EXPIRED = 'auth/token_expired' as const; /** - * PasswordlessVerification Tokens expired i.e. magic-link expired + * VerificationToken Tokens expired i.e. magic-link expired * (AuthService) */ export const MAGIC_LINK_EXPIRED = 'auth/magic_link_expired' as const; diff --git a/packages/hoppscotch-backend/src/user/user.service.ts b/packages/hoppscotch-backend/src/user/user.service.ts index 121747bf2..a88f88c0d 100644 --- a/packages/hoppscotch-backend/src/user/user.service.ts +++ b/packages/hoppscotch-backend/src/user/user.service.ts @@ -88,7 +88,7 @@ export class UserService { const createdUser = await this.prisma.user.create({ data: { email: email, - accounts: { + providerAccounts: { create: { provider: 'magic', providerAccountId: email, @@ -121,7 +121,7 @@ export class UserService { displayName: userDisplayName, email: profile.emails[0].value, photoURL: userPhotoURL, - accounts: { + providerAccounts: { create: { provider: profile.provider, providerAccountId: profile.id,