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 19 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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,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
26 changes: 24 additions & 2 deletions packages/backend/api/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/* eslint-disable @typescript-eslint/consistent-type-definitions */
/* eslint-disable @typescript-eslint/no-namespace */
import cookieParser from 'cookie-parser';
import cors from 'cors';
import express from 'express';
import fileUpload from 'express-fileupload';
Expand All @@ -15,8 +18,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(
'/cdn',
Expand All @@ -32,5 +45,14 @@ 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 global {
namespace 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;
}
46 changes: 46 additions & 0 deletions packages/backend/api/src/middlewares/login.middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { NextFunction, Request, Response } from 'express';
import * as jose from 'jose';

const FRONTEND_HOST = process.env.FRONTEND_HOST ?? '';

const JWT_SECRET = process.env.JWT_SECRET;

const secret = new TextEncoder().encode(JWT_SECRET);

export default async function loginMiddleware(
req: Request,
res: Response,
next: NextFunction,
) {
const token = req.signedCookies.token;

if (!token) {

Check warning on line 17 in packages/backend/api/src/middlewares/login.middleware.ts

View workflow job for this annotation

GitHub Actions / check-pr

Unexpected any value in conditional. An explicit comparison or type conversion is required
console.error('Token is missing in signed cookies');
res.status(401).json({ ok: false, message: 'Token is missing' });
return;
}

try {
const { payload } = await jose.jwtVerify<{ userId: number }>(
token,
secret,
{
audience: FRONTEND_HOST,
issuer: FRONTEND_HOST,
},
);

console.log('Payload:', payload);

Check warning on line 33 in packages/backend/api/src/middlewares/login.middleware.ts

View workflow job for this annotation

GitHub Actions / check-pr

Unexpected console statement. Only these console methods are allowed: error

req.isAuthenticated = true;
req.userId = payload.userId;
} catch (error) {
console.error(error);
res.json({
ok: false,
});
return;
}

next();
}
14 changes: 14 additions & 0 deletions packages/backend/api/src/models/user-cookie.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { db } from '@app/backend-shared';

export default async function userCookie(userId: number) {
try {
return await db
.selectFrom('user')
.select(['user.id', 'user.email'])
.where('user.id', '=', userId)
.executeTakeFirstOrThrow();
} catch (error) {
console.error('Error in userCookie:', error);
throw new Error('Failed to fetch user from database');
}
}
32 changes: 32 additions & 0 deletions packages/backend/api/src/models/user-login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import argon2 from 'argon2';

import { db } from '@app/backend-shared';

export async function userLogin(email: string, password: string) {
try {
const user = await db
.selectFrom('user')
.select(['user.id', 'user.password', 'user.email'])
.where('user.email', '=', email || 'user.username ')
.executeTakeFirst();

if (!user) {
return { error: 'Invalid email or password' };
}

const isPasswordValid = await argon2.verify(user.password, password);

if (!isPasswordValid) {
return { error: 'Invalid email or password' };
}

return {
message: 'Login successful',
userId: user.id,
email: user.email,
};
} catch (error) {
console.error('Error logging in:', error);
throw new Error('Internal server error');
}
}
25 changes: 25 additions & 0 deletions packages/backend/api/src/models/user-register.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import argon2 from 'argon2';

import { db } from '@app/backend-shared';

export async function userRegister(
email: string,
username: string,
password: string,
) {
const hashPassword = await argon2.hash(password, {
memoryCost: 19456,
timeCost: 2,
parallelism: 1,
});

return db
.insertInto('user')
.values({ email, username, password: hashPassword })
.executeTakeFirst()
.then(() => ({ message: 'User created successfully' }))
.catch((error: unknown) => {
console.error('Error creating user:', error);
throw new Error('Failed to create user');
});
}
16 changes: 16 additions & 0 deletions packages/backend/api/src/router.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
import express from 'express';

import loginGuards from './middlewares/login.guards';
import loginMiddleware from './middlewares/login.middleware';
import userLoginRouter, { cookkieRouterGet } from './subrouters/login-router';
import userLogout from './subrouters/logout-router';
import postsRouter from './subrouters/posts-router';
import tagsRouter from './subrouters/tags-router';
import usersRouter from './subrouters/users-router';

const router = express.Router();

router.use('/register', usersRouter);

router.use('/login', userLoginRouter);
router.use('/logout', userLogout);

// 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('/cookie', cookkieRouterGet);

router.get('*', function (req, res) {
res.status(404).send(`ressource ${req.path} not found`);
});
Expand Down
111 changes: 111 additions & 0 deletions packages/backend/api/src/subrouters/login-router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import express from 'express';
import * as jose from 'jose';

import { db } from '@app/backend-shared';
import { env } from '@app/shared';

import loginGuards from '@/middlewares/login.guards';
import { userLogin } from '@/models/user-login';

env();

const userLoginRouter = express.Router();

export const cookkieRouterGet = express.Router();

const FRONTEND_HOST = process.env.FRONTEND_HOST ?? '';

const JWT_SECRET = process.env.JWT_SECRET;

const secret = new TextEncoder().encode(JWT_SECRET);

// POST LOGIN**************************************************

userLoginRouter.post('/', async function (req, res) {
try {
const { email, password } = req.body;

const userAccess = await userLogin(email, password);

const token = await new jose.SignJWT({
sub: email,
userId: userAccess.userId,
})
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setIssuer(FRONTEND_HOST)
.setAudience(FRONTEND_HOST)
.setExpirationTime('60s')
.sign(secret);

res.cookie('token', token, {
httpOnly: true,
signed: true,
// secure: true,
// sameSite: 'strict',
});

res.json(userAccess);
} catch (error) {
if (
error instanceof Error &&
error.message === 'Invalid email or password'
) {
res.status(401).json({ message: error.message });
} else {
console.error('Error during login:', error);
res.status(500).json({ message: 'Internal login server error' });
}
}
});

// GET COOKIES **************************************************

cookkieRouterGet.get('/', loginGuards, async function (req, res) {
const userId = req.userId;

if (userId === undefined) {
res.json({ ok: 'false' });
return;
}

try {
const user = await db
.selectFrom('user')
.selectAll()
.where('user.id', '=', userId)
.executeTakeFirst();

if (!user) {
res.json({ ok: 'false' });
return;
}
res.json({ user, ok: 'true' });
} catch (error) {
console.error(error);
res.json(
'not authorized, please login to get your token or check your cookies',
);
return;
}
});

// GET **************************************************

userLoginRouter.get('/:id', function (req, res) {
res.send('login get');
});

// UPDATE **************************************************

userLoginRouter.put('/', function (req, res) {
res.send('login put');
});

// DELETE **************************************************

userLoginRouter.delete('/:id', function (req, res) {
res.send('login delete');
});

export default userLoginRouter;
16 changes: 16 additions & 0 deletions packages/backend/api/src/subrouters/logout-router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// POST LOGOUT**************************************************
import express from 'express';

const userLogout = express.Router();

userLogout.post('/', function (req, res) {
try {
res.clearCookie('token');
res.json({ ok: true });
} catch (error) {
console.error('Error during logout:', error);
res.status(500).json({ message: 'Internal logout server error' });
}
});

export default userLogout;
Loading
Loading