Net.HTTP.request() ne fonctionne pas dans Acrobat 2026. verifierEtBloquerSiInvalide() retourne true directement le temps de valider les modules d'imposition. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
329 lines
13 KiB
JavaScript
Executable File
329 lines
13 KiB
JavaScript
Executable File
// Imposition-00b-Licence.js
|
|
// ---------------------------------------------------------------------------
|
|
// Suite d'imposition professionnelle - Folder-Level Script pour Adobe Acrobat Pro
|
|
// Module 0b : Verification de licence (serveur Vision)
|
|
//
|
|
// Depend de Imposition-00-Core.js (doit etre charge avant). Doit etre charge
|
|
// AVANT Imposition-01-UI.js (le prefixe "00b" garantit cet ordre).
|
|
//
|
|
// Reutilise le serveur de licence Vision deja en place pour le projet
|
|
// "Copydev Imposing Tool" (impose) : meme API license.php, meme logique de
|
|
// cache hors-ligne avec duree de tolerance, meme principe de plafond
|
|
// d'appareils (max_devices) gere cote serveur. Seul le champ "product"
|
|
// change pour distinguer ce plugin Acrobat des autres produits Copydev.
|
|
//
|
|
// AVERTISSEMENTS TECHNIQUES - a tester dans Acrobat Pro reel :
|
|
// - Net.HTTP.request() est l'API documentee pour les requetes HTTP depuis
|
|
// un script Acrobat privilegie, mais sa disponibilite depend des
|
|
// reglages de securite reseau d'Acrobat (Preferences > Securite
|
|
// (avancee) > Gestionnaire de confiance > acces internet pour les
|
|
// scripts non-PDF). A activer/whitelister si necessaire.
|
|
// - La lecture du flux de reponse (Stream.read()) est implementee selon le
|
|
// schema le plus communement documente, mais n'a pas pu etre executee
|
|
// dans cet environnement de developpement (pas d'Acrobat installe) :
|
|
// ajuster _lireFluxReponse() si le parsing JSON echoue en conditions
|
|
// reelles.
|
|
// - L'identifiant machine (machine_id) repose sur ActiveXObject (COM),
|
|
// disponible uniquement sous Windows pour des scripts de dossier
|
|
// (folder-level) de confiance. En cas d'indisponibilite, on retombe sur
|
|
// un identifiant genere une fois et persiste localement (moins robuste
|
|
// contre la copie de licence, mais fonctionnel).
|
|
// ---------------------------------------------------------------------------
|
|
|
|
if (typeof CDImp === "undefined") {
|
|
throw new Error("Imposition-00b-Licence.js : CDImp.Core doit etre charge avant ce fichier.");
|
|
}
|
|
|
|
CDImp.Licence = CDImp.Licence || {};
|
|
|
|
CDImp.Licence.CONFIG = {
|
|
serveurUrl: "https://vision.copydev.fr/api/license.php",
|
|
produit: "imposing-acrobat",
|
|
dureeCacheHeuresParDefaut: 24 // utilisee si le serveur ne renvoie pas offline_timeout_hours
|
|
};
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Identifiants machine
|
|
// -----------------------------------------------------------------------
|
|
/**
|
|
* Nom de la machine, via WSH (Windows uniquement, scripts de dossier
|
|
* privilegies). Retombe sur "Inconnu" si indisponible.
|
|
*/
|
|
CDImp.Licence._obtenirHostname = function () {
|
|
try {
|
|
var reseau = new ActiveXObject("WScript.Network");
|
|
return String(reseau.ComputerName);
|
|
} catch (e) {
|
|
return "Inconnu";
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Identifiant machine stable, persiste dans les preferences globales
|
|
* d'Acrobat (genere une seule fois). Pas un identifiant materiel (UUID
|
|
* BIOS), mais suffisant pour le comptage d'appareils cote serveur.
|
|
*/
|
|
CDImp.Licence._obtenirMachineId = function () {
|
|
if (typeof global.cdImpMachineId !== "undefined" && global.cdImpMachineId) {
|
|
return global.cdImpMachineId;
|
|
}
|
|
var id = "";
|
|
for (var i = 0; i < 32; i++) {
|
|
id += Math.floor(Math.random() * 16).toString(16);
|
|
}
|
|
CDImp.Util.avecPrivileges(function () {
|
|
global.cdImpMachineId = id;
|
|
global.setPersistent("cdImpMachineId", true);
|
|
});
|
|
return id;
|
|
};
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Requete HTTP synchrone vers le serveur de licence
|
|
// -----------------------------------------------------------------------
|
|
/**
|
|
* Convertit le flux de reponse Net.HTTP en chaine de caracteres.
|
|
*/
|
|
CDImp.Licence._lireFluxReponse = function (msgStream) {
|
|
try {
|
|
var nTaille = msgStream.length;
|
|
var aOctets = msgStream.read(nTaille);
|
|
var texte = "";
|
|
for (var i = 0; i < aOctets.length; i++) {
|
|
texte += String.fromCharCode(aOctets[i]);
|
|
}
|
|
return texte;
|
|
} catch (e) {
|
|
return "";
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Effectue une requete GET synchrone et retourne { erreur, texte }.
|
|
*/
|
|
CDImp.Licence._requeteHTTPSync = function (url) {
|
|
var resultat = { erreur: null, texte: null };
|
|
try {
|
|
Net.HTTP.request({
|
|
cVerb: "GET",
|
|
cURL: url,
|
|
oHandler: {
|
|
response: function (msgStream, status) {
|
|
if (status && status >= 400) {
|
|
resultat.erreur = "HTTP " + status;
|
|
} else {
|
|
resultat.texte = CDImp.Licence._lireFluxReponse(msgStream);
|
|
}
|
|
},
|
|
error: function (msg, err) {
|
|
resultat.erreur = (err || msg || "Erreur reseau inconnue").toString();
|
|
}
|
|
},
|
|
bAsync: false
|
|
});
|
|
} catch (e) {
|
|
resultat.erreur = e.toString();
|
|
}
|
|
return resultat;
|
|
};
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Saisie / stockage de la cle de licence
|
|
// -----------------------------------------------------------------------
|
|
CDImp.Licence._demanderCle = function () {
|
|
var cle = app.response({
|
|
cQuestion: "Cle de licence Copydev Imposing (Acrobat) :",
|
|
cTitle: "Activation de la licence",
|
|
cDefault: ""
|
|
});
|
|
return (cle && cle.length > 0) ? cle : null;
|
|
};
|
|
|
|
/**
|
|
* Recopie la cle dans le Registre Windows (HKCU\Software\Copydev\
|
|
* ImposingAcrobat\CleLicence), seul emplacement que le plugin natif
|
|
* (voir /native/PluginMain.cpp) sait lire : global.setPersistent() stocke
|
|
* la valeur dans le mecanisme de preferences interne d'Acrobat, pas dans
|
|
* le Registre, donc cette ecriture explicite est necessaire pour que le
|
|
* plugin natif et le JS partagent la meme cle. Echec silencieux si
|
|
* ActiveXObject est indisponible (plugin natif alors simplement inutilisable,
|
|
* le JS continue de fonctionner seul).
|
|
*/
|
|
CDImp.Licence._ecrireCleRegistre = function (cle) {
|
|
try {
|
|
var shell = new ActiveXObject("WScript.Shell");
|
|
shell.RegWrite("HKCU\\Software\\Copydev\\ImposingAcrobat\\CleLicence", cle, "REG_SZ");
|
|
} catch (e) {
|
|
// pas grave : le plugin natif (s'il est installe) ne pourra pas
|
|
// verifier la licence de son cote, le JS reste fonctionnel seul.
|
|
}
|
|
};
|
|
|
|
CDImp.Licence._obtenirCle = function () {
|
|
if (typeof global.cdImpLicenceCle !== "undefined" && global.cdImpLicenceCle) {
|
|
return global.cdImpLicenceCle;
|
|
}
|
|
var cle = CDImp.Licence._demanderCle();
|
|
if (!cle) {
|
|
return null;
|
|
}
|
|
CDImp.Util.avecPrivileges(function () {
|
|
global.cdImpLicenceCle = cle;
|
|
global.setPersistent("cdImpLicenceCle", true);
|
|
});
|
|
CDImp.Licence._ecrireCleRegistre(cle);
|
|
return cle;
|
|
};
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Verdict du plugin natif (voir /native/), lu en priorite s'il est present
|
|
// et frais. Permet de s'appuyer sur une verification effectuee en code
|
|
// compile (plus dur a lire/patcher qu'un .js) plutot que sur le seul check
|
|
// JS ci-dessous. Si le plugin natif n'est pas installe ou n'a pas encore
|
|
// ecrit de verdict, on retombe naturellement sur la verification JS pure
|
|
// (aucune regression).
|
|
// -----------------------------------------------------------------------
|
|
CDImp.Licence._lireVerdictNatif = function () {
|
|
try {
|
|
var shell = new ActiveXObject("WScript.Shell");
|
|
var ok = shell.RegRead("HKCU\\Software\\Copydev\\ImposingAcrobat\\LicenceOK");
|
|
var expirationStr = shell.RegRead("HKCU\\Software\\Copydev\\ImposingAcrobat\\LicenceValideJusqua");
|
|
var expiration = parseInt(expirationStr, 10);
|
|
var maintenant = Math.floor((new Date()).getTime() / 1000);
|
|
|
|
if (String(ok) === "1" && expiration > maintenant) {
|
|
return { valide: true, source: "plugin_natif" };
|
|
}
|
|
return { valide: false, source: "plugin_natif", raison: "Verdict du plugin natif absent ou expire." };
|
|
} catch (e) {
|
|
return null; // plugin natif non installe / registre absent : pas d'info
|
|
}
|
|
};
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Verification (serveur, avec repli sur cache hors-ligne)
|
|
// -----------------------------------------------------------------------
|
|
/**
|
|
* Verifie la licence auprès du serveur Vision. En cas d'echec reseau,
|
|
* retombe sur le dernier resultat valide mis en cache, dans la limite de la
|
|
* duree de tolerance hors-ligne (offline_timeout_hours renvoye par le
|
|
* serveur, ou valeur par defaut).
|
|
*
|
|
* @returns {Object} { valide, source: "serveur"|"cache", donnees, raison }
|
|
*/
|
|
CDImp.Licence.verifier = function () {
|
|
var verdictNatif = CDImp.Licence._lireVerdictNatif();
|
|
if (verdictNatif && verdictNatif.valide) {
|
|
return verdictNatif;
|
|
}
|
|
// Verdict natif absent, expire ou plugin non installe : on continue
|
|
// avec la verification JS habituelle (HTTP + cache hors-ligne).
|
|
|
|
var cle = CDImp.Licence._obtenirCle();
|
|
if (!cle) {
|
|
return { valide: false, raison: "Aucune cle de licence saisie." };
|
|
}
|
|
|
|
var machineId = CDImp.Licence._obtenirMachineId();
|
|
var hostname = CDImp.Licence._obtenirHostname();
|
|
var url = CDImp.Licence.CONFIG.serveurUrl
|
|
+ "?key=" + encodeURIComponent(cle)
|
|
+ "&machine_id=" + encodeURIComponent(machineId)
|
|
+ "&hostname=" + encodeURIComponent(hostname)
|
|
+ "&product=" + encodeURIComponent(CDImp.Licence.CONFIG.produit);
|
|
|
|
var reponse = CDImp.Licence._requeteHTTPSync(url);
|
|
|
|
if (reponse.erreur || !reponse.texte) {
|
|
return CDImp.Licence._verifierCache(reponse.erreur);
|
|
}
|
|
|
|
var data;
|
|
try {
|
|
data = JSON.parse(reponse.texte);
|
|
} catch (e) {
|
|
return CDImp.Licence._verifierCache("Reponse serveur illisible.");
|
|
}
|
|
|
|
var valide = !!(data.active || data.valid);
|
|
|
|
CDImp.Util.avecPrivileges(function () {
|
|
global.cdImpLicenceCache = { valide: valide, donnees: data, dateVerif: (new Date()).getTime() };
|
|
global.setPersistent("cdImpLicenceCache", true);
|
|
});
|
|
|
|
return { valide: valide, donnees: data, source: "serveur" };
|
|
};
|
|
|
|
CDImp.Licence._verifierCache = function (raisonReseau) {
|
|
var cache = global.cdImpLicenceCache;
|
|
if (!cache) {
|
|
return { valide: false, raison: "Serveur de licence inaccessible (" + (raisonReseau || "?") + ") et aucun cache local." };
|
|
}
|
|
var heuresEcoulees = ((new Date()).getTime() - cache.dateVerif) / 3600000;
|
|
var tolerance = (cache.donnees && cache.donnees.offline_timeout_hours) || CDImp.Licence.CONFIG.dureeCacheHeuresParDefaut;
|
|
|
|
if (cache.valide && heuresEcoulees <= tolerance) {
|
|
return { valide: true, donnees: cache.donnees, source: "cache", heuresEcoulees: heuresEcoulees };
|
|
}
|
|
return {
|
|
valide: false,
|
|
raison: "Serveur de licence inaccessible (" + (raisonReseau || "?") + ") et cache hors-ligne expire ou invalide\n(hors-ligne depuis ~" + Math.round(heuresEcoulees) + "h, tolerance " + tolerance + "h)."
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Verifie la licence et affiche une alerte bloquante si elle est invalide.
|
|
* A appeler avant toute action des modules d'imposition.
|
|
*
|
|
* @returns {Boolean} true si l'utilisation peut continuer
|
|
*/
|
|
CDImp.Licence.verifierEtBloquerSiInvalide = function () {
|
|
// TODO: reactiver la verification serveur une fois Net.HTTP.request
|
|
// valide dans Acrobat 2026. Bypass temporaire pour tester les modules.
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* Boite de dialogue simple permettant de saisir/remplacer la cle de licence
|
|
* et de relancer immediatement une verification.
|
|
*/
|
|
CDImp.Licence.gererCle = function () {
|
|
var cleActuelle = global.cdImpLicenceCle || "";
|
|
var nouvelleCle = app.response({
|
|
cQuestion: "Cle de licence Copydev Imposing (Acrobat) :",
|
|
cTitle: "Gerer la licence",
|
|
cDefault: cleActuelle
|
|
});
|
|
if (nouvelleCle === null || nouvelleCle === cleActuelle) {
|
|
return;
|
|
}
|
|
CDImp.Util.avecPrivileges(function () {
|
|
global.cdImpLicenceCle = nouvelleCle;
|
|
global.setPersistent("cdImpLicenceCle", true);
|
|
global.cdImpLicenceCache = null; // force une nouvelle verification serveur
|
|
global.setPersistent("cdImpLicenceCache", true);
|
|
});
|
|
CDImp.Licence._ecrireCleRegistre(nouvelleCle);
|
|
CDImp.Util.info("Cle enregistree. Redemarrez Acrobat pour que le plugin natif\n(s'il est installe) la prenne en compte au prochain demarrage.");
|
|
var resultat = CDImp.Licence.verifier();
|
|
if (resultat.valide) {
|
|
CDImp.Util.info("Licence valide. Source : " + resultat.source + ".");
|
|
} else {
|
|
CDImp.Util.erreur("Licence invalide : " + (resultat.raison || ""));
|
|
}
|
|
};
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Entree de menu "Gerer la licence..."
|
|
// -----------------------------------------------------------------------
|
|
try {
|
|
app.addMenuItem({
|
|
cName: "CDImpGererLicence",
|
|
cParent: "ImpositionPro",
|
|
cExec: "CDImp.Licence.gererCle();",
|
|
cEnable: "event.rc = (CDImp.Licence != undefined);",
|
|
nPos: 1
|
|
});
|
|
} catch (e) {}
|