Ajoute le plugin Acrobat Pro d'imposition (acrobat-plugin/)

Suite d'imposition professionnelle en Folder-Level Scripts JS (7 modules +
verification de licence Vision), avec un plugin natif hybride optionnel
(WinINet + Registre) pour deplacer la verification de licence en code
compile. Installeur install.bat sur le meme modele que celui du projet
desktop (git portable, detection automatique des dossiers Acrobat).
This commit is contained in:
Jules
2026-06-21 22:16:24 +02:00
parent 202834a794
commit de76c1776c
14 changed files with 2856 additions and 0 deletions

View File

@@ -0,0 +1,225 @@
// LicenceVerifier.cpp
// ---------------------------------------------------------------------------
// Voir LicenceVerifier.h pour le contexte general.
//
// Le parsing JSON est volontairement minimal (recherche de sous-chaines) car
// le SDK Acrobat ne fournit pas de bibliotheque JSON et on souhaite eviter
// toute dependance externe pour un plugin aussi cible. Le format attendu de
// license.php est celui deja documente pour le projet "impose" :
// { "active": true/false, "offline_timeout_hours": 24, ... }
// Si le serveur utilise plutot un champ "valid" au lieu de "active", les
// deux sont acceptes. A AJUSTER si le format reel differe (voir TestConsole
// pour verifier la reponse brute sans avoir a passer par Acrobat).
// ---------------------------------------------------------------------------
#include "LicenceVerifier.h"
#include <windows.h>
#include <wininet.h>
#include <shlwapi.h>
#include <ctime>
#include <cstdio>
#pragma comment(lib, "Wininet.lib")
#pragma comment(lib, "Advapi32.lib")
#pragma comment(lib, "Shlwapi.lib")
namespace CDImpLicence {
static const wchar_t* CLE_REGISTRE = L"Software\\Copydev\\ImposingAcrobat";
// -------------------------------------------------------------------
// Utilitaires de parsing minimal (pas de dependance JSON externe)
// -------------------------------------------------------------------
static bool ContientChampBooleenVrai(const std::string& json, const char* champ) {
std::string motif = std::string("\"") + champ + "\"";
size_t pos = json.find(motif);
if (pos == std::string::npos) {
return false;
}
pos = json.find(':', pos);
if (pos == std::string::npos) {
return false;
}
// Ignore les espaces apres ':'
pos++;
while (pos < json.size() && isspace((unsigned char)json[pos])) {
pos++;
}
return json.compare(pos, 4, "true") == 0;
}
static int LireChampEntier(const std::string& json, const char* champ, int defaut) {
std::string motif = std::string("\"") + champ + "\"";
size_t pos = json.find(motif);
if (pos == std::string::npos) {
return defaut;
}
pos = json.find(':', pos);
if (pos == std::string::npos) {
return defaut;
}
pos++;
while (pos < json.size() && isspace((unsigned char)json[pos])) {
pos++;
}
int valeur = atoi(json.c_str() + pos);
return (valeur > 0) ? valeur : defaut;
}
// -------------------------------------------------------------------
// Identifiants machine
// -------------------------------------------------------------------
std::wstring ObtenirHostname() {
wchar_t nom[256] = { 0 };
DWORD taille = 256;
if (GetComputerNameW(nom, &taille)) {
return std::wstring(nom);
}
return L"Inconnu";
}
std::wstring ObtenirMachineId() {
wchar_t nomVolume[MAX_PATH] = { 0 };
DWORD numeroSerie = 0;
// Volume serial number du lecteur systeme : stable pour une
// installation Windows donnee, suffisant pour le comptage
// d'appareils cote serveur (pas un UUID materiel, mais standard
// Win32 fiable, sans dependance WMI/COM).
wchar_t racineSysteme[4] = L"C:\\";
GetWindowsDirectoryW(nomVolume, MAX_PATH);
if (wcslen(nomVolume) >= 2) {
racineSysteme[0] = nomVolume[0];
}
GetVolumeInformationW(racineSysteme, nullptr, 0, &numeroSerie, nullptr, nullptr, nullptr, 0);
wchar_t buffer[64];
swprintf_s(buffer, 64, L"%08X-%s", numeroSerie, ObtenirHostname().c_str());
return std::wstring(buffer);
}
// -------------------------------------------------------------------
// Requete HTTP (WinINet)
// -------------------------------------------------------------------
static std::wstring EncoderURL(const std::wstring& valeur) {
wchar_t tampon[1024];
DWORD taille = 1024;
if (UrlEscapeW(valeur.c_str(), tampon, &taille, URL_ESCAPE_PERCENT)) {
return std::wstring(tampon);
}
return valeur;
}
ResultatVerification VerifierLicence(
const std::wstring& serveurUrl,
const std::wstring& cleLicence,
const std::wstring& machineId,
const std::wstring& hostname,
const std::wstring& produit
) {
ResultatVerification resultat;
std::wstring url = serveurUrl
+ L"?key=" + EncoderURL(cleLicence)
+ L"&machine_id=" + EncoderURL(machineId)
+ L"&hostname=" + EncoderURL(hostname)
+ L"&product=" + EncoderURL(produit);
HINTERNET hInternet = InternetOpenW(L"CopydevImposingAcrobat/1.0",
INTERNET_OPEN_TYPE_PRECONFIG, nullptr, nullptr, 0);
if (!hInternet) {
resultat.erreur = "InternetOpenW a echoue";
return resultat;
}
// Timeout raisonnable : ne pas bloquer le demarrage d'Acrobat
// indefiniment si le serveur ne repond pas.
DWORD timeoutMs = 5000;
InternetSetOptionW(hInternet, INTERNET_OPTION_CONNECT_TIMEOUT, &timeoutMs, sizeof(timeoutMs));
InternetSetOptionW(hInternet, INTERNET_OPTION_RECEIVE_TIMEOUT, &timeoutMs, sizeof(timeoutMs));
HINTERNET hUrl = InternetOpenUrlW(hInternet, url.c_str(), nullptr, 0,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_SECURE, 0);
if (!hUrl) {
resultat.erreur = "InternetOpenUrlW a echoue (reseau indisponible ou serveur inaccessible)";
InternetCloseHandle(hInternet);
return resultat;
}
char tampon[2048];
DWORD octetsLus = 0;
std::string corps;
while (InternetReadFile(hUrl, tampon, sizeof(tampon) - 1, &octetsLus) && octetsLus > 0) {
tampon[octetsLus] = '\0';
corps += tampon;
}
InternetCloseHandle(hUrl);
InternetCloseHandle(hInternet);
if (corps.empty()) {
resultat.erreur = "Reponse vide du serveur de licence";
return resultat;
}
resultat.succesReseau = true;
resultat.reponseBrute = corps;
resultat.valide = ContientChampBooleenVrai(corps, "active") || ContientChampBooleenVrai(corps, "valid");
resultat.offlineTimeoutHeures = LireChampEntier(corps, "offline_timeout_hours", 24);
return resultat;
}
// -------------------------------------------------------------------
// Registre Windows
// -------------------------------------------------------------------
void EcrireVerdictRegistre(bool valide, int dureeToleranceHeures) {
HKEY hCle;
if (RegCreateKeyExW(HKEY_CURRENT_USER, CLE_REGISTRE, 0, nullptr,
REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &hCle, nullptr) != ERROR_SUCCESS) {
return;
}
long long expiration = (long long)time(nullptr) + (long long)dureeToleranceHeures * 3600LL;
wchar_t valeurOK[2];
swprintf_s(valeurOK, 2, L"%d", valide ? 1 : 0);
wchar_t valeurExpiration[32];
swprintf_s(valeurExpiration, 32, L"%lld", expiration);
RegSetValueExW(hCle, L"LicenceOK", 0, REG_SZ,
(const BYTE*)valeurOK, (DWORD)((wcslen(valeurOK) + 1) * sizeof(wchar_t)));
RegSetValueExW(hCle, L"LicenceValideJusqua", 0, REG_SZ,
(const BYTE*)valeurExpiration, (DWORD)((wcslen(valeurExpiration) + 1) * sizeof(wchar_t)));
RegCloseKey(hCle);
}
bool LireVerdictRegistre(bool& valideOut, long long& expirationUnixOut) {
HKEY hCle;
if (RegOpenKeyExW(HKEY_CURRENT_USER, CLE_REGISTRE, 0, KEY_READ, &hCle) != ERROR_SUCCESS) {
return false;
}
wchar_t valeurOK[16] = { 0 };
DWORD tailleOK = sizeof(valeurOK);
wchar_t valeurExpiration[32] = { 0 };
DWORD tailleExpiration = sizeof(valeurExpiration);
bool ok1 = RegQueryValueExW(hCle, L"LicenceOK", nullptr, nullptr,
(LPBYTE)valeurOK, &tailleOK) == ERROR_SUCCESS;
bool ok2 = RegQueryValueExW(hCle, L"LicenceValideJusqua", nullptr, nullptr,
(LPBYTE)valeurExpiration, &tailleExpiration) == ERROR_SUCCESS;
RegCloseKey(hCle);
if (!ok1 || !ok2) {
return false;
}
valideOut = (_wtoi(valeurOK) == 1);
expirationUnixOut = _wtoi64(valeurExpiration);
return true;
}
} // namespace CDImpLicence