From 7f5c7f041c9c06f1529d59e0af02978ff569cc87 Mon Sep 17 00:00:00 2001 From: dev4 Date: Thu, 18 Sep 2025 19:36:28 +0000 Subject: [PATCH] feat(idnot): accepter code en JSON body sur POST /api/v1/idnot/auth | ci: docker_tag=ext --- .env.exemple | 3 ++- CHANGELOG.md | 7 +++++ docs/analyse.md | 4 +++ package.json | 2 +- src/handlers/idnot.handlers.ts | 48 ++++++++++++++++++---------------- src/routes/idnot.routes.ts | 2 +- tests/analyse.md | 4 +++ 7 files changed, 44 insertions(+), 26 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.env.exemple b/.env.exemple index 547f36b..d674744 100644 --- a/.env.exemple +++ b/.env.exemple @@ -89,4 +89,5 @@ STRIPE_STANDARD_ANNUAL_SUBSCRIPTION_PRICE_ID= STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID= STRIPE_UNLIMITED_ANNUAL_SUBSCRIPTION_PRICE_ID= -SIGNER_API_KEY=your-api-key-change-this \ No newline at end of file +SIGNER_API_KEY=your-api-key-change-this +VITE_JWT_SECRET_KEY=52b3d77617bb00982dfee15b08effd52cfe5b2e69b2f61cc4848cfe1e98c0bc9 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..55fcbe7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +## v1.0.1 + +- IdNot: l’endpoint d’authentification accepte désormais le code en POST `/api/v1/idnot/auth` avec `{ code }` dans le corps. +- Handler compatible params/body, recommandation: body JSON. +- Rappel déploiement: image Docker consommée par `lecoffre_node` via tag `ext`. + + diff --git a/docs/analyse.md b/docs/analyse.md index 642eb58..4ac7375 100644 --- a/docs/analyse.md +++ b/docs/analyse.md @@ -24,6 +24,10 @@ Analyse synthétique de `lecoffre-back-mini` (Express + TypeScript). - retry emails (1 min) - **Arrêts propres**: gestion `SIGINT`/`SIGTERM`, exceptions et promesses rejetées +### Changements IdNot +- L’endpoint d’authentification accepte désormais le code en POST corps JSON sur `/api/v1/idnot/auth` (au lieu d’un segment d’URL). +- Le handler supporte à la fois `req.params.code` et `req.body.code` pour compatibilité, mais l’usage recommandé est `req.body.code`. + ### Dépendances clés - **HTTP**: `express`, `cors` - **Infra**: `pg`, `dotenv` diff --git a/package.json b/package.json index 19acc49..25cbf4e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lecoffre-back-mini", - "version": "1.0.0", + "version": "1.0.1", "description": "Mini serveur avec une route /api/ping", "main": "dist/server.js", "scripts": { diff --git a/src/handlers/idnot.handlers.ts b/src/handlers/idnot.handlers.ts index d79d214..04a33d7 100644 --- a/src/handlers/idnot.handlers.ts +++ b/src/handlers/idnot.handlers.ts @@ -4,21 +4,21 @@ import { asyncHandler } from '../middleware/error-handler'; import { ValidationError, BusinessRuleError } from '../types/errors'; /** - * Route handlers that extract and validate HTTP request data + * Route handlers that extract and validate HTTP request data * before calling pure controller methods */ export class IdNotHandlers { - + /** * GET /user/rattachements * Extract idNot from query params and call controller */ static getUserRattachements = asyncHandler(async (req: Request, res: Response): Promise => { const requestId = req.headers['x-request-id'] as string; - + // Extract and validate parameters const { idNot } = req.query; - + if (!idNot || typeof idNot !== 'string') { throw new ValidationError('idNot parameter is required', [ { field: 'idNot', value: idNot, constraints: ['Must be a valid string'] } @@ -27,20 +27,20 @@ export class IdNotHandlers { // Call pure controller method with extracted parameters const result = await IdNotController.getUserRattachements(idNot); - + res.json(result); }); /** - * GET /office/rattachements + * GET /office/rattachements * Extract idNot from query params and call controller */ static getOfficeRattachements = asyncHandler(async (req: Request, res: Response): Promise => { const requestId = req.headers['x-request-id'] as string; - + // Extract and validate parameters const { idNot } = req.query; - + if (!idNot || typeof idNot !== 'string') { throw new ValidationError('idNot parameter is required', [ { field: 'idNot', value: idNot, constraints: ['Must be a valid string'] } @@ -49,7 +49,7 @@ export class IdNotHandlers { // Call pure controller method const result = await IdNotController.getOfficeRattachements(idNot); - + res.json(result); }); @@ -59,10 +59,12 @@ export class IdNotHandlers { */ static authenticate = asyncHandler(async (req: Request, res: Response): Promise => { const requestId = req.headers['x-request-id'] as string; - - // Extract and validate parameters - const { code } = req.params; - + + // Extract and validate parameters (support body or URL param) + const codeParam = req.params?.code; + const codeBody = (req.body && typeof req.body.code === 'string') ? req.body.code : undefined; + const code = (codeBody && codeBody.length > 0) ? codeBody : codeParam; + if (!code || typeof code !== 'string' || code.length < 10) { throw new ValidationError('Invalid authentication code', [ { field: 'code', value: code, constraints: ['Must be a valid authorization code'] } @@ -71,7 +73,7 @@ export class IdNotHandlers { // Call pure controller method const result = await IdNotController.authenticate(code); - + res.json(result); }); @@ -81,17 +83,17 @@ export class IdNotHandlers { */ static getCurrentUser = asyncHandler(async (req: Request, res: Response): Promise => { const requestId = req.headers['x-request-id'] as string; - + // Extract user info (set by authenticateIdNot middleware) if (!req.idNotUser) { throw new BusinessRuleError('User authentication required', undefined, requestId); } const { idNot, authToken } = req.idNotUser; - + // Call pure controller method const result = await IdNotController.getCurrentUser(idNot, authToken); - + res.json(result); }); @@ -101,16 +103,16 @@ export class IdNotHandlers { */ static logout = asyncHandler(async (req: Request, res: Response): Promise => { const requestId = req.headers['x-request-id'] as string; - + if (!req.idNotUser) { throw new BusinessRuleError('User authentication required', undefined, requestId); } const { authToken } = req.idNotUser; - + // Call pure controller method const result = await IdNotController.logout(authToken); - + res.json(result); }); @@ -120,16 +122,16 @@ export class IdNotHandlers { */ static validateToken = asyncHandler(async (req: Request, res: Response): Promise => { const requestId = req.headers['x-request-id'] as string; - + if (!req.idNotUser) { throw new BusinessRuleError('User authentication required', undefined, requestId); } const { idNot } = req.idNotUser; - + // Call pure controller method const result = await IdNotController.validateToken(idNot); - + res.json(result); }); } diff --git a/src/routes/idnot.routes.ts b/src/routes/idnot.routes.ts index 596108d..0d5245f 100644 --- a/src/routes/idnot.routes.ts +++ b/src/routes/idnot.routes.ts @@ -6,7 +6,7 @@ const router = Router(); router.get('/user/rattachements', IdNotHandlers.getUserRattachements); router.get('/office/rattachements', IdNotHandlers.getOfficeRattachements); -router.post('/auth/:code', IdNotHandlers.authenticate); +router.post('/auth', IdNotHandlers.authenticate); router.get('/user', authenticateIdNot, IdNotHandlers.getCurrentUser); router.post('/logout', authenticateIdNot, IdNotHandlers.logout); diff --git a/tests/analyse.md b/tests/analyse.md index 482b5c4..da15fa1 100644 --- a/tests/analyse.md +++ b/tests/analyse.md @@ -14,3 +14,7 @@ Axes de tests pour `lecoffre-back-mini` (sans exemples d’implémentation). ### Sécurité - **Entrées**: validation, schémas, erreurs typées - **Secrets**: vérification de la non-exposition via réponses API + +### Auth IdNot +- Vérifier POST `/api/v1/idnot/auth` avec un code long dans le corps JSON (`{ code }`) retourne un statut applicatif (4xx/5xx) mais pas 502. +- Vérifier qu’un GET/POST avec segment d’URL trop long n’est plus utilisé par le front.