hotfix: magiclink dynamic email redirection url (#67)

* chore: modified magiclink /signin function to work with origin

* chore: modified testcases for signInMagicLink to reflect new changes

* chore: removed prisma migration file

* chore: removed admin module dulicate from guards folder

* chore: implemented ENUMs for origins in signin method

* chore: added VITE_ADMIN_URL to .env.example file
This commit is contained in:
Balu Babu
2023-04-06 11:41:01 +05:30
committed by GitHub
parent 6d688ed2bc
commit 22aa8ee334
5 changed files with 32 additions and 4 deletions

View File

@@ -47,6 +47,7 @@ RATE_LIMIT_MAX=100 # Max requests per IP
# Base URLs # Base URLs
VITE_BASE_URL=http://localhost:3000 VITE_BASE_URL=http://localhost:3000
VITE_SHORTCODE_BASE_URL=http://localhost:3000 VITE_SHORTCODE_BASE_URL=http://localhost:3000
VITE_ADMIN_URL=http://localhost:3100
# Backend URLs # Backend URLs
VITE_BACKEND_GQL_URL=http://localhost:3170/graphql VITE_BACKEND_GQL_URL=http://localhost:3170/graphql

View File

@@ -3,6 +3,7 @@ import {
Controller, Controller,
Get, Get,
Post, Post,
Query,
Req, Req,
Request, Request,
Res, Res,
@@ -34,9 +35,13 @@ export class AuthController {
** Route to initiate magic-link auth for a users email ** Route to initiate magic-link auth for a users email
*/ */
@Post('signin') @Post('signin')
async signInMagicLink(@Body() authData: SignInMagicDto) { async signInMagicLink(
@Body() authData: SignInMagicDto,
@Query('origin') origin: string,
) {
const deviceIdToken = await this.authService.signInMagicLink( const deviceIdToken = await this.authService.signInMagicLink(
authData.email, authData.email,
origin,
); );
if (E.isLeft(deviceIdToken)) throwHTTPErr(deviceIdToken.left); if (E.isLeft(deviceIdToken)) throwHTTPErr(deviceIdToken.left);
return deviceIdToken.right; return deviceIdToken.right;

View File

@@ -77,7 +77,7 @@ const encodedRefreshToken =
describe('signInMagicLink', () => { describe('signInMagicLink', () => {
test('Should throw error if email is not in valid format', async () => { test('Should throw error if email is not in valid format', async () => {
const result = await authService.signInMagicLink('bbbgmail.com'); const result = await authService.signInMagicLink('bbbgmail.com', 'admin');
expect(result).toEqualLeft({ expect(result).toEqualLeft({
message: INVALID_EMAIL, message: INVALID_EMAIL,
statusCode: HttpStatus.BAD_REQUEST, statusCode: HttpStatus.BAD_REQUEST,
@@ -94,6 +94,7 @@ describe('signInMagicLink', () => {
const result = await authService.signInMagicLink( const result = await authService.signInMagicLink(
'dwight@dundermifflin.com', 'dwight@dundermifflin.com',
'admin',
); );
expect(result).toEqualRight({ expect(result).toEqualRight({
deviceIdentifier: passwordlessData.deviceIdentifier, deviceIdentifier: passwordlessData.deviceIdentifier,
@@ -108,6 +109,7 @@ describe('signInMagicLink', () => {
const result = await authService.signInMagicLink( const result = await authService.signInMagicLink(
'dwight@dundermifflin.com', 'dwight@dundermifflin.com',
'admin',
); );
expect(result).toEqualRight({ expect(result).toEqualRight({
deviceIdentifier: passwordlessData.deviceIdentifier, deviceIdentifier: passwordlessData.deviceIdentifier,

View File

@@ -27,6 +27,7 @@ import { JwtService } from '@nestjs/jwt';
import { AuthError } from 'src/types/AuthError'; import { AuthError } from 'src/types/AuthError';
import { AuthUser, IsAdmin } from 'src/types/AuthUser'; import { AuthUser, IsAdmin } from 'src/types/AuthUser';
import { VerificationToken } from '@prisma/client'; import { VerificationToken } from '@prisma/client';
import { Origin } from './helper';
@Injectable() @Injectable()
export class AuthService { export class AuthService {
@@ -195,7 +196,7 @@ export class AuthService {
* @param email User's email * @param email User's email
* @returns Either containing DeviceIdentifierToken * @returns Either containing DeviceIdentifierToken
*/ */
async signInMagicLink(email: string) { async signInMagicLink(email: string, origin: string) {
if (!validateEmail(email)) if (!validateEmail(email))
return E.left({ return E.left({
message: INVALID_EMAIL, message: INVALID_EMAIL,
@@ -213,11 +214,25 @@ export class AuthService {
const generatedTokens = await this.generateMagicLinkTokens(user); const generatedTokens = await this.generateMagicLinkTokens(user);
// check to see if origin is valid
let url: string;
switch (origin) {
case Origin.ADMIN:
url = process.env.VITE_ADMIN_URL;
break;
case Origin.APP:
url = process.env.VITE_BASE_URL;
break;
default:
// if origin is invalid by default set URL to Hoppscotch-App
url = process.env.VITE_BASE_URL;
}
await this.mailerService.sendAuthEmail(email, { await this.mailerService.sendAuthEmail(email, {
template: 'code-your-own', template: 'code-your-own',
variables: { variables: {
inviteeEmail: email, inviteeEmail: email,
magicLink: `${process.env.VITE_BASE_URL}/magic-link?token=${generatedTokens.token}`, magicLink: `${url}/magic-link?token=${generatedTokens.token}`,
}, },
}); });

View File

@@ -11,6 +11,11 @@ enum AuthTokenType {
REFRESH_TOKEN = 'refresh_token', REFRESH_TOKEN = 'refresh_token',
} }
export enum Origin {
ADMIN = 'admin',
APP = 'app',
}
/** /**
* This function allows throw to be used as an expression * This function allows throw to be used as an expression
* @param errMessage Message present in the error message * @param errMessage Message present in the error message