Skip to content

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

Open
wants to merge 29 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d1018ab
composant login, composant logo et page login faites(mobile)
sadjoaldi Mar 28, 2025
87d41d0
page login, signup, forgotten password done
sadjoaldi Mar 31, 2025
9d5224c
bug build
sadjoaldi Apr 1, 2025
4282fa1
bug build
sadjoaldi Apr 1, 2025
97024fe
bug build
sadjoaldi Apr 1, 2025
26faf67
merge develop
sadjoaldi Apr 1, 2025
9151867
pull develop
sadjoaldi Apr 1, 2025
ba2db5d
ajustement style
sadjoaldi Apr 2, 2025
92a6377
register&login back ok, login front ok
sadjoaldi Apr 9, 2025
a5c3381
renommage de fichiers, register et login ok front et back
sadjoaldi Apr 9, 2025
940e59d
cheik error
sadjoaldi Apr 9, 2025
14b1fcb
cheik error
sadjoaldi Apr 9, 2025
626410c
cheik error
sadjoaldi Apr 9, 2025
ffb02e8
correction
sadjoaldi Apr 10, 2025
c30c060
register, login, logout good
sadjoaldi Apr 17, 2025
8d9f34e
register, login, logout ok
sadjoaldi Apr 22, 2025
b1ae9eb
Merge branch 'develop' into feature/login-formular
sadjoaldi Apr 22, 2025
dada3ee
register,login, logout
sadjoaldi Apr 22, 2025
fe40730
register,login, logout
sadjoaldi Apr 22, 2025
d19dfe1
corrections
sadjoaldi Apr 23, 2025
07d13d2
regis, log, cook
sadjoaldi Apr 24, 2025
c68a1c0
pull
sadjoaldi Apr 24, 2025
143c9e8
Merge branch 'develop' into feature/login-formular
sadjoaldi Apr 24, 2025
7b4c593
pull
sadjoaldi Apr 24, 2025
0251665
pull
sadjoaldi Apr 24, 2025
bb00354
pull
sadjoaldi Apr 24, 2025
2a47c44
corrections
sadjoaldi Apr 24, 2025
8561465
correct
sadjoaldi Apr 25, 2025
c2bcfdd
Delete .vscode/settings.json
TeddyAgt Apr 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ DB_USER="$MYSQL_USER"
DB_PASS="$MYSQL_PASSWORD"
DB_NAME="$MYSQL_DATABASE"
DB_URL="mysql://$DB_USER:$DB_PASS@$DB_HOST:$DB_PORT/$DB_NAME"

ACCESS_TOKEN_SECRET="Your_ACCESS_TOKEN_SECRET"
REFRESH_TOKEN_SECRET="Your_REFRESH_TOKEN_SECRET"
COOKIE_SECRET="Your_Cookie_secret"
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ node_modules

# IDE - VSCode
.vscode/*
!.vscode/settings.json
# !.vscode/settings.json
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json


# misc
/.sass-cache
/connect.lock
Expand Down Expand Up @@ -56,4 +57,5 @@ web-build/
*-mock.*
deployment/db/
*-mock.*
test.js
test.js
**/*.tsbuildinfo
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ packages/frontend/mobile/ios
packages/frontend/mobile/android
deployment/mysql/data
**/types/database.ts
**/*.tsbuildinfo
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"Devdb.colorTheme": "dark"
}
1 change: 1 addition & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default typescriptPlugin.config([
'packages/frontend/mobile/ios',
'packages/frontend/mobile/android',
'deployment/mysql/data',
'**/*.tsbuildinfo',
],
},
{
Expand Down
864 changes: 480 additions & 384 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions packages/backend/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@
"dependencies": {
"@app/backend-shared": "*",
"@app/shared": "*",
"argon2": "^0.41.1",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"express": "^4.21.2",
"jose": "^6.0.10",
"express-fileupload": "^1.5.1",
"kysely": "^0.27.6",
"sharp": "^0.34.1"
},
"devDependencies": {
"@types/cookie-parser": "^1.4.8",
"@types/cors": "^2.8.17",
"@types/express": "^5.0.0",
"@types/express-fileupload": "^1.5.1",
Expand Down
23 changes: 21 additions & 2 deletions packages/backend/api/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/consistent-type-definitions */
import cookieParser from 'cookie-parser';
import cors from 'cors';
import express from 'express';
import fileUpload from 'express-fileupload';
Expand All @@ -15,8 +17,18 @@ const app = express();
const HOST = process.env.BACKEND_HOST ?? 'localhost';
const PORT = process.env.BACKEND_PORT ?? 3000;

const COOKIE_SECRET = process.env.COOKIE_SECRET ?? 'secret';

app.use(cookieParser(COOKIE_SECRET));

app.use(express.json());
app.use(cors());

app.use(
cors({
origin: `http://${process.env.FRONTEND_HOST}:${process.env.FRONTEND_PORT}`,
credentials: true,
}),
);

app.use(fileUpload());
app.use(
Expand All @@ -33,5 +45,12 @@ app.listen(PORT, () => {
console.log(`Server is listening on http://${HOST}:${PORT}`);
});

export default app;
export type * from './models/model-types';
export default app;

declare module 'Express' {
interface Request {
isAuthenticated?: boolean;
userId?: number;
}
}
17 changes: 17 additions & 0 deletions packages/backend/api/src/middlewares/login.guards.ts
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;
}
93 changes: 93 additions & 0 deletions packages/backend/api/src/middlewares/login.middleware.ts
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);
Copy link
Contributor

Choose a reason for hiding this comment

The 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
A l'échelle de centaines d'utilisateurs, tu vas très vite surcharger les fichiers de logs, et donc le stockage de ton serveur


// 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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idem


// If the refresh token is invalid,
req.isAuthenticated = false;
return;
Copy link
Contributor

Choose a reason for hiding this comment

The 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();
}
69 changes: 69 additions & 0 deletions packages/backend/api/src/models/user-model.ts
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) {

Check warning on line 6 in packages/backend/api/src/models/user-model.ts

View workflow job for this annotation

GitHub Actions / check-pr

'password' is defined but never used
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

return db
.selectFrom('user')
.select(['user.id', 'user.password', 'user.email'])
.where('user.email', '=', email || 'user.username ')
Copy link
Contributor

Choose a reason for hiding this comment

The 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
Copy link
Contributor

Choose a reason for hiding this comment

The 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
Expand Down
19 changes: 18 additions & 1 deletion packages/backend/api/src/router.ts
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
Copy link
Contributor

Choose a reason for hiding this comment

The 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` });
Expand Down
Loading
Loading