diff --git a/mon-aide-cyber-api/src/api/gestionnaires/erreurs.ts b/mon-aide-cyber-api/src/api/gestionnaires/erreurs.ts index 85b40535e..94ec73bec 100644 --- a/mon-aide-cyber-api/src/api/gestionnaires/erreurs.ts +++ b/mon-aide-cyber-api/src/api/gestionnaires/erreurs.ts @@ -11,11 +11,13 @@ import { ErreurEnvoiEmail } from '../messagerie/Messagerie'; import { ErreurModificationPreferences } from '../aidant/routesAPIAidantPreferences'; import { ErreurModificationProfil } from '../aidant/routesAPIProfil'; import { ErreurCreationEspaceAidant } from '../../espace-aidant/Aidant'; +import { ErreurReinitialisationMotDePasse } from '../../authentification/ServiceUtilisateur'; const HTTP_MAUVAISE_REQUETE = 400; const HTTP_NON_AUTORISE = 401; const HTTP_ACCES_REFUSE = 403; const HTTP_NON_TROUVE = 404; +const HTTP_EXPIRE = 419; const HTTP_NON_TRAITABLE = 422; const HTTP_ERREUR_SERVEUR = 500; @@ -150,6 +152,20 @@ const erreursGerees: Map< }); }, ], + [ + 'ErreurReinitialisationMotDePasse', + ( + erreur: ErreurMAC, + _requete, + _consignateur, + reponse + ) => { + construisReponse(reponse, HTTP_EXPIRE, { + ...constructeurActionsHATEOAS().actionsPubliques().construis(), + message: erreur.message, + }); + }, + ], ]); export const gestionnaireErreurGeneralisee = ( diff --git a/mon-aide-cyber-api/src/api/routesAPIUtilisateur.ts b/mon-aide-cyber-api/src/api/routesAPIUtilisateur.ts index 882dfa172..767d3d2fb 100644 --- a/mon-aide-cyber-api/src/api/routesAPIUtilisateur.ts +++ b/mon-aide-cyber-api/src/api/routesAPIUtilisateur.ts @@ -24,6 +24,10 @@ type CorpsRequeteReinitialiserMotDePasse = core.ParamsDictionary & { confirmationMotDePasse: string; }; +export type CorpsReponseReinitialiserMotDePasseEnErreur = ReponseHATEOAS & { + message: string; +}; + type CorpsRequeteReinitialisationMotDePasse = core.ParamsDictionary & { email: string; }; @@ -116,7 +120,7 @@ export const routesAPIUtilisateur = (configuration: ConfigurationServeur) => { async ( requete: Request, reponse: Response, - _suite: NextFunction + suite: NextFunction ) => { const resultatsValidation: Result = validationResult(requete) as Result; @@ -138,7 +142,8 @@ export const routesAPIUtilisateur = (configuration: ConfigurationServeur) => { serviceDeChiffrement.dechiffre(atob(corpsRequete.token)) ), }) - .then(() => reponse.status(204).send()); + .then(() => reponse.status(204).send()) + .catch((erreur) => suite(erreur)); } ); diff --git a/mon-aide-cyber-api/test/api/routesAPIUtilisateur.spec.ts b/mon-aide-cyber-api/test/api/routesAPIUtilisateur.spec.ts index b19d81b4b..08baadbde 100644 --- a/mon-aide-cyber-api/test/api/routesAPIUtilisateur.spec.ts +++ b/mon-aide-cyber-api/test/api/routesAPIUtilisateur.spec.ts @@ -6,10 +6,14 @@ import { AdaptateurDeVerificationDeSessionAvecContexteDeTest } from '../adaptate import { AdaptateurDeVerificationDeSessionDeTest } from '../adaptateurs/AdaptateurDeVerificationDeSessionDeTest'; import { unUtilisateur } from '../constructeurs/constructeursAidantUtilisateur'; -import { ReponseReinitialisationMotDePasseEnErreur } from '../../src/api/routesAPIUtilisateur'; +import { + CorpsReponseReinitialiserMotDePasseEnErreur, + ReponseReinitialisationMotDePasseEnErreur, +} from '../../src/api/routesAPIUtilisateur'; import crypto from 'crypto'; import { FournisseurHorloge } from '../../src/infrastructure/horloge/FournisseurHorloge'; import { FournisseurHorlogeDeTest } from '../infrastructure/horloge/FournisseurHorlogeDeTest'; +import { add } from 'date-fns'; describe('le serveur MAC sur les routes /api/utilisateur', () => { const testeurMAC = testeurIntegration(); @@ -208,6 +212,61 @@ describe('le serveur MAC sur les routes /api/utilisateur', () => { ).toStrictEqual('n0uv3eaU-M0D3passe'); }); + it('Retourne une erreur', async () => { + FournisseurHorlogeDeTest.initialise(new Date()); + const utilisateur = unUtilisateur() + .avecUnMotDePasse('original') + .construis(); + await testeurMAC.entrepots.utilisateurs().persiste(utilisateur); + const token = btoa( + JSON.stringify({ + identifiant: utilisateur.identifiant, + date: FournisseurHorloge.maintenant(), + sommeDeControle: crypto + .createHash('sha256') + .update(utilisateur.motDePasse) + .digest('base64'), + }) + ); + + FournisseurHorlogeDeTest.initialise( + add(FournisseurHorloge.maintenant(), { minutes: 25 }) + ); + const reponse = await executeRequete( + donneesServeur.app, + 'PATCH', + `/api/utilisateur/reinitialiser-mot-de-passe`, + donneesServeur.portEcoute, + { + motDePasse: 'n0uv3eaU-M0D3passe', + confirmationMotDePasse: 'n0uv3eaU-M0D3passe', + token, + } + ); + + expect(reponse.statusCode).toBe(419); + expect( + await reponse.json() + ).toStrictEqual({ + message: + 'Le lien de réinitialisation du mot de passe n’est plus valide.', + liens: { + 'demande-devenir-aidant': { + methode: 'GET', + url: '/api/demandes/devenir-aidant', + }, + 'demande-etre-aide': { + methode: 'GET', + url: '/api/demandes/etre-aide', + }, + 'se-connecter': { + methode: 'POST', + url: '/api/token', + }, + }, + }); + }); + describe('Lors de la phase de validation', () => { it('Valide le mot de passe', async () => { const utilisateur = unUtilisateur()