feat(idnot): accepter code en JSON body sur POST /api/v1/idnot/auth | ci: docker_tag=ext
This commit is contained in:
parent
10832ef375
commit
7f5c7f041c
@ -89,4 +89,5 @@ STRIPE_STANDARD_ANNUAL_SUBSCRIPTION_PRICE_ID=
|
|||||||
STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID=
|
STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID=
|
||||||
STRIPE_UNLIMITED_ANNUAL_SUBSCRIPTION_PRICE_ID=
|
STRIPE_UNLIMITED_ANNUAL_SUBSCRIPTION_PRICE_ID=
|
||||||
|
|
||||||
SIGNER_API_KEY=your-api-key-change-this
|
SIGNER_API_KEY=your-api-key-change-this
|
||||||
|
VITE_JWT_SECRET_KEY=52b3d77617bb00982dfee15b08effd52cfe5b2e69b2f61cc4848cfe1e98c0bc9
|
7
CHANGELOG.md
Normal file
7
CHANGELOG.md
Normal file
@ -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`.
|
||||||
|
|
||||||
|
|
@ -24,6 +24,10 @@ Analyse synthétique de `lecoffre-back-mini` (Express + TypeScript).
|
|||||||
- retry emails (1 min)
|
- retry emails (1 min)
|
||||||
- **Arrêts propres**: gestion `SIGINT`/`SIGTERM`, exceptions et promesses rejetées
|
- **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
|
### Dépendances clés
|
||||||
- **HTTP**: `express`, `cors`
|
- **HTTP**: `express`, `cors`
|
||||||
- **Infra**: `pg`, `dotenv`
|
- **Infra**: `pg`, `dotenv`
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "lecoffre-back-mini",
|
"name": "lecoffre-back-mini",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Mini serveur avec une route /api/ping",
|
"description": "Mini serveur avec une route /api/ping",
|
||||||
"main": "dist/server.js",
|
"main": "dist/server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -4,21 +4,21 @@ import { asyncHandler } from '../middleware/error-handler';
|
|||||||
import { ValidationError, BusinessRuleError } from '../types/errors';
|
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
|
* before calling pure controller methods
|
||||||
*/
|
*/
|
||||||
export class IdNotHandlers {
|
export class IdNotHandlers {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET /user/rattachements
|
* GET /user/rattachements
|
||||||
* Extract idNot from query params and call controller
|
* Extract idNot from query params and call controller
|
||||||
*/
|
*/
|
||||||
static getUserRattachements = asyncHandler(async (req: Request, res: Response): Promise<void> => {
|
static getUserRattachements = asyncHandler(async (req: Request, res: Response): Promise<void> => {
|
||||||
const requestId = req.headers['x-request-id'] as string;
|
const requestId = req.headers['x-request-id'] as string;
|
||||||
|
|
||||||
// Extract and validate parameters
|
// Extract and validate parameters
|
||||||
const { idNot } = req.query;
|
const { idNot } = req.query;
|
||||||
|
|
||||||
if (!idNot || typeof idNot !== 'string') {
|
if (!idNot || typeof idNot !== 'string') {
|
||||||
throw new ValidationError('idNot parameter is required', [
|
throw new ValidationError('idNot parameter is required', [
|
||||||
{ field: 'idNot', value: idNot, constraints: ['Must be a valid string'] }
|
{ field: 'idNot', value: idNot, constraints: ['Must be a valid string'] }
|
||||||
@ -27,20 +27,20 @@ export class IdNotHandlers {
|
|||||||
|
|
||||||
// Call pure controller method with extracted parameters
|
// Call pure controller method with extracted parameters
|
||||||
const result = await IdNotController.getUserRattachements(idNot);
|
const result = await IdNotController.getUserRattachements(idNot);
|
||||||
|
|
||||||
res.json(result);
|
res.json(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET /office/rattachements
|
* GET /office/rattachements
|
||||||
* Extract idNot from query params and call controller
|
* Extract idNot from query params and call controller
|
||||||
*/
|
*/
|
||||||
static getOfficeRattachements = asyncHandler(async (req: Request, res: Response): Promise<void> => {
|
static getOfficeRattachements = asyncHandler(async (req: Request, res: Response): Promise<void> => {
|
||||||
const requestId = req.headers['x-request-id'] as string;
|
const requestId = req.headers['x-request-id'] as string;
|
||||||
|
|
||||||
// Extract and validate parameters
|
// Extract and validate parameters
|
||||||
const { idNot } = req.query;
|
const { idNot } = req.query;
|
||||||
|
|
||||||
if (!idNot || typeof idNot !== 'string') {
|
if (!idNot || typeof idNot !== 'string') {
|
||||||
throw new ValidationError('idNot parameter is required', [
|
throw new ValidationError('idNot parameter is required', [
|
||||||
{ field: 'idNot', value: idNot, constraints: ['Must be a valid string'] }
|
{ field: 'idNot', value: idNot, constraints: ['Must be a valid string'] }
|
||||||
@ -49,7 +49,7 @@ export class IdNotHandlers {
|
|||||||
|
|
||||||
// Call pure controller method
|
// Call pure controller method
|
||||||
const result = await IdNotController.getOfficeRattachements(idNot);
|
const result = await IdNotController.getOfficeRattachements(idNot);
|
||||||
|
|
||||||
res.json(result);
|
res.json(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -59,10 +59,12 @@ export class IdNotHandlers {
|
|||||||
*/
|
*/
|
||||||
static authenticate = asyncHandler(async (req: Request, res: Response): Promise<void> => {
|
static authenticate = asyncHandler(async (req: Request, res: Response): Promise<void> => {
|
||||||
const requestId = req.headers['x-request-id'] as string;
|
const requestId = req.headers['x-request-id'] as string;
|
||||||
|
|
||||||
// Extract and validate parameters
|
// Extract and validate parameters (support body or URL param)
|
||||||
const { code } = req.params;
|
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) {
|
if (!code || typeof code !== 'string' || code.length < 10) {
|
||||||
throw new ValidationError('Invalid authentication code', [
|
throw new ValidationError('Invalid authentication code', [
|
||||||
{ field: 'code', value: code, constraints: ['Must be a valid authorization code'] }
|
{ field: 'code', value: code, constraints: ['Must be a valid authorization code'] }
|
||||||
@ -71,7 +73,7 @@ export class IdNotHandlers {
|
|||||||
|
|
||||||
// Call pure controller method
|
// Call pure controller method
|
||||||
const result = await IdNotController.authenticate(code);
|
const result = await IdNotController.authenticate(code);
|
||||||
|
|
||||||
res.json(result);
|
res.json(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -81,17 +83,17 @@ export class IdNotHandlers {
|
|||||||
*/
|
*/
|
||||||
static getCurrentUser = asyncHandler(async (req: Request, res: Response): Promise<void> => {
|
static getCurrentUser = asyncHandler(async (req: Request, res: Response): Promise<void> => {
|
||||||
const requestId = req.headers['x-request-id'] as string;
|
const requestId = req.headers['x-request-id'] as string;
|
||||||
|
|
||||||
// Extract user info (set by authenticateIdNot middleware)
|
// Extract user info (set by authenticateIdNot middleware)
|
||||||
if (!req.idNotUser) {
|
if (!req.idNotUser) {
|
||||||
throw new BusinessRuleError('User authentication required', undefined, requestId);
|
throw new BusinessRuleError('User authentication required', undefined, requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { idNot, authToken } = req.idNotUser;
|
const { idNot, authToken } = req.idNotUser;
|
||||||
|
|
||||||
// Call pure controller method
|
// Call pure controller method
|
||||||
const result = await IdNotController.getCurrentUser(idNot, authToken);
|
const result = await IdNotController.getCurrentUser(idNot, authToken);
|
||||||
|
|
||||||
res.json(result);
|
res.json(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -101,16 +103,16 @@ export class IdNotHandlers {
|
|||||||
*/
|
*/
|
||||||
static logout = asyncHandler(async (req: Request, res: Response): Promise<void> => {
|
static logout = asyncHandler(async (req: Request, res: Response): Promise<void> => {
|
||||||
const requestId = req.headers['x-request-id'] as string;
|
const requestId = req.headers['x-request-id'] as string;
|
||||||
|
|
||||||
if (!req.idNotUser) {
|
if (!req.idNotUser) {
|
||||||
throw new BusinessRuleError('User authentication required', undefined, requestId);
|
throw new BusinessRuleError('User authentication required', undefined, requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { authToken } = req.idNotUser;
|
const { authToken } = req.idNotUser;
|
||||||
|
|
||||||
// Call pure controller method
|
// Call pure controller method
|
||||||
const result = await IdNotController.logout(authToken);
|
const result = await IdNotController.logout(authToken);
|
||||||
|
|
||||||
res.json(result);
|
res.json(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -120,16 +122,16 @@ export class IdNotHandlers {
|
|||||||
*/
|
*/
|
||||||
static validateToken = asyncHandler(async (req: Request, res: Response): Promise<void> => {
|
static validateToken = asyncHandler(async (req: Request, res: Response): Promise<void> => {
|
||||||
const requestId = req.headers['x-request-id'] as string;
|
const requestId = req.headers['x-request-id'] as string;
|
||||||
|
|
||||||
if (!req.idNotUser) {
|
if (!req.idNotUser) {
|
||||||
throw new BusinessRuleError('User authentication required', undefined, requestId);
|
throw new BusinessRuleError('User authentication required', undefined, requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { idNot } = req.idNotUser;
|
const { idNot } = req.idNotUser;
|
||||||
|
|
||||||
// Call pure controller method
|
// Call pure controller method
|
||||||
const result = await IdNotController.validateToken(idNot);
|
const result = await IdNotController.validateToken(idNot);
|
||||||
|
|
||||||
res.json(result);
|
res.json(result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ const router = Router();
|
|||||||
|
|
||||||
router.get('/user/rattachements', IdNotHandlers.getUserRattachements);
|
router.get('/user/rattachements', IdNotHandlers.getUserRattachements);
|
||||||
router.get('/office/rattachements', IdNotHandlers.getOfficeRattachements);
|
router.get('/office/rattachements', IdNotHandlers.getOfficeRattachements);
|
||||||
router.post('/auth/:code', IdNotHandlers.authenticate);
|
router.post('/auth', IdNotHandlers.authenticate);
|
||||||
|
|
||||||
router.get('/user', authenticateIdNot, IdNotHandlers.getCurrentUser);
|
router.get('/user', authenticateIdNot, IdNotHandlers.getCurrentUser);
|
||||||
router.post('/logout', authenticateIdNot, IdNotHandlers.logout);
|
router.post('/logout', authenticateIdNot, IdNotHandlers.logout);
|
||||||
|
@ -14,3 +14,7 @@ Axes de tests pour `lecoffre-back-mini` (sans exemples d’implémentation).
|
|||||||
### Sécurité
|
### Sécurité
|
||||||
- **Entrées**: validation, schémas, erreurs typées
|
- **Entrées**: validation, schémas, erreurs typées
|
||||||
- **Secrets**: vérification de la non-exposition via réponses API
|
- **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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user