From d5234e1390a0c5c06e17c389473d7d86dc8af7eb Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Thu, 17 Sep 2026 05:36:28 +0100 Subject: [PATCH] fix(licence): refus de la 2e couche indiscernable d'une route inconnue Le 404 a corps vide etait remplace par la page HTML d'Indy, distincte du 404 JSON d'une route inexistante : on pouvait lister les routes reelles. La 2e couche renvoie maintenant exactement le meme JSON. Ajoute un exe d'essai qui saute l'ecran d'activation, pour eprouver la 2e couche depuis l'application. Define de compilation LICENCE_TEST_SKIP_SCREEN, jamais un reglage : un interrupteur dans config.txt ferait sauter la 1re couche sans rapiecage. Build dedie, .dcu a part ; verifie que seul l'exe d'essai porte le define. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 18 ++++++++++++++++++ delphi-backend/Source/PM.Router.pas | 13 ++++++++----- delphi-backend/UMainForm.pas | 9 +++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 8b0264d..0c217e1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -476,6 +476,24 @@ l'ecran ne donne plus acces aux donnees. atteignent ce point ; les fichiers de l'ecran d'activation passent par `TryServeEmbedded`, non garde — sinon l'ecran qui permet de s'activer ne se chargerait plus. **404**, pas 403, comme le reste du verrouillage. +- **Le refus est le MEME 404 qu'une route inexistante** (`TJSONHelper.SendError(404, + 'Not found')`). Un corps vide ne suffisait pas : Indy le remplace par sa page + HTML, distincte du JSON d'une route inconnue — ce qui revelait les routes + existantes (vu a l'essai F de LICENCE-TESTS.md). +- **Exe d'essai qui saute l'ecran** : define `LICENCE_TEST_SKIP_SCREEN`, qui fait + repondre `licence/status` ok. **A la compilation et jamais par un reglage** — + un interrupteur dans `config.txt`, que n'importe qui cree a cote de l'exe, + ferait sauter la 1re couche sans rapiecage. Build dedie, dossiers exe ET + `.dcu` a part (des unites compilees avec ce define ne doivent jamais etre + liees dans un exe normal) ; `;` des defines echappe en `%3B` pour MSBuild : + ``` + msbuild PMServer.dproj /p:Config=Release /p:Platform=Win32 + "/p:DCC_Define=RELEASE%3BLICENCE_TEST_SKIP_SCREEN" + "/p:DCC_ExeOutput=E:\password manager\Win32-TEST-licence" + "/p:DCC_DcuOutput=E:\password manager\dcu\Win32-TEST-licence" + ``` + Verifier apres build : la chaine `LICENCE TEST BUILD` (UTF-16) ne doit + exister que dans l'exe d'essai. - Un **oui** est retenu pour le processus (le test est sur le chemin de chaque requete) ; un **non** jamais, pour qu'une activation faite juste avant soit vue a la requete suivante. diff --git a/delphi-backend/Source/PM.Router.pas b/delphi-backend/Source/PM.Router.pas index 86c8b20..a105832 100644 --- a/delphi-backend/Source/PM.Router.pas +++ b/delphi-backend/Source/PM.Router.pas @@ -45,7 +45,7 @@ var implementation uses - PM.LicenceGate; + PM.LicenceGate, PM.JSON; constructor TPMRouter.Create; begin @@ -92,12 +92,15 @@ begin // DEUXIEME COUCHE DE LICENCE : ici, et seulement ici. Seules les routes // de l'API arrivent a cette ligne — les fichiers de l'ecran d'activation // passent par TryServeEmbedded, qui n'est pas garde, sinon l'ecran qui - // permet de s'activer ne pourrait plus se charger. 404 et non 403, comme - // le reste du verrouillage : ne pas dire ce qui manque. + // permet de s'activer ne pourrait plus se charger. + // + // LE MEME 404 QU'UNE ROUTE INEXISTANTE, AU CARACTERE PRES. Un corps vide + // ne suffisait pas : Indy le remplace par sa propre page, qui se + // distinguait du JSON d'une route inconnue — et revelait donc quelles + // routes existent. Refuser doit etre indiscernable de ne rien avoir. if not ApiLicenceOk then begin - AResponse.ResponseNo := 404; - AResponse.ContentText := ''; + TJSONHelper.SendError(AResponse, 404, 'Not found'); Exit(True); end; SetLength(LParams, LMatch.Groups.Count - 1); diff --git a/delphi-backend/UMainForm.pas b/delphi-backend/UMainForm.pas index 484cbb8..73d3f25 100644 --- a/delphi-backend/UMainForm.pas +++ b/delphi-backend/UMainForm.pas @@ -1362,6 +1362,15 @@ begin begin LLicOk := PM.Licence.IsLicensed; LLicInfo := PM.Licence.LicenceInfo; + {$IFDEF LICENCE_TEST_SKIP_SCREEN} + // EXE D'ESSAI UNIQUEMENT : simule une 1re couche rapiecee, pour eprouver + // la 2e depuis l'application elle-meme. A la COMPILATION et jamais par un + // reglage — un interrupteur dans config.txt, que n'importe qui peut + // creer a cote de l'exe, ferait sauter la 1re couche sans rapiecage. + // La 2e couche, elle, verifie toujours la vraie licence : c'est l'essai. + LLicOk := True; + LogLine('LICENCE TEST BUILD: ecran d''activation saute (1re couche simulee rapiecee)'); + {$ENDIF} end; // Le nom, le courriel et la date viennent d'une charge utile QUE NOUS AVONS // SIGNEE, mais ils sont interpoles dans du JavaScript : on les echappe