-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/login formular #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 27 commits
d1018ab
87d41d0
9d5224c
4282fa1
97024fe
26faf67
9151867
ba2db5d
92a6377
a5c3381
940e59d
14b1fcb
626410c
ffb02e8
c30c060
8d9f34e
b1ae9eb
dada3ee
fe40730
d19dfe1
07d13d2
c68a1c0
143c9e8
7b4c593
0251665
bb00354
2a47c44
8561465
c2bcfdd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
TeddyAgt marked this conversation as resolved.
Show resolved
Hide resolved
sadjoaldi marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"Devdb.colorTheme": "dark" | ||
} |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import type { NextFunction, Request, Response } from 'express'; | ||
|
||
export default function loginGuards( | ||
req: Request, | ||
res: Response, | ||
next: NextFunction, | ||
) { | ||
if (req.isAuthenticated === true) { | ||
next(); | ||
return; | ||
} | ||
|
||
res.json({ | ||
ok: false, | ||
}); | ||
return; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import type { NextFunction, Request, Response } from 'express'; | ||
import * as jose from 'jose'; | ||
|
||
import { env } from '@app/shared'; | ||
|
||
const FRONTEND_HOST = process.env.FRONTEND_HOST ?? ''; | ||
|
||
env(); | ||
|
||
const ACCESS_TOKEN_SECRET = process.env.ACCESS_TOKEN_SECRET; | ||
const accessTokenSecret = new TextEncoder().encode(ACCESS_TOKEN_SECRET); | ||
|
||
const REFRESH_TOKEN_SECRET = process.env.REFRESH_TOKEN_SECRET; | ||
const refreshTokenSecret = new TextEncoder().encode(REFRESH_TOKEN_SECRET); | ||
|
||
export default async function loginMiddleware( | ||
req: Request, | ||
res: Response, | ||
next: NextFunction, | ||
) { | ||
// Check if the request has a signed cookie named accessToken | ||
const accessToken = req.signedCookies.accessToken; | ||
|
||
if (accessToken === undefined) { | ||
console.error('accessToken is missing in signed cookies'); | ||
res.status(401).json({ ok: false, message: 'accessToken is missing' }); | ||
return; | ||
} | ||
|
||
try { | ||
// Verify the access token and extract the payload | ||
const { payload } = await jose.jwtVerify<{ userId: number }>( | ||
accessToken, | ||
accessTokenSecret, | ||
{ | ||
audience: FRONTEND_HOST, | ||
issuer: FRONTEND_HOST, | ||
}, | ||
); | ||
|
||
// If the access token is valid: | ||
|
||
req.isAuthenticated = true; | ||
req.userId = payload.userId; | ||
} catch (aterror) { | ||
console.error(aterror); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Surtout pas ! C'est une erreur qui va arriver très souvent, et c'est normal, si on console.log, ça va seulement spam les logs |
||
|
||
// If the access token is invalid, we check if the refresh token is present | ||
const refreshToken = req.signedCookies.refreshToken; | ||
|
||
try { | ||
const { payload } = await jose.jwtVerify<{ userId: number }>( | ||
refreshToken, | ||
refreshTokenSecret, | ||
{ | ||
audience: FRONTEND_HOST, | ||
issuer: FRONTEND_HOST, | ||
}, | ||
); | ||
|
||
// If the refresh token is valid, we create a new access token and set it in the cookie | ||
|
||
const newAccessToken = await new jose.SignJWT({ | ||
sub: payload.sub, | ||
userId: payload.userId, | ||
}) | ||
.setProtectedHeader({ alg: 'HS256' }) | ||
.setIssuedAt() | ||
.setIssuer(FRONTEND_HOST) | ||
.setAudience(FRONTEND_HOST) | ||
.setExpirationTime('60s') | ||
.sign(accessTokenSecret); | ||
|
||
res.cookie('newAccessToken', newAccessToken, { | ||
httpOnly: true, | ||
signed: true, | ||
// secure: true, | ||
// sameSite: 'strict', | ||
}); | ||
|
||
req.isAuthenticated = true; | ||
req.userId = payload.userId; | ||
} catch (rterror) { | ||
console.error('Refresh token is invalid', rterror); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. idem |
||
|
||
// If the refresh token is invalid, | ||
req.isAuthenticated = false; | ||
return; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pourquoi return ? Si on arrive ici, le client qui fait la requête n'aura jamais de réponse |
||
} | ||
} | ||
|
||
next(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,76 @@ | ||
import argon2 from 'argon2'; | ||
import { jsonArrayFrom } from 'kysely/helpers/mysql'; | ||
|
||
import { db } from '@app/backend-shared'; | ||
|
||
export async function userLogin(email: string, password: string) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
return db | ||
.selectFrom('user') | ||
.select(['user.id', 'user.password', 'user.email']) | ||
.where('user.email', '=', email || 'user.username ') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pourquoi ? |
||
.executeTakeFirst(); | ||
} | ||
|
||
export async function userRegister( | ||
email: string, | ||
username: string, | ||
password: string, | ||
) { | ||
try { | ||
// Pour la verif du mail | ||
const existingEmail = await db | ||
.selectFrom('user') | ||
.select('email') | ||
.where('email', '=', email) | ||
.executeTakeFirst(); | ||
|
||
if (existingEmail) { | ||
return { error: 'Email is already in use, please use a different email' }; | ||
} | ||
|
||
// Pour la verif du username | ||
const existingUsername = await db | ||
.selectFrom('user') | ||
.select('username') | ||
.where('username', '=', username) | ||
.executeTakeFirst(); | ||
|
||
if (existingUsername) { | ||
return { | ||
error: 'Email is already in use, please use a different username', | ||
}; | ||
} | ||
Comment on lines
+21
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tu peux faire 1 seule requête SQL avec un "or where" |
||
|
||
// Hachage du mot de passe | ||
const hashPassword = await argon2.hash(password, { | ||
memoryCost: 19456, | ||
timeCost: 2, | ||
parallelism: 1, | ||
}); | ||
|
||
// Insert de l'utilisateur dans la base de données | ||
await db | ||
.insertInto('user') | ||
.values({ email, username, password: hashPassword }) | ||
.executeTakeFirst(); | ||
|
||
return { message: 'User created successfully' }; | ||
} catch (error) { | ||
console.error('Error creating user:', error); | ||
throw new Error( | ||
error instanceof Error ? error.message : 'Failed to create user', | ||
); | ||
} | ||
} | ||
|
||
export async function getUserById(userId: number) { | ||
return db | ||
.selectFrom('user') | ||
.selectAll() | ||
.where('user.id', '=', userId) | ||
.executeTakeFirst(); | ||
} | ||
|
||
export default { | ||
async getUserProfileById(userId: number) { | ||
const profile = await db | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,32 @@ | ||
// src/router.ts | ||
import express from 'express'; | ||
|
||
import loginGuards from './middlewares/login.guards'; | ||
import loginMiddleware from './middlewares/login.middleware'; | ||
import userLoginRouter, { cookieRouterGet } from './subrouters/login-router'; | ||
import userLogout from './subrouters/logout-router'; | ||
Comment on lines
+4
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. c'est n'importe quoi le nommage |
||
import postsRouter from './subrouters/posts-router'; | ||
import tagsRouter from './subrouters/tags-router'; | ||
import usersRouter from './subrouters/users-router'; | ||
|
||
const router = express.Router(); | ||
|
||
// users registration | ||
router.use('/users', usersRouter); | ||
|
||
router.use('/login', userLoginRouter); | ||
|
||
// Middleware to check if the user is authenticated | ||
router.use(loginMiddleware); | ||
|
||
//login guards il faudra mettre mettre toutes les routes qui necessitent d'etre authentifié | ||
router.use(loginGuards); | ||
router.use('/posts', postsRouter); | ||
router.use('/tags', tagsRouter); | ||
router.use('/users', usersRouter); | ||
|
||
router.use('/logout', userLogout); | ||
|
||
router.use('/cookie', cookieRouterGet); | ||
|
||
router.use('*', (req, res) => { | ||
res.status(404).json({ message: `Resource ${req.path} not found` }); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why?