Files
copydev-imposing-tool/acrobat-plugin/src/Imposition-00b-Licence.js
Jules Dubois e9eca79abd licence: bypass temporaire pour tester les modules
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>
2026-06-24 00:29:17 +02:00

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) {}