-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #128 from atlp-rwanda/fix-google-auth-3
fixes google authentication issue
- Loading branch information
Showing
6 changed files
with
194 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
import request from 'supertest'; | ||
import { app, server } from '../index'; | ||
import { createConnection, getRepository } from 'typeorm'; | ||
import { getRepository } from 'typeorm'; | ||
import { User, UserInterface } from '../entities/User'; | ||
|
||
import { cleanDatabase } from './test-assets/DatabaseCleanup'; | ||
|
@@ -9,11 +9,17 @@ import { dbConnection } from '../startups/dbConnection'; | |
|
||
import bcrypt from 'bcrypt'; | ||
import jwt from 'jsonwebtoken'; | ||
import googleAuth from '../services/userServices/googleAuthservice'; | ||
import { Request, Response } from 'express'; | ||
|
||
let req: Partial<Request>; | ||
let res: Partial<Response>; | ||
|
||
const userId = uuid(); | ||
const user1Id = uuid(); | ||
const user2Id = uuid(); | ||
const user3Id = uuid(); | ||
const user4Id = uuid(); | ||
|
||
const getAccessToken = (id: string, email: string) => { | ||
return jwt.sign( | ||
|
@@ -86,17 +92,41 @@ const sampleUser3: UserInterface = { | |
role: 'VENDOR', | ||
}; | ||
|
||
const sampleUser4: UserInterface = { | ||
id: user4Id, | ||
firstName: 'user4', | ||
lastName: 'user', | ||
email: '[email protected]', | ||
password: '', | ||
userType: 'Admin', | ||
verified: true, | ||
twoFactorEnabled: true, | ||
twoFactorCode: '123456', | ||
twoFactorCodeExpiresAt: new Date(Date.now() + 10 * 60 * 1000), | ||
gender: 'Male', | ||
phoneNumber: '126380996347', | ||
photoUrl: 'https://example.com/photo.jpg', | ||
role: 'ADMIN', | ||
}; | ||
|
||
|
||
beforeAll(async () => { | ||
const connection = await dbConnection(); | ||
sampleUser.password = await bcrypt.hash('password', 10); | ||
sampleUser2.password = await bcrypt.hash('password', 10); | ||
sampleUser3.password = await bcrypt.hash('password', 10); | ||
sampleUser4.password = await bcrypt.hash('password', 10); | ||
|
||
const userRepository = connection?.getRepository(User); | ||
await userRepository?.save({ ...sampleUser }); | ||
await userRepository?.save({ ...sampleUser1 }); | ||
await userRepository?.save({ ...sampleUser2 }); | ||
await userRepository?.save({ ...sampleUser3 }); | ||
await userRepository?.save({ ...sampleUser4 }); | ||
|
||
res = { | ||
redirect: jest.fn(), | ||
}; | ||
}); | ||
|
||
afterAll(async () => { | ||
|
@@ -131,6 +161,34 @@ describe('User service Test', () => { | |
}); | ||
}); | ||
|
||
it('admin should get all registered user', async () => { | ||
// Arrange | ||
|
||
// Act | ||
const res = await request(app).get('/user/allUsers').set( | ||
{ | ||
'authorization': `Bearer ${getAccessToken(sampleUser4.id!, sampleUser4.email)}` | ||
} | ||
) | ||
// Assert | ||
expect(res.status).toBe(200); | ||
expect(res.body.users).toBeDefined(); | ||
}); | ||
|
||
it('admin should be able to get data for a single user', async () => { | ||
// Arrange | ||
|
||
// Act | ||
const res = await request(app).get(`/user/single/${sampleUser.id}`).set( | ||
{ | ||
'authorization': `Bearer ${getAccessToken(sampleUser4.id!, sampleUser4.email)}` | ||
} | ||
) | ||
// Assert | ||
expect(res.status).toBe(200); | ||
expect(res.body.user).toBeDefined(); | ||
}); | ||
|
||
it('should Login a user, with valid credentials', async () => { | ||
const res = await request(app).post('/user/login').send({ | ||
email: '[email protected]', | ||
|
@@ -533,4 +591,71 @@ describe('User service Test', () => { | |
expect(res.body).toEqual({ status: 'error', message: 'Incorrect email or password' }); | ||
}, 10000); | ||
}); | ||
|
||
describe('google OAuth controller', () => { | ||
it('should redirect with error status, when something went wrong on server', async () => { | ||
await googleAuth(req as Request, res as Response); | ||
expect(res.redirect).toHaveBeenCalledWith(`${process.env.CLIENT_URL}/login/google-auth?status=error`); | ||
}); | ||
it('should redirect with success status', async () => { | ||
req = { | ||
user: { | ||
id: '123', | ||
firstName: 'sample', | ||
lastName: 'User', | ||
email: '[email protected]', | ||
role: 'user', | ||
status: 'active', | ||
twoFactorEnabled: false, | ||
phoneNumber: '1234567890', | ||
}, | ||
}; | ||
|
||
await googleAuth(req as Request, res as Response); | ||
expect(res.redirect).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should redirect with userSuspended status', async () => { | ||
req = { | ||
user: { | ||
id: '123', | ||
firstName: 'sample', | ||
lastName: 'User', | ||
email: '[email protected]', | ||
role: 'user', | ||
status: 'suspended', | ||
twoFactorEnabled: false, | ||
phoneNumber: '1234567890', | ||
}, | ||
}; | ||
|
||
await googleAuth(req as Request, res as Response); | ||
expect(res.redirect).toHaveBeenCalledWith(`${process.env.CLIENT_URL}/login/google-auth?status=userSuspended`); | ||
}); | ||
|
||
it('should redirect with otp status', async () => { | ||
req = { | ||
user: { | ||
id: '123', | ||
firstName: 'sample', | ||
lastName: 'User', | ||
email: '[email protected]', | ||
role: 'user', | ||
status: 'active', | ||
twoFactorEnabled: true, | ||
phoneNumber: '1234567890', | ||
}, | ||
}; | ||
|
||
await googleAuth(req as Request, res as Response); | ||
expect(res.redirect).toHaveBeenCalledWith(`${process.env.CLIENT_URL}/login/google-auth?status=otp&[email protected]`); | ||
}); | ||
|
||
it('should redirect with userNotFound status', async () => { | ||
req.user = undefined; | ||
await googleAuth(req as Request, res as Response); | ||
expect(res.redirect).toHaveBeenCalledWith(`${process.env.CLIENT_URL}/login/google-auth?status=userNotFound`); | ||
}); | ||
|
||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { Request, Response } from 'express'; | ||
import { responseError } from '../../utils/response.utils'; | ||
import { UserInterface } from '../../entities/User'; | ||
import jwt from 'jsonwebtoken'; | ||
import { start2FAProcess } from './userStartTwoFactorAuthProcess'; | ||
import { otpTemplate } from '../../helper/emailTemplates'; | ||
import { sendOTPEmail } from './userSendOTPEmail'; | ||
import { sendOTPSMS } from './userSendOTPMessage'; | ||
|
||
const googleAuth = async (req: Request, res: Response) => { | ||
try { | ||
const user = req.user as UserInterface; | ||
if (!user) { | ||
return res.redirect(`${process.env.CLIENT_URL}/login/google-auth?status=userNotFound`); | ||
} | ||
|
||
if (user.status === 'suspended') { | ||
return res.redirect(`${process.env.CLIENT_URL}/login/google-auth?status=userSuspended`); | ||
} | ||
|
||
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.redirect(`${process.env.CLIENT_URL}/login/google-auth?status=success&token=${token}&role=${user.role?.toLowerCase()}`); | ||
} | ||
|
||
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.redirect(`${process.env.CLIENT_URL}/login/google-auth?status=otp&email=${user.email}`); | ||
} catch (error) { | ||
return res.redirect(`${process.env.CLIENT_URL}/login/google-auth?status=error`); | ||
} | ||
}; | ||
|
||
export default googleAuth; |