From 3555b416e1d64c91ec544ff90c245219b3a4e903 Mon Sep 17 00:00:00 2001
From: aimedivin
Date: Fri, 21 Jun 2024 20:52:30 +0200
Subject: [PATCH] fix(google-auth): resolve API redirect issue on same port
during google authentication - ensure correct redirect to client URL - send
appropriate response to client
---
src/entities/User.ts | 4 +-
src/index.ts | 2 +-
src/routes/ProductRoutes.ts | 2 +-
src/routes/UserRoutes.ts | 49 ++++++++++++++-----
.../sendResetPasswordLinkService.ts | 2 +-
src/services/userServices/userLoginService.ts | 5 +-
.../userServices/userProfileUpdateServices.ts | 3 +-
src/services/userServices/userValidateOTP.ts | 4 +-
src/utils/auth.ts | 5 +-
9 files changed, 54 insertions(+), 22 deletions(-)
diff --git a/src/entities/User.ts b/src/entities/User.ts
index 787c5e0..4808482 100644
--- a/src/entities/User.ts
+++ b/src/entities/User.ts
@@ -25,10 +25,10 @@ export interface UserInterface {
phoneNumber: string;
photoUrl?: string;
verified?: boolean;
+ twoFactorEnabled?: boolean;
status?: 'active' | 'suspended';
userType: 'Admin' | 'Buyer' | 'Vendor';
role?: string;
- twoFactorEnabled?: boolean;
twoFactorCode?: string;
twoFactorCodeExpiresAt?: Date;
createdAt?: Date;
@@ -119,7 +119,7 @@ export class User {
feedbacks!: Feedback[];
@BeforeInsert()
- setRole (): void {
+ setRole(): void {
this.role = this.userType === 'Vendor' ? roles.vendor : roles.buyer;
}
}
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index d689c27..377e419 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -28,7 +28,7 @@ app.use(passport.initialize());
app.use(passport.session());
app.use(express.json());
app.use(cookieParser());
-app.use(cors({ origin: '*' }));
+app.use(cors({ origin: process.env.CLIENT_URL, credentials: true }));
app.use(router);
addDocumentation(app);
app.all('*', (req: Request, res: Response, next) => {
diff --git a/src/routes/ProductRoutes.ts b/src/routes/ProductRoutes.ts
index 49a6c5e..0faba97 100644
--- a/src/routes/ProductRoutes.ts
+++ b/src/routes/ProductRoutes.ts
@@ -18,7 +18,7 @@ import {
createOrder,
getOrders, getOrder,
updateOrder,
- getOrdersHistory,Payment,
+ getOrdersHistory, Payment,
getSingleVendorOrder,
getVendorOrders,
updateVendorOrder,
diff --git a/src/routes/UserRoutes.ts b/src/routes/UserRoutes.ts
index ad25a36..20ba2b2 100644
--- a/src/routes/UserRoutes.ts
+++ b/src/routes/UserRoutes.ts
@@ -20,6 +20,10 @@ import { hasRole } from '../middlewares/roleCheck';
import { isTokenValide } from '../middlewares/isValid';
import passport from 'passport';
import '../utils/auth';
+import { start2FAProcess } from '../services/userServices/userStartTwoFactorAuthProcess';
+import { otpTemplate } from '../helper/emailTemplates';
+import { sendOTPEmail } from '../services/userServices/userSendOTPEmail';
+import { sendOTPSMS } from '../services/userServices/userSendOTPMessage';
import { authMiddleware } from '../middlewares/verifyToken';
const router = Router();
@@ -41,29 +45,52 @@ router.get('/google-auth', passport.authenticate('google', { scope: ['profile',
router.get(
'/auth/google/callback',
passport.authenticate('google', {
- successRedirect: '/user/login/success',
- failureRedirect: '/user/login/failed',
+ successRedirect: `${process.env.CLIENT_URL}/login/google-auth`,
+ failureRedirect: `${process.env.CLIENT_URL}/login/google-auth`,
})
);
router.get('/login/success', async (req, res) => {
const user = req.user as UserInterface;
+
if (!user) {
responseError(res, 404, 'user not found');
+ return;
+ }
+
+ if (user.status === 'suspended') {
+ return res.status(400).json({ status: 'error', message: 'Your account has been suspended' });
}
- const payload = {
- id: user?.id,
- email: user?.email,
- role: user?.role,
- };
- const token = jwt.sign(payload, process.env.JWT_SECRET as string, { expiresIn: '24h' });
- res.status(200).json({
+
+ if (!user.twoFactorEnabled) {
+ const payload = {
+ id: user?.id,
+ firstName: user.firstName,
+ lastName: user.lastName,
+ email: user?.email,
+ role: user?.role,
+ };
+ const token = jwt.sign(payload, process.env.JWT_SECRET as string, { expiresIn: '24h' });
+ return res.status(200).json({
+ status: 'success',
+ data: {
+ token: token,
+ message: 'Login success',
+ },
+ });
+ }
+ const otpCode = await start2FAProcess(user.email);
+ const OTPEmailcontent = otpTemplate(user.firstName, otpCode.toString());
+ await sendOTPEmail('Login OTP Code', user.email, OTPEmailcontent);
+ await sendOTPSMS(user.phoneNumber, otpCode.toString());
+ return res.status(200).json({
status: 'success',
data: {
- token: token,
- message: 'Login success',
+ email: user.email,
+ message: 'Please provide the OTP sent to your email or phone',
},
});
});
+
router.get('/login/failed', async (req, res) => {
res.status(401).json({
status: false,
diff --git a/src/services/userServices/sendResetPasswordLinkService.ts b/src/services/userServices/sendResetPasswordLinkService.ts
index 1d34666..c7d9721 100644
--- a/src/services/userServices/sendResetPasswordLinkService.ts
+++ b/src/services/userServices/sendResetPasswordLinkService.ts
@@ -74,7 +74,7 @@ export const sendPasswordResetLinkService = async (req: Request, res: Response)
password has been generated for you. To reset your password, click the
following link and follow the instructions.
- Reset
Password
diff --git a/src/services/userServices/userLoginService.ts b/src/services/userServices/userLoginService.ts
index 57633d0..fa30bbd 100644
--- a/src/services/userServices/userLoginService.ts
+++ b/src/services/userServices/userLoginService.ts
@@ -42,8 +42,10 @@ export const userLoginService = async (req: Request, res: Response) => {
const token = jwt.sign(
{
id: user.id,
+ firstName: user.firstName,
+ lastName: user.lastName,
email: user.email,
- userType: user.userType,
+ role: user.role,
},
process.env.JWT_SECRET as string,
{ expiresIn: '24h' }
@@ -71,6 +73,7 @@ export const userLoginService = async (req: Request, res: Response) => {
return res.status(200).json({
status: 'success',
data: {
+ email: user.email,
message: 'Please provide the OTP sent to your email or phone',
},
});
diff --git a/src/services/userServices/userProfileUpdateServices.ts b/src/services/userServices/userProfileUpdateServices.ts
index 82fb71d..f5d4b30 100644
--- a/src/services/userServices/userProfileUpdateServices.ts
+++ b/src/services/userServices/userProfileUpdateServices.ts
@@ -2,8 +2,7 @@ import { Request, Response } from 'express';
import { responseError, responseSuccess } from '../../utils/response.utils';
import { User, UserInterface } from '../../entities/User';
import { getRepository } from 'typeorm';
-import { userProfileUpdate } from '../../controllers/authController';
-
+import { userProfileUpdate } from '../../controllers/authController'
export const userProfileUpdateServices = async (req: Request, res: Response) => {
try {
diff --git a/src/services/userServices/userValidateOTP.ts b/src/services/userServices/userValidateOTP.ts
index c26003f..7dce921 100644
--- a/src/services/userServices/userValidateOTP.ts
+++ b/src/services/userServices/userValidateOTP.ts
@@ -26,8 +26,10 @@ export const userValidateOTP = async (req: Request, res: Response) => {
const token = jwt.sign(
{
id: user?.id,
+ firstName: user?.firstName,
+ lastName: user?.lastName,
email: user?.email,
- userType: user?.userType,
+ role: user?.role,
},
process.env.JWT_SECRET as string,
{ expiresIn: '24h' }
diff --git a/src/utils/auth.ts b/src/utils/auth.ts
index 623883f..f09ca47 100644
--- a/src/utils/auth.ts
+++ b/src/utils/auth.ts
@@ -5,12 +5,13 @@ import { User } from '../entities/User';
import { getRepository } from 'typeorm';
import bcrypt from 'bcrypt';
import '../utils/auth';
+import { v4 as uuid } from 'uuid';
passport.use(
new Strategy(
{
clientID: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
- callbackURL: 'http://localhost:6890/user/auth/google/callback/',
+ callbackURL: `http://localhost:${process.env.PORT || 8000}/user/auth/google/callback/`,
scope: ['email', 'profile'],
},
async (accessToken: any, refreshToken: any, profile: any, cb: any) => {
@@ -27,7 +28,7 @@ passport.use(
return await cb(null, existingUser);
}
const saltRounds = 10;
- const hashedPassword = await bcrypt.hash('password', saltRounds);
+ const hashedPassword = await bcrypt.hash(uuid(), saltRounds);
const newUser = new User();
newUser.firstName = givenName;
newUser.lastName = family_name ?? familyName ?? 'undefined';