Aller au contenu
getnextpdf.com

Enterprise édition

Gestion des licences — Référence détaillée

Cette page est la référence détaillée de la surface de gestion des licences NextPDF Enterprise — le module qui résout toutes les autres capacités Enterprise. Elle couvre le modèle d’états de droits (EntitlementEvaluator, EntitlementStatus, EntitlementResult), le contrôle imposé des capacités (FeatureGate, CapabilityCode, CapabilityRegistry), la machine d’application de canal à deux minuteurs (ChannelEnforcementPolicy, OnlineCheckScheduler) et le client en ligne signé (LicenseClient). L’évaluation ordinaire des droits ne nécessite aucun réseau. Le client en ligne existe pour les opérations explicites d’activation, de heartbeat, de désactivation, de vérification en ligne et de sonde de renouvellement. Le détail des mécanismes internes reste dans la documentation interne du dépôt source et sort du périmètre de ce manuel.

Cette capacité est livrée dans NextPDF Enterprise (nextpdf/enterprise) et s’active avec une enveloppe de licence de niveau Enterprise. Un déploiement dépourvu de ce droit ne charge pas les classes de la capacité. Compare les éditions et obtiens une licence.

La gestion des licences est une surface Enterprise de base. Elle est toujours présente dès que le paquet Enterprise est installé aux côtés du paquet Core, car c’est la surface qui résout tout le reste. NextPDF Pro n’a pas de surface de droits distincte ; le modèle d’états, la machine d’application et le client en ligne sont livrés uniquement dans nextpdf/enterprise. NextPDF Core (Apache-2.0) n’a aucun modèle de droits — un hôte qui a besoin d’un comportement Apache-2.0 sans licence utilise directement le moteur Core, et non le pipeline Enterprise.

Tous les types résident sous NextPDF\Enterprise\Licensing. La machine d’application se trouve dans le sous-espace de noms Channel, la composition d’exécution dans Runtime et les types de statut signé dans Online.

SymboleParamètresComportement par défautRetourneLève ou échoue avecNotes
EntitlementEvaluator::evaluate()?LicenseKey $license, ?DateTimeImmutable $now = nullFait correspondre une licence vérifiée (ou null) à la décision de droits complèteEntitlementResultAucunUne licence null produit le résultat sans licence, à sécurité intégrée
EntitlementEvaluator::evaluateEnforced()?LicenseKey $license, EnforcementOutcome $outcomeConvertit un résultat d’application pré-calculé en résultat de droitsEntitlementResultAucunL’édition effective provient du résultat ; toute rétrogradation d’application aboutit à Core
EntitlementEvaluator::resolveBrandingMode(), ::resolveBrandingStrategy()?LicenseKey $license, ?DateTimeImmutable $now = nullRésout la décision de marquage pour la sortie généréeBrandingMode / BrandingStrategyAucunSeule autorité de marquage ; seul le canal d’évaluation appose un filigrane
EntitlementResultObjet-valeur en lecture seulePorte le statut, l’édition, le canal, le mode de marquage, les indicateurs d’exécution/mise à jour/support et un avertissement optionnelAucunAssistants : isFullyActive(), isExpired(), isDowngradedToCore(), shouldApplyEvaluationBranding()
EntitlementStatusÉnumération adossée à une chaîneActive, GracePeriod, DowngradedToCore, EvaluationExpired, NoLicenseAucunPerpetualFallback est conservé mais déprécié ; maintenu uniquement pour que les consommateurs antérieurs à 6.0 compilent encore
FeatureGate::hasCapability()CapabilityCode $capabilityVérifie la capacité face à l’édition effective imposée et à l’état des packsboolAucunÀ sécurité intégrée vers core en cas d’erreur du résolveur
FeatureGate::requireCapability()CapabilityCode $capabilityPasse en silence ou lève avec un contexte de montée en gamme structurévoidSpectrumAuthenticationException SPEC-LIC-001 (non licencié) ou SPEC-LIC-002 (pack expiré)Le contexte porte required_capability, required_pack, current_packs, upgrade_info_url
FeatureGate::isFeatureEnabled(), ::requireFeature()string $featureContrôle d’identifiant de fonctionnalité héritébool / voidSpectrumAuthenticationException SPEC-AUTH-007 (chemin require)Compatibilité héritée ; préfère les contrôles de capacité
Accesseurs FeatureGateAucunIntrospection de licenceVariableAucuncurrentEdition(), isLicenseValid(), isInGracePeriod(), getActivePacks(), trialPolicy()
CapabilityCodeÉnumération adossée à une chaîneIdentifiants de capacité canoniques (core.*, pro.*, enterprise.*, pack.*)AucunisPack(), packName(), minimumEdition(), forEdition()
CapabilityRegistryLicenseKey, motifs de routeRésolution route-vers-capacité et recherche de pack avant la répartitionVariableAucunregisterDefaultRoutes() couvre les routes de service documentées
LicenseKeyObjet-valeur en lecture seuleRevendications de licence analysées et vérifiéesAucunisExpired(), isInGracePeriod(), isFullyExpired(), hasFeature(), hasCapability(), activePackNames() ; maxSlots est purement contractuel
LicenseValidator::buildVerifiedLicenseKey()array $dataConstruit un LicenseKey typé à partir d’une charge utile déjà vérifiéeLicenseKeySpectrumAuthenticationException SPEC-AUTH-001 en cas de violation de schémaPrend en charge les schémas 2.0, 1.0 et les charges utiles héritées
PackDefinition / PackRegistryObjets-valeur en lecture seuleÉtat des packs additionnels avec expiration et grâce indépendantesVariableAucunisActive(), isFullyExpired(), activePacks(), activeCapabilities()
TrialPolicybool $enabled, int $maxPagesPerSecond = 2, champs de filigranePolitique de plafonnement du débit d’essaiAucunfromLicenseKey(), disabled(), isThrottled() ; l’autorité de marquage reste au niveau de l’évaluateur
ChannelEnforcementPolicy::enforce()LicenseKey $license, LocalState $state, int $systemNow, bool $revoked = falseExécute la machine à deux minuteurs plus la révocation et le ré-étiquetage d’essaiEnforcementOutcomeAucunLa révocation prime sur tous les minuteurs et l’état d’essai
OnlineCheckScheduler::evaluate(), ::recordSuccessfulOnlineCheck()Licence, état local, horodatagesÉvaluation à deux minuteurs ; renouvellement du bail à partir de l’heure serveur vérifiéeEnforcementOutcome / LocalStateAucunONLINE_GRACE_SECONDS accorde 48 heures de grâce de vivacité au-delà du bail
EnforcementDecision / EnforcementReason / EnforcementOutcomeÉnumérations + objet-valeur en lecture seuleActive, Grace, DowngradedToCore plus la raison préciseAucunChaque raison correspond de façon déterministe à une décision
Runtime\EntitlementResolver::currentEntitlement()AucunInterface : le droit imposé que sert l’exécutionEntitlementResultDéfini par l’implémentationEnforcedEntitlementResolver compose cache, état, politique et évaluateur, à sécurité intégrée vers Core
LicenseStateCache::get(), ::getOrThrow()bool $forceRefresh = falseCache de licence vérifiée qui alimente le contrôleur?LicenseKeygetOrThrow() : SpectrumAuthenticationException SPEC-AUTH-008 ; LicenseConfigurationException en cas de câblage invalideinvalidate(), isCacheValid()
LicenseClient::activate(), ::heartbeat(), ::deactivate(), ::verifyOnline()string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = nullUn échange de statut signé ; la réponse est vérifiée face à la racine épinglée et liée au nonce envoyéStatusResponseLicenseClientException (transport, non-200, nonce fourni invalide) ; SpectrumAuthenticationException (réponse falsifiée, altérée, périmée, à mauvais nonce, à mauvaise licence, de mauvais type)Seul le hachage salé de l’empreinte est envoyé, jamais une empreinte brute
LicenseClient::checkRenewal()string $licenseId, string $customerIdSonde de disponibilité de renouvellement ; 404 est la réponse normale « aucun disponible »Tableau de renouvellement (available, download_url, expires_at)LicenseClientException (injoignable, non-200/404, ou download_url rejeté par la politique)L’URL du corps non signé est filtrée contre le SSRF avant de pouvoir s’échapper
LicenseClient::__construct()Voir le bloc de signatureValide le transport, le schéma d’URL et le jeu d’épingles à la constructionLicenseConfigurationException (transport n’appliquant pas la politique, schéma interdit, HTTP en clair sans épingles, jeu d’épingles malformé)getPinSet() expose le jeu d’épingles actif pour l’outillage de rotation
Online\StatusResponseObjet-valeur en lecture seuleLe statut signé vérifiéAucunisLive() est faux pour revoked / expired / released ; porte leaseExpiresAt, les décomptes de créneaux et un instantané de droits
LicenseChannelMode / OnlineMode / OnlinePolicyÉnumérations + objet-valeur en lecture seuleRevendications de canal et de politique en ligneAucunsigned_source vs ioncube ; mode en ligne required / optional / disabled avec intervalDays et leaseDays
LicenseEditionÉnumération adossée à une chaîneCore, Pro, EnterpriseAucunsatisfies() implémente la hiérarchie des niveaux
public function __construct(private ?EvaluationBrandingConfig $evaluationBrandingConfig = null)
public function evaluate(?LicenseKey $license, ?DateTimeImmutable $now = null): EntitlementResult
public function evaluateEnforced(?LicenseKey $license, EnforcementOutcome $outcome): EntitlementResult
public function resolveBrandingMode(?LicenseKey $license, ?DateTimeImmutable $now = null): BrandingMode
public function resolveBrandingStrategy(?LicenseKey $license, ?DateTimeImmutable $now = null): BrandingStrategy
public function __construct(private readonly LicenseStateCache $licenseCache, private readonly EntitlementResolver $entitlementResolver, private readonly string $upgradeInfoUrl = self::DEFAULT_UPGRADE_URL)
public function isFeatureEnabled(string $feature): bool
public function requireFeature(string $feature): void
public function currentEdition(): ?string
public function isLicenseValid(): bool
public function isInGracePeriod(): bool
public function hasCapability(CapabilityCode $capability): bool
public function requireCapability(CapabilityCode $capability): void
public function getActivePacks(): array
public function trialPolicy(): TrialPolicy
public function __construct(private readonly ClientInterface $httpClient, private readonly RequestFactoryInterface $requestFactory, private readonly StreamFactoryInterface $streamFactory, private readonly StatusX5cValidator $statusValidator, private readonly string $baseUrl = self::DEFAULT_BASE_URL, #[SensitiveParameter] private readonly ?string $apiKey = null, array $pinnedPublicKeys = [], array $backupPins = [], private readonly OutboundHttpPolicy $policy = new OutboundHttpPolicy(allowedSchemes: ['https'], connectTimeoutSeconds: 10, readTimeoutSeconds: 30, maxResponseBytes: 10_485_760, followRedirects: false, allowPrivateTargets: false, retryAttempts: 0, retryBaseBackoffMs: 250))
public function activate(string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = null): StatusResponse
public function heartbeat(string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = null): StatusResponse
public function deactivate(string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = null): StatusResponse
public function verifyOnline(string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = null): StatusResponse
public function getPinSet(): ?PinSet
public function checkRenewal(string $licenseId, string $customerId): array

L’évaluation des droits produit l’un des cinq états actuels, chacun avec une conséquence d’exécution fixe :

StatutExécutionCapacités effectivesMises à jour / supportMarquage
Activeautoriséeédition attribuée + packs actifsoui (payant) ; non (évaluation)aucun (payant) ; filigrane (évaluation)
GracePeriodautoriséeédition attribuée + packs actifsouiaucun (payant)
DowngradedToCoreautoriséeCore uniquementnonaucun (payant) ; filigrane (essai)
EvaluationExpiredrestreinteaucunenonfiligrane
NoLicensedésactivée (à sécurité intégrée)aucunenonfiligrane
  • L’expiration payante ne désactive jamais l’exécution installée. runtimeAllowed reste vrai pour chaque état payant. Passée la fenêtre de grâce, l’édition effective rétrograde vers Core : les capacités Core continuent de fonctionner indéfiniment, toutes les capacités Pro/Enterprise/pack se bloquent, et les mises à jour et le support sont révoqués. Le cas déprécié EntitlementStatus::PerpetualFallback nomme la politique d’expiration antérieure à 6.0 et n’existe que pour la compatibilité de compilation.
  • Tout état ne se termine pas par une exécution Core. La grâce conserve l’édition attribuée complète avec un avertissement de renouvellement daté. L’expiration d’évaluation restreint l’exécution et conserve le filigrane. L’état sans licence désactive les chemins Enterprise à sécurité intégrée et appose visiblement un filigrane sur toute sortie héritée, de sorte qu’il ne peut jamais passer pour une exécution payante.
  • Ordre de résolution fixe. Une licence entièrement expirée ne résout aucune capacité. Les capacités de pack s’en remettent à l’état actif propre au pack et à son expiration indépendante. Les capacités d’édition se résolvent face à l’édition effective imposée selon la hiérarchie stricte Enterprise ⊇ Pro ⊇ Core. LicenseKey::$edition brut n’est jamais consulté pour le contrôle.
  • Deux minuteurs ; le plus restrictif l’emporte. Le minuteur de droits (les deux canaux) pilote Active, Grace et la rétrogradation vers Core après la grâce. Le minuteur de vivacité en ligne s’applique uniquement au canal ioncube avec le mode en ligne required : le bail, plus une grâce de vivacité de 48 heures, doit être actif. Hors ligne au-delà du bail, le premium se met en pause au niveau Core ; une vérification en ligne ultérieure vérifiée rétablit le bail et le premium reprend. Le canal signed_source — et tout mode en ligne non requis — n’a pas de minuteur de vivacité et reste hors ligne et compatible avec l’isolement réseau.
  • L’anti-retour arrière est déterministe. L’application évalue face à un plancher monotone : l’heure effective est le maximum de l’horloge système et de la dernière heure vérifiée, de sorte qu’un changement d’horloge vers l’arrière n’accorde aucun temps supplémentaire. Un retour arrière dépassant la tolérance de dérive et la grâce restante force la rétrogradation vers Core.
  • Les baux avancent uniquement sur une heure de confiance. Une vérification en ligne réussie enregistre l’heure serveur vérifiée et signée, jamais l’horloge locale, de sorte qu’un saut d’horloge locale vers l’avant ne peut pas gonfler le bail.
  • Le marquage a une seule autorité. Seul le canal d’évaluation déclenche le filigrane. Une licence payante ne résout aucun marquage dans tout état, y compris les états rétrogradés.
  • L’essai est une couche de politique sur les mêmes minuteurs. Le débit est plafonné (par défaut 2 pages/seconde), le filigrane d’évaluation s’applique et l’expiration est stricte, sans grâce. Seule la raison rapportée change ; la décision et l’édition effective suivent la machine payante.
  • Le contrat en ligne est signé de bout en bout. Chaque requête porte un nonce client CSPRNG. Chaque réponse est un JWS EdDSA compact de type de média application/nextpdf-status+jwt, vérifié via une chaîne x5c jusqu’à une racine épinglée compilée et lié au nonce envoyé, à l’identifiant de licence installé et au point de terminaison invoqué. L’ancien transport d’enveloppe non signée est retiré ; il ne reste exactement qu’un seul chemin de confiance. Les épingles SPKI configurées circulent dans l’en-tête X-NextPDF-Pinned-Public-Key, et un jeu d’épingles doit inclure une épingle de secours.
  • Aucune application de sièges à l’exécution. maxSlots est purement contractuel — aucune télémétrie et aucun rappel obligatoire pour le fonctionnement ordinaire.
  • Un contrôle de capacité sur une licence entièrement expirée court-circuite vers « indisponible » avant l’exécution de toute logique de pack ou d’édition.
  • Un pack additionnel peut expirer alors que la licence de base est active. Le refus indique alors pack expiré (SPEC-LIC-002), et non non licencié (SPEC-LIC-001), et liste les packs actuellement actifs.
  • Un fichier d’état d’application local présent mais illisible ou non analysable est un signal d’altération. La machine bascule à sécurité intégrée vers la rétrogradation Core avec EnforcementReason::CorruptState. Un fichier légitimement absent n’est pas corrompu et se poursuit normalement.
  • Un retour arrière d’horloge sous le plancher monotone qui dépasse la tolérance de dérive (par défaut 120 secondes) et la grâce restante force la rétrogradation Core de façon déterministe.
  • Un bail de vivacité expiré rétrograde une licence ioncube par ailleurs Active ; l’expiration des droits rétrograde quel que soit l’état du bail.
  • evaluate(null) est à sécurité intégrée : l’exécution est interdite, le filigrane s’applique et l’avertissement nomme l’URL de tarification. Les hôtes qui ont besoin d’un comportement Core sans licence doivent construire directement le moteur Core.
  • Une licence d’évaluation expirée n’a ni grâce ni repli ; l’exécution est restreinte et le filigrane demeure.
  • checkRenewal() traite le HTTP 404 comme la réponse normale « aucun disponible ». Tout autre code non-200 lève LicenseClientException, et un download_url qui viole la politique sortante échoue à sécurité intégrée avant de pouvoir s’échapper de la méthode.
  • Une réponse de statut falsifiée, altérée, périmée, à mauvais nonce ou à mauvaise licence ne produit jamais de StatusResponse ; la vérification lève SpectrumAuthenticationException. Un statut signé mais revoked, expired ou released se vérifie et se présente comme un signal de rétrogradation (isLive() est faux).
  • Une réponse de statut émise pour un autre échange est rejetée : le response_type vérifié doit correspondre au point de terminaison invoqué.
  • FeatureGate bascule à sécurité intégrée en cas d’erreur du résolveur : l’édition effective se dégrade vers core et aucune capacité premium n’est accordée.
  • EnforcedEntitlementResolver est à sécurité intégrée de bout en bout : toute exception dans sa chaîne produit le résultat sans licence (Core) et un journal d’erreur PSR-3, jamais un octroi premium.

La couche de gestion des licences n’ajoute aucune politique cryptographique propre. Les signatures de licence et de statut sont des vérifications Ed25519 effectuées par le fournisseur cryptographique de l’hôte. Dans une build contrainte par FIPS, un algorithme que le fournisseur n’approuve pas échoue à la frontière cryptographique avec une erreur explicite ; rien ne rétrograde en silence. Ce sont des affirmations de capacité concernant le code NextPDF : NextPDF n’est pas un module cryptographique validé, ne détient aucune certification et n’en accorde aucune.

AffirmationNormeClause
Les fichiers de licence et les réponses de statut sont des JWS en sérialisation compacte, vérifiés à sécurité intégrée.RFC 7515§3.1
Les signatures de licence et de statut sont Ed25519.RFC 8032§5.1
La chaîne x5c d’une réponse signée se valide jusqu’à une ancre de confiance épinglée compilée.RFC 5280§6.1
Un jeu d’épingles SPKI configuré doit inclure une épingle de secours pour une clé pas encore déployée.RFC 7469§4.3
Les revendications vérifiées (iss, aud, exp, nbf, iat) sont des noms de revendication enregistrés.RFC 7519§4.1

Toutes les clauses sont paraphrasées ; aucun texte normatif n’est reproduit. NextPDF ne formule aucune revendication de certification. La prise en charge n’équivaut pas à la conformité, et la conformité n’équivaut pas à la certification. Le module aligne son comportement sur les clauses citées à titre de capacité ; l’acceptation d’une enveloppe de licence ou de statut est décidée par le vérificateur à racine épinglée propre à NextPDF, et non par une autorité externe.

  • Construis LicenseClient avec un transport appliquant la politique (canoniquement SecurityAwareHttpClient). Un client PSR-18 brut est rejeté à la construction afin que le trafic de licence ne puisse jamais être envoyé sans les contrôles anti-SSRF, sans redirection, de plafond d’octets et de délai d’expiration.
  • Un nonce client fourni par l’appelant doit se décoder en au moins 16 octets d’entropie. La source fonde cette borne sur RFC 8555 §6.5 ; cette clause est hors du corpus cité, donc la borne est énoncée ici à partir de la source du produit uniquement.
  • Contrôle les fonctionnalités via FeatureGate ; ne branche jamais sur LicenseKey::$edition brut. Le contrôleur consulte uniquement l’édition effective imposée et bascule à sécurité intégrée vers core.
  • N’aiguille pas sur le cas déprécié EntitlementStatus::PerpetualFallback dans du nouveau code. Teste plutôt isDowngradedToCore() ou fais correspondre DowngradedToCore.
  • Traite un refus de capacité comme une charge utile de remédiation. Expose son contexte structuré et son URL de mise à niveau à l’appelant plutôt que de le réduire à une erreur générique.
  • Ce module concerne des fonctionnalités cryptographiques ; traite-le comme sensible du point de vue de la sécurité dans ta propre revue. Les conditions de capacité et de sièges sont régies par le contrat de licence, et non par l’application à l’exécution. Cette référence n’est pas un avis juridique ; consulte tes propres conseillers en conformité et en droit.

Cette page documente uniquement le comportement observable de l’extérieur et la surface d’API publique prise en charge. Les chemins d’espace de noms internes, les classes utilitaires, les tables de mécanismes, les noms de fichiers de runbook et les préfixes de tickets sortent du périmètre.