Files
copydev-imposing-tool/acrobat-plugin/native/LicenceVerifier.cpp
Jules de76c1776c 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).
2026-06-21 22:16:24 +02:00

226 lines
8.4 KiB
C++
Executable File

// 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