fix: changed all refrences to passwordlessVerification to verificationTokens in auth module

This commit is contained in:
Balu Babu
2023-02-01 11:58:15 +05:30
parent 3afc89db6b
commit 5c5ab5bad5
6 changed files with 69 additions and 85 deletions

View File

@@ -104,7 +104,7 @@ CREATE TABLE "Account" (
); );
-- CreateTable -- CreateTable
CREATE TABLE "PasswordlessVerification" ( CREATE TABLE "VerificationToken" (
"deviceIdentifier" TEXT NOT NULL, "deviceIdentifier" TEXT NOT NULL,
"token" TEXT NOT NULL, "token" TEXT NOT NULL,
"userUid" 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"); CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");
-- CreateIndex -- CreateIndex
CREATE UNIQUE INDEX "PasswordlessVerification_token_key" ON "PasswordlessVerification"("token"); CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token");
-- CreateIndex -- CreateIndex
CREATE UNIQUE INDEX "PasswordlessVerification_deviceIdentifier_token_key" ON "PasswordlessVerification"("deviceIdentifier", "token"); CREATE UNIQUE INDEX "VerificationToken_deviceIdentifier_token_key" ON "VerificationToken"("deviceIdentifier", "token");
-- CreateIndex -- CreateIndex
CREATE UNIQUE INDEX "UserSettings_userUid_key" ON "UserSettings"("userUid"); 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; ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey -- 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 -- AddForeignKey
ALTER TABLE "UserSettings" ADD CONSTRAINT "UserSettings_userUid_fkey" FOREIGN KEY ("userUid") REFERENCES "User"("uid") ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE "UserSettings" ADD CONSTRAINT "UserSettings_userUid_fkey" FOREIGN KEY ("userUid") REFERENCES "User"("uid") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -79,20 +79,20 @@ model TeamEnvironment {
} }
model User { model User {
uid String @id @default(cuid()) uid String @id @default(cuid())
displayName String? displayName String?
email String? @unique email String? @unique
photoURL String? photoURL String?
isAdmin Boolean @default(false) isAdmin Boolean @default(false)
refreshToken String? refreshToken String?
providerAccounts Account[] providerAccounts Account[]
PasswordlessVerification PasswordlessVerification[] VerificationToken VerificationToken[]
settings UserSettings? settings UserSettings?
UserHistory UserHistory[] UserHistory UserHistory[]
UserEnvironments UserEnvironment[] UserEnvironments UserEnvironment[]
currentRESTSession Json? currentRESTSession Json?
currentGQLSession Json? currentGQLSession Json?
createdOn DateTime @default(now()) @db.Timestamp(3) createdOn DateTime @default(now()) @db.Timestamp(3)
} }
model Account { model Account {

View File

@@ -1,13 +1,13 @@
import { HttpStatus } from '@nestjs/common'; import { HttpStatus } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt'; 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 { mockDeep, mockFn } from 'jest-mock-extended';
import { import {
INVALID_EMAIL, INVALID_EMAIL,
INVALID_MAGIC_LINK_DATA, INVALID_MAGIC_LINK_DATA,
INVALID_REFRESH_TOKEN, INVALID_REFRESH_TOKEN,
MAGIC_LINK_EXPIRED, MAGIC_LINK_EXPIRED,
PASSWORDLESS_DATA_NOT_FOUND, VERIFICATION_TOKEN_DATA_NOT_FOUND,
USER_NOT_FOUND, USER_NOT_FOUND,
} from 'src/errors'; } from 'src/errors';
import { MailerService } from 'src/mailer/mailer.service'; import { MailerService } from 'src/mailer/mailer.service';
@@ -39,9 +39,11 @@ const user: AuthUser = {
isAdmin: false, isAdmin: false,
refreshToken: 'hbfvdkhjbvkdvdfjvbnkhjb', refreshToken: 'hbfvdkhjbvkdvdfjvbnkhjb',
createdOn: currentTime, createdOn: currentTime,
currentGQLSession: {},
currentRESTSession: {},
}; };
const passwordlessData: PasswordlessVerification = { const passwordlessData: VerificationToken = {
deviceIdentifier: 'k23hb7u7gdcujhb', deviceIdentifier: 'k23hb7u7gdcujhb',
token: 'jhhj24sdjvl', token: 'jhhj24sdjvl',
userUid: user.uid, userUid: user.uid,
@@ -85,10 +87,8 @@ describe('signInMagicLink', () => {
mockUser.findUserByEmail.mockResolvedValue(O.none); mockUser.findUserByEmail.mockResolvedValue(O.none);
// create new user // create new user
mockUser.createUserViaMagicLink.mockResolvedValue(user); mockUser.createUserViaMagicLink.mockResolvedValue(user);
// create new entry in passwordlessVerification table // create new entry in VerificationToken table
mockPrisma.passwordlessVerification.create.mockResolvedValueOnce( mockPrisma.verificationToken.create.mockResolvedValueOnce(passwordlessData);
passwordlessData,
);
const result = await authService.signInMagicLink( const result = await authService.signInMagicLink(
'dwight@dundermifflin.com', 'dwight@dundermifflin.com',
@@ -101,10 +101,8 @@ describe('signInMagicLink', () => {
test('should successfully return the passwordless details for a pre-existing user account', async () => { test('should successfully return the passwordless details for a pre-existing user account', async () => {
// check to see if user exists, return error // check to see if user exists, return error
mockUser.findUserByEmail.mockResolvedValueOnce(O.some(user)); mockUser.findUserByEmail.mockResolvedValueOnce(O.some(user));
// create new entry in passwordlessVerification table // create new entry in VerificationToken table
mockPrisma.passwordlessVerification.create.mockResolvedValueOnce( mockPrisma.verificationToken.create.mockResolvedValueOnce(passwordlessData);
passwordlessData,
);
const result = await authService.signInMagicLink( const result = await authService.signInMagicLink(
'dwight@dundermifflin.com', 'dwight@dundermifflin.com',
@@ -117,7 +115,7 @@ describe('signInMagicLink', () => {
describe('verifyMagicLinkTokens', () => { describe('verifyMagicLinkTokens', () => {
test('should throw INVALID_MAGIC_LINK_DATA if data is invalid', async () => { test('should throw INVALID_MAGIC_LINK_DATA if data is invalid', async () => {
mockPrisma.passwordlessVerification.findUniqueOrThrow.mockRejectedValueOnce( mockPrisma.verificationToken.findUniqueOrThrow.mockRejectedValueOnce(
'NotFoundError', 'NotFoundError',
); );
@@ -130,7 +128,7 @@ describe('verifyMagicLinkTokens', () => {
test('should throw USER_NOT_FOUND if user is invalid', async () => { test('should throw USER_NOT_FOUND if user is invalid', async () => {
// validatePasswordlessTokens // validatePasswordlessTokens
mockPrisma.passwordlessVerification.findUniqueOrThrow.mockResolvedValueOnce( mockPrisma.verificationToken.findUniqueOrThrow.mockResolvedValueOnce(
passwordlessData, passwordlessData,
); );
// findUserById // findUserById
@@ -145,12 +143,10 @@ describe('verifyMagicLinkTokens', () => {
test('should successfully return auth token pair with provider account existing', async () => { test('should successfully return auth token pair with provider account existing', async () => {
// validatePasswordlessTokens // validatePasswordlessTokens
mockPrisma.passwordlessVerification.findUniqueOrThrow.mockResolvedValueOnce( mockPrisma.verificationToken.findUniqueOrThrow.mockResolvedValueOnce({
{ ...passwordlessData,
...passwordlessData, expiresOn: nowPlus30,
expiresOn: nowPlus30, });
},
);
// findUserById // findUserById
mockUser.findUserById.mockResolvedValue(O.some(user)); mockUser.findUserById.mockResolvedValue(O.some(user));
// checkIfProviderAccountExists // checkIfProviderAccountExists
@@ -160,9 +156,7 @@ describe('verifyMagicLinkTokens', () => {
mockJWT.sign.mockReturnValue(user.refreshToken); mockJWT.sign.mockReturnValue(user.refreshToken);
mockPrisma.user.update.mockResolvedValueOnce(user); mockPrisma.user.update.mockResolvedValueOnce(user);
// deletePasswordlessVerificationToken // deletePasswordlessVerificationToken
mockPrisma.passwordlessVerification.delete.mockResolvedValueOnce( mockPrisma.verificationToken.delete.mockResolvedValueOnce(passwordlessData);
passwordlessData,
);
const result = await authService.verifyMagicLinkTokens(magicLinkVerify); const result = await authService.verifyMagicLinkTokens(magicLinkVerify);
expect(result).toEqualRight({ expect(result).toEqualRight({
@@ -173,12 +167,10 @@ describe('verifyMagicLinkTokens', () => {
test('should successfully return auth token pair with provider account not existing', async () => { test('should successfully return auth token pair with provider account not existing', async () => {
// validatePasswordlessTokens // validatePasswordlessTokens
mockPrisma.passwordlessVerification.findUniqueOrThrow.mockResolvedValueOnce( mockPrisma.verificationToken.findUniqueOrThrow.mockResolvedValueOnce({
{ ...passwordlessData,
...passwordlessData, expiresOn: nowPlus30,
expiresOn: nowPlus30, });
},
);
// findUserById // findUserById
mockUser.findUserById.mockResolvedValue(O.some(user)); mockUser.findUserById.mockResolvedValue(O.some(user));
// checkIfProviderAccountExists // checkIfProviderAccountExists
@@ -188,9 +180,7 @@ describe('verifyMagicLinkTokens', () => {
mockJWT.sign.mockReturnValue(user.refreshToken); mockJWT.sign.mockReturnValue(user.refreshToken);
mockPrisma.user.update.mockResolvedValueOnce(user); mockPrisma.user.update.mockResolvedValueOnce(user);
// deletePasswordlessVerificationToken // deletePasswordlessVerificationToken
mockPrisma.passwordlessVerification.delete.mockResolvedValueOnce( mockPrisma.verificationToken.delete.mockResolvedValueOnce(passwordlessData);
passwordlessData,
);
const result = await authService.verifyMagicLinkTokens(magicLinkVerify); const result = await authService.verifyMagicLinkTokens(magicLinkVerify);
expect(result).toEqualRight({ expect(result).toEqualRight({
@@ -201,7 +191,7 @@ describe('verifyMagicLinkTokens', () => {
test('should throw MAGIC_LINK_EXPIRED if passwordless token is expired', async () => { test('should throw MAGIC_LINK_EXPIRED if passwordless token is expired', async () => {
// validatePasswordlessTokens // validatePasswordlessTokens
mockPrisma.passwordlessVerification.findUniqueOrThrow.mockResolvedValueOnce( mockPrisma.verificationToken.findUniqueOrThrow.mockResolvedValueOnce(
passwordlessData, passwordlessData,
); );
// findUserById // findUserById
@@ -218,12 +208,10 @@ describe('verifyMagicLinkTokens', () => {
test('should throw USER_NOT_FOUND when updating refresh tokens fails', async () => { test('should throw USER_NOT_FOUND when updating refresh tokens fails', async () => {
// validatePasswordlessTokens // validatePasswordlessTokens
mockPrisma.passwordlessVerification.findUniqueOrThrow.mockResolvedValueOnce( mockPrisma.verificationToken.findUniqueOrThrow.mockResolvedValueOnce({
{ ...passwordlessData,
...passwordlessData, expiresOn: nowPlus30,
expiresOn: nowPlus30, });
},
);
// findUserById // findUserById
mockUser.findUserById.mockResolvedValue(O.some(user)); mockUser.findUserById.mockResolvedValue(O.some(user));
// checkIfProviderAccountExists // checkIfProviderAccountExists
@@ -242,12 +230,10 @@ describe('verifyMagicLinkTokens', () => {
test('should throw PASSWORDLESS_DATA_NOT_FOUND when deleting passwordlessVerification entry from DB', async () => { test('should throw PASSWORDLESS_DATA_NOT_FOUND when deleting passwordlessVerification entry from DB', async () => {
// validatePasswordlessTokens // validatePasswordlessTokens
mockPrisma.passwordlessVerification.findUniqueOrThrow.mockResolvedValueOnce( mockPrisma.verificationToken.findUniqueOrThrow.mockResolvedValueOnce({
{ ...passwordlessData,
...passwordlessData, expiresOn: nowPlus30,
expiresOn: nowPlus30, });
},
);
// findUserById // findUserById
mockUser.findUserById.mockResolvedValue(O.some(user)); mockUser.findUserById.mockResolvedValue(O.some(user));
// checkIfProviderAccountExists // checkIfProviderAccountExists
@@ -257,13 +243,11 @@ describe('verifyMagicLinkTokens', () => {
mockJWT.sign.mockReturnValue(user.refreshToken); mockJWT.sign.mockReturnValue(user.refreshToken);
mockPrisma.user.update.mockResolvedValueOnce(user); mockPrisma.user.update.mockResolvedValueOnce(user);
// deletePasswordlessVerificationToken // deletePasswordlessVerificationToken
mockPrisma.passwordlessVerification.delete.mockRejectedValueOnce( mockPrisma.verificationToken.delete.mockRejectedValueOnce('RecordNotFound');
'RecordNotFound',
);
const result = await authService.verifyMagicLinkTokens(magicLinkVerify); const result = await authService.verifyMagicLinkTokens(magicLinkVerify);
expect(result).toEqualLeft({ expect(result).toEqualLeft({
message: PASSWORDLESS_DATA_NOT_FOUND, message: VERIFICATION_TOKEN_DATA_NOT_FOUND,
statusCode: HttpStatus.NOT_FOUND, statusCode: HttpStatus.NOT_FOUND,
}); });
}); });

View File

@@ -13,7 +13,7 @@ import { DeviceIdentifierToken } from 'src/types/Passwordless';
import { import {
INVALID_EMAIL, INVALID_EMAIL,
INVALID_MAGIC_LINK_DATA, INVALID_MAGIC_LINK_DATA,
PASSWORDLESS_DATA_NOT_FOUND, VERIFICATION_TOKEN_DATA_NOT_FOUND,
MAGIC_LINK_EXPIRED, MAGIC_LINK_EXPIRED,
USER_NOT_FOUND, USER_NOT_FOUND,
INVALID_REFRESH_TOKEN, INVALID_REFRESH_TOKEN,
@@ -27,7 +27,7 @@ import {
import { JwtService } from '@nestjs/jwt'; import { JwtService } from '@nestjs/jwt';
import { AuthError } from 'src/types/AuthError'; import { AuthError } from 'src/types/AuthError';
import { AuthUser } from 'src/types/AuthUser'; import { AuthUser } from 'src/types/AuthUser';
import { PasswordlessVerification } from '@prisma/client'; import { VerificationToken } from '@prisma/client';
@Injectable() @Injectable()
export class AuthService { export class AuthService {
@@ -42,7 +42,7 @@ export class AuthService {
* Generate Id and token for email Magic-Link auth * Generate Id and token for email Magic-Link auth
* *
* @param user User Object * @param user User Object
* @returns Created PasswordlessVerification token * @returns Created VerificationToken token
*/ */
private async generateMagicLinkTokens(user: AuthUser) { private async generateMagicLinkTokens(user: AuthUser) {
const salt = await bcrypt.genSalt( const salt = await bcrypt.genSalt(
@@ -53,7 +53,7 @@ export class AuthService {
.toISO() .toISO()
.toString(); .toString();
const idToken = await this.prismaService.passwordlessVerification.create({ const idToken = await this.prismaService.verificationToken.create({
data: { data: {
deviceIdentifier: salt, deviceIdentifier: salt,
userUid: user.uid, 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 * @param magicLinkTokens Object containing deviceIdentifier and token
* @returns Option of PasswordlessVerification token * @returns Option of VerificationToken token
*/ */
private async validatePasswordlessTokens(magicLinkTokens: verifyMagicDto) { private async validatePasswordlessTokens(magicLinkTokens: verifyMagicDto) {
try { try {
const tokens = const tokens =
await this.prismaService.passwordlessVerification.findUniqueOrThrow({ await this.prismaService.verificationToken.findUniqueOrThrow({
where: { where: {
passwordless_deviceIdentifier_tokens: { passwordless_deviceIdentifier_tokens: {
deviceIdentifier: magicLinkTokens.deviceIdentifier, 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 * @param passwordlessTokens VerificationToken entry to delete from DB
* @returns Either of deleted PasswordlessVerification token * @returns Either of deleted VerificationToken token
*/ */
private async deleteMagicLinkVerificationTokens( private async deleteMagicLinkVerificationTokens(
passwordlessTokens: PasswordlessVerification, passwordlessTokens: VerificationToken,
) { ) {
try { try {
const deletedPasswordlessToken = const deletedPasswordlessToken =
await this.prismaService.passwordlessVerification.delete({ await this.prismaService.verificationToken.delete({
where: { where: {
passwordless_deviceIdentifier_tokens: { passwordless_deviceIdentifier_tokens: {
deviceIdentifier: passwordlessTokens.deviceIdentifier, deviceIdentifier: passwordlessTokens.deviceIdentifier,
@@ -164,7 +164,7 @@ export class AuthService {
}); });
return E.right(deletedPasswordlessToken); return E.right(deletedPasswordlessToken);
} catch (error) { } catch (error) {
return E.left(PASSWORDLESS_DATA_NOT_FOUND); return E.left(VERIFICATION_TOKEN_DATA_NOT_FOUND);
} }
} }

View File

@@ -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; 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) * (AuthService)
*/ */
export const PASSWORDLESS_DATA_NOT_FOUND = export const VERIFICATION_TOKEN_DATA_NOT_FOUND =
'auth/passwordless_token_data_not_found' as const; 'auth/verification_token_data_not_found' as const;
/** /**
* Auth Tokens expired * Auth Tokens expired
@@ -338,7 +338,7 @@ export const PASSWORDLESS_DATA_NOT_FOUND =
export const TOKEN_EXPIRED = 'auth/token_expired' as const; 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) * (AuthService)
*/ */
export const MAGIC_LINK_EXPIRED = 'auth/magic_link_expired' as const; export const MAGIC_LINK_EXPIRED = 'auth/magic_link_expired' as const;

View File

@@ -88,7 +88,7 @@ export class UserService {
const createdUser = await this.prisma.user.create({ const createdUser = await this.prisma.user.create({
data: { data: {
email: email, email: email,
accounts: { providerAccounts: {
create: { create: {
provider: 'magic', provider: 'magic',
providerAccountId: email, providerAccountId: email,
@@ -121,7 +121,7 @@ export class UserService {
displayName: userDisplayName, displayName: userDisplayName,
email: profile.emails[0].value, email: profile.emails[0].value,
photoURL: userPhotoURL, photoURL: userPhotoURL,
accounts: { providerAccounts: {
create: { create: {
provider: profile.provider, provider: profile.provider,
providerAccountId: profile.id, providerAccountId: profile.id,