Skip to content

Commit aae9851

Browse files
committed
googleAuth
1 parent 4e51ee1 commit aae9851

11 files changed

+14696
-182
lines changed

Diff for: package-lock.json

+14,352
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+5
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
"jsonwebtoken": "^9.0.0",
4545
"nock": "^13.3.0",
4646
"nodemailer": "^6.9.1",
47+
"passport": "^0.6.0",
48+
"passport-google-oauth2": "^0.2.0",
4749
"pg": "^8.9.0",
4850
"pg-hstore": "^2.3.4",
4951
"redis": "^4.6.4",
@@ -58,10 +60,13 @@
5860
"devDependencies": {
5961
"@types/bcrypt": "^5.0.0",
6062
"@types/express": "^4.17.16",
63+
"@types/express-session": "^1.17.6",
6164
"@types/jest": "^29.4.0",
6265
"@types/jsonwebtoken": "^9.0.1",
6366
"@types/nodemailer": "^6.4.7",
67+
"@types/passport": "^1.0.12",
6468
"@types/supertest": "^2.0.12",
69+
"@types/swagger-jsdoc": "^6.0.1",
6570
"@types/swagger-ui-express": "^4.1.3",
6671
"@typescript-eslint/eslint-plugin": "^5.50.0",
6772
"@typescript-eslint/parser": "^5.50.0",

Diff for: src/app.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,21 @@ import {config} from 'dotenv'
33
import swaggerDocs from './docs/swagger'
44
import connectdb from './db/database'
55
import authRoutes from './routes/authroutes'
6-
import profileRoutes from "./routes/profileroutes"
6+
import profileRoutes from './routes/profileroutes'
7+
import passport from 'passport'
8+
import session from 'express-session'
9+
710
const app: Application = express()
11+
import './config/googlePassport.config'
12+
app.use(
13+
session({
14+
secret: `process.env.SECRET`,
15+
resave: false,
16+
saveUninitialized: true,
17+
}),
18+
)
19+
app.use(passport.initialize())
20+
app.use(passport.session())
821

922
config()
1023
//middleware section
@@ -23,4 +36,4 @@ connectdb().then(() => {
2336
// change this to just port in case someone is listening from 127.0.0.1 instead of localhost
2437
})
2538

26-
export default app
39+
export default app

Diff for: src/config/googlePassport.config.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const passport = require('passport')
2+
const GoogleStrategy = require('passport-google-oauth2').Strategy
3+
require('dotenv').config()
4+
passport.use(
5+
new GoogleStrategy(
6+
{
7+
clientID: process.env.CLIENT_ID,
8+
clientSecret: process.env.CLIENT_SECRET,
9+
callbackURL: process.env.CallBackURL,
10+
passReqToCallBack: true,
11+
},
12+
function (request, accessToken, refreshToken, profile, done) {
13+
return done(null, profile)
14+
},
15+
),
16+
)
17+
passport.serializeUser((user, done) => {
18+
done(null, user)
19+
})
20+
passport.deserializeUser((user, done) => {
21+
done(null, user)
22+
})

Diff for: src/controllers/__tests__/authController.test.ts

+82-42
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,35 @@ import supertest from 'supertest'
44
import app from '../../app'
55
import USER from '../../models/User'
66
import Tokens from '../../models/token'
7+
import {httpRequest, httpResponse} from '../mock/user.mock'
8+
import GoogleController from '../googleAuthController'
9+
jest.setTimeout(20000)
10+
describe('Login via google', () => {
11+
afterAll(async () => {
12+
USER.destroy({
13+
where: {email: '[email protected]'},
14+
})
15+
})
16+
test('redirect to google and authenticate', async () => {
17+
const data = await GoogleController.googleAuth(
18+
httpRequest('[email protected]'),
19+
httpResponse(),
20+
)
21+
expect(data.body).toHaveProperty('user')
22+
})
23+
24+
test('testing register', async () => {
25+
const data: any = await GoogleController.googleAuth(
26+
httpRequest('[email protected]'),
27+
httpResponse(),
28+
)
29+
expect(data.body).toHaveProperty('user')
30+
})
31+
test('testing 500', async () => {
32+
const data: any = await GoogleController.googleAuth('helll', httpResponse())
33+
expect(data.body.status).toBe(500)
34+
})
35+
})
736

837
/* eslint-disable @typescript-eslint/no-explicit-any */
938
describe('Math functions', () => {
@@ -18,48 +47,59 @@ describe('Math functions', () => {
1847
})
1948
})
2049
// reset password coontroller tests
21-
describe('reset password',()=>{
22-
describe('send link to email' , ()=>{
23-
test('incase of unregistered email', async ()=>{
24-
const response = await supertest(app).post("/resetpassword/link").send({email: "[email protected]"})
50+
describe('reset password', () => {
51+
describe('send link to email', () => {
52+
test('incase of unregistered email', async () => {
53+
const response = await supertest(app)
54+
.post('/resetpassword/link')
55+
.send({email: '[email protected]'})
2556
expect(response.status).toBe(400)
26-
}, 10000)// timeout 10 seconds
57+
}, 10000) // timeout 10 seconds
2758
})
28-
test('incase of a registered email', async ()=>{
29-
const response = await supertest(app).post("/resetpassword/link").send({email: "[email protected]"})
30-
expect(response.status).toBe(200)
31-
}, 20000)
32-
test('incase invalid email input', async ()=>{
33-
const response = await supertest(app).post("/resetpassword/link").send({email: "rukundjoseph"})
34-
expect(response.status).toBe(400)
35-
}, 20000)
36-
describe('add token and change password',()=>{
37-
test('incase incorrect token', async ()=>{
38-
const response = await supertest(app).patch("/changepassword/[email protected]/65328dba23").send({newpassword : "newpassword",
39-
confirmpass: "newpassword"})
59+
test('incase of a registered email', async () => {
60+
const response = await supertest(app)
61+
.post('/resetpassword/link')
62+
.send({email: '[email protected]'})
63+
expect(response.status).toBe(200)
64+
}, 20000)
65+
test('incase invalid email input', async () => {
66+
const response = await supertest(app)
67+
.post('/resetpassword/link')
68+
.send({email: 'rukundjoseph'})
69+
expect(response.status).toBe(400)
70+
}, 20000)
71+
describe('add token and change password', () => {
72+
test('incase incorrect token', async () => {
73+
const response = await supertest(app)
74+
.patch('/changepassword/[email protected]/65328dba23')
75+
.send({newpassword: 'newpassword', confirmpass: 'newpassword'})
4076
expect(response.status).toBe(400)
41-
}, 20000)
42-
test('incase incorrect token', async ()=>{
43-
const response = await supertest(app).patch("/changepassword/[email protected]/65328dba23").send({newpassword : "newpassword",
44-
confirmpass: "newpassword"})
45-
expect(response.status).toBe(400)
46-
}, 20000)
47-
test('incase of a unmatching passwords', async ()=>{
48-
const user: any = await USER.findOne({where: {email: "[email protected]"}})
49-
const token: any = await Tokens.findOne({where: {userId: `${user.id}`}})
50-
const response = await supertest(app).patch(`/changepassword/[email protected]/${token.token}`).send({newpassword : "newpas",
51-
confirmpass: "newpaa"})
52-
expect(response.status).toBe(400)
53-
})
54-
test('incase of a valid token and email', async ()=>{
55-
const user: any = await USER.findOne({where: {email: "[email protected]"}})
56-
const token: any = await Tokens.findOne({where: {userId: `${user.id}`}})
57-
const response = await supertest(app).patch(`/changepassword/[email protected]/${token.token}`).send({newpassword : "newpas",
58-
confirmpass: "newpas"})
59-
expect(response.status).toBe(200)
60-
})
61-
62-
})
63-
})
64-
65-
77+
}, 20000)
78+
test('incase incorrect token', async () => {
79+
const response = await supertest(app)
80+
.patch('/changepassword/[email protected]/65328dba23')
81+
.send({newpassword: 'newpassword', confirmpass: 'newpassword'})
82+
expect(response.status).toBe(400)
83+
}, 20000)
84+
test('incase of a unmatching passwords', async () => {
85+
const user: any = await USER.findOne({
86+
where: {email: '[email protected]'},
87+
})
88+
const token: any = await Tokens.findOne({where: {userId: `${user.id}`}})
89+
const response = await supertest(app)
90+
.patch(`/changepassword/[email protected]/${token.token}`)
91+
.send({newpassword: 'newpas', confirmpass: 'newpaa'})
92+
expect(response.status).toBe(400)
93+
})
94+
test('incase of a valid token and email', async () => {
95+
const user: any = await USER.findOne({
96+
where: {email: '[email protected]'},
97+
})
98+
const token: any = await Tokens.findOne({where: {userId: `${user.id}`}})
99+
const response = await supertest(app)
100+
.patch(`/changepassword/[email protected]/${token.token}`)
101+
.send({newpassword: 'newpas', confirmpass: 'newpas'})
102+
expect(response.status).toBe(200)
103+
})
104+
})
105+
})

Diff for: src/controllers/googleAuthController.ts

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import User from '../models/User'
2+
import bcrypyt from 'bcrypt'
3+
import jwt from 'jsonwebtoken'
4+
import {randomUUID} from 'crypto'
5+
6+
class GoogleController {
7+
static async googleAuth(req: any, res: any) {
8+
try {
9+
await User.findOne({
10+
where: {
11+
email: req.user.email,
12+
},
13+
}).then(async (result: any) => {
14+
if (result) {
15+
res.status(200).json({
16+
success: true,
17+
user: {
18+
id: result.id,
19+
firstName: result.firstName,
20+
lastName: result.lastName,
21+
email: result.email,
22+
token: generateToken(result),
23+
},
24+
})
25+
} else {
26+
const salt = await bcrypyt.genSalt(10)
27+
const rand = randomUUID()
28+
const hashpassword = await bcrypyt.hash(generateToken(rand), salt)
29+
const user = await User.create({
30+
firstName: req.user.name.givenName,
31+
lastName: req.user.name.familyName,
32+
email: req.user.email,
33+
password: hashpassword,
34+
})
35+
await user.save()
36+
37+
return res.status(200).json({user: user})
38+
}
39+
})
40+
return res
41+
} catch (error) {
42+
return res.status(500).json({status: 500, error: error})
43+
}
44+
}
45+
}
46+
47+
const generateToken = (user) => {
48+
return jwt.sign({user}, 'my-token-secret', {expiresIn: '30d'})
49+
}
50+
export default GoogleController

Diff for: src/controllers/mock/user.mock.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
export const httpRequest = (email) => ({
2+
user: {
3+
id: '1',
4+
email,
5+
name: {
6+
familyName: 'request',
7+
middleName: 'request',
8+
givenName: 'request',
9+
},
10+
firstName: 'firstName',
11+
lastName: 'lastName',
12+
role: 'buyer',
13+
},
14+
})
15+
16+
export const httpResponse = () => {
17+
const res: any = {
18+
json: (data) => {
19+
res.body = data
20+
return res
21+
},
22+
status: (data) => {
23+
res.body = data
24+
return res
25+
},
26+
}
27+
return res
28+
}

0 commit comments

Comments
 (0)