feat(licence): Settings affiche le porteur de la licence
Porteur, courriel, date d'emission et Installation ID, lus dans la charge utile deja verifiee. Rempli une fois au demarrage sur les deux chemins (deja licencie, activation reussie) : rien n'y change pendant une session. Section masquee hors navigateur hote. Les champs sont echappes avant interpolation dans ExecuteJavaScript bien qu'ils viennent d'une charge utile signee — signee ne veut pas dire inoffensive. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<string>.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) --------------------------
|
||||
|
||||
+20
@@ -990,6 +990,26 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="slideover-field" id="settingLicenceSection">
|
||||
<div class="slideover-field-label">Licence</div>
|
||||
<div class="setting-row">
|
||||
<span>Licensed to</span>
|
||||
<strong id="settingLicenceHolder">—</strong>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span>Email</span>
|
||||
<span id="settingLicenceEmail" style="color:var(--text-dim)">—</span>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span>Issued</span>
|
||||
<span id="settingLicenceIssued" style="color:var(--text-dim)">—</span>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<span>Installation ID</span>
|
||||
<code id="settingLicenceMachine" style="font-family:ui-monospace,Consolas,monospace;user-select:all">—</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user