diff --git a/CLAUDE.md b/CLAUDE.md index 3e1ae02..708a83b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -353,6 +353,19 @@ sur une licence acceptee — pas de bouton « plus tard ». qui essaie d'en fabriquer une. Le journal note le verdict, **jamais la cle**. - Hors du navigateur hote (`Bridge.active` faux : dev en navigateur, harnais de test) il n'y a pas de licence a verifier — la porte est ouverte. +- **Settings → Licence** affiche porteur, courriel, date d'emission et + Installation ID. Rempli par `applyLicenceInfo(st)` **une fois au demarrage** + (les deux chemins : deja licencie, et activation reussie) plutot que branche + sur le rendu des reglages — rien n'y change pendant une session, et le panneau + est deja dans le DOM, cache. Section masquee hors navigateur hote : une suite + de tirets ferait croire a une activation perdue. +- Les champs sont **echappes avant interpolation** dans `ExecuteJavaScript`, + bien qu'ils viennent d'une charge utile signee : signee ne veut pas dire + inoffensive, c'est l'editeur qui les a tapes au moment d'emettre. +- Piege Delphi rencontre : **une routine imbriquee ne se declare pas au milieu + d'un corps de procedure** (seulement dans la section de declaration). En + glisser une casse l'inference des methodes anonymes de tout ce qui suit — + cinq `TThread.Queue` sans rapport se sont mis a ne plus compiler. **ORDRE OBLIGATOIRE.** Tant que `LicencePublicKeyBlob` est a zero, aucune licence n'est valide et l'ecran d'activation est **infranchissable** — l'exe diff --git a/delphi-backend/UMainForm.pas b/delphi-backend/UMainForm.pas index cdbc790..1564991 100644 --- a/delphi-backend/UMainForm.pas +++ b/delphi-backend/UMainForm.pas @@ -1352,14 +1352,27 @@ begin LLicOk := PM.Licence.IsLicensed; LLicInfo := PM.Licence.LicenceInfo; end; - var LHolder := LLicInfo.Holder; - if LHolder = '' then LHolder := LLicInfo.Email; - LHolder := StringReplace(LHolder, '\', '\\', [rfReplaceAll]); - LHolder := StringReplace(LHolder, '"', '\"', [rfReplaceAll]); + // 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 + // comme n'importe quelle chaine etrangere. Signee ne veut pas dire + // inoffensive — c'est nous qui les avons tapes au moment d'emettre. + var LFields := TArray.Create( + LLicInfo.Holder, LLicInfo.Email, LLicInfo.IssuedOn); + for var LI := 0 to High(LFields) do + begin + LFields[LI] := StringReplace(LFields[LI], '\', '\\', [rfReplaceAll]); + LFields[LI] := StringReplace(LFields[LI], '"', '\"', [rfReplaceAll]); + LFields[LI] := StringReplace(LFields[LI], #13, '\r', [rfReplaceAll]); + LFields[LI] := StringReplace(LFields[LI], #10, '\n', [rfReplaceAll]); + end; + WebBrowser.ExecuteJavaScript( 'if(window.Bridge&&Bridge.onLicenceResult)' + 'Bridge.onLicenceResult(' + BoolToStr(LLicOk, True).ToLower + - ',"' + LHolder + '","' + PM.Licence.ThisMachineId + '")'); + ',"' + LFields[0] + + '","' + PM.Licence.ThisMachineId + + '","' + LFields[1] + + '","' + LFields[2] + '")'); end // ---- Start with Windows (HKCU Run registry) -------------------------- diff --git a/index.html b/index.html index eaa4bc5..7796213 100644 --- a/index.html +++ b/index.html @@ -990,6 +990,26 @@ + +
+
Licence
+
+ Licensed to + — +
+
+ Email + — +
+
+ Issued + — +
+
+ Installation ID + — +
+
diff --git a/js/app.js b/js/app.js index 2734ef4..c3a8f52 100644 --- a/js/app.js +++ b/js/app.js @@ -315,11 +315,17 @@ const Bridge = (() => { }, 3000); }); }, - onLicenceResult(ok, holder, machine) { + onLicenceResult(ok, holder, machine, email, issued) { const r = licenceResolver; if (!r) return; licenceResolver = null; - r({ ok: !!ok, holder: holder || '', machine: machine || '' }); + r({ + ok: !!ok, + holder: holder || '', + machine: machine || '', + email: email || '', + issued: issued || '', + }); }, onPrefResult(key, value) { const r = prefResolvers[key]; @@ -6939,14 +6945,29 @@ function resetAutoLock() { // La porte d'entrée : sans licence valable, rien d'autre ne se peint. // Ne rend la main QUE sur une licence acceptée — il n'y a pas de bouton // "plus tard", c'est tout l'objet de l'écran. +// Les quatre lignes de Settings → Licence. Rien ici ne change pendant une +// session, donc c'est ecrit une fois au demarrage plutot que branche sur le +// rendu des reglages : le panneau existe deja dans le DOM, cache. +function applyLicenceInfo(st) { + const section = $('#settingLicenceSection'); + if (!section) return; + // Hors du navigateur hote il n'y a pas de licence — montrer une section + // vide de tirets ferait croire a une activation perdue. + if (!Bridge.active) { section.style.display = 'none'; return; } + $('#settingLicenceHolder').textContent = st.holder || '—'; + $('#settingLicenceEmail').textContent = st.email || '—'; + $('#settingLicenceIssued').textContent = st.issued || '—'; + $('#settingLicenceMachine').textContent = st.machine || '—'; +} + async function ensureLicence() { let st = await Bridge.licence('status'); - if (st.ok) return; + if (st.ok) { applyLicenceInfo(st); return; } // Un démarrage à froid lent peut manquer la fenêtre de réponse, et le // silence se lit alors comme un refus : redemander une fois coûte moins // qu'un écran d'activation présenté à quelqu'un qui a déjà payé. st = await Bridge.licence('status'); - if (st.ok) return; + if (st.ok) { applyLicenceInfo(st); return; } const screen = $('#licenceScreen'); const hint = $('#licenceHint'); @@ -6975,6 +6996,7 @@ async function ensureLicence() { input.select(); return; } + applyLicenceInfo(res); screen.classList.add('is-hidden'); resolve(); });