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.
Disponibilité et licence
Section intitulée « Disponibilité et licence »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.
Surface d’API publique
Section intitulée « Surface d’API publique »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.
| Symbole | Paramètres | Comportement par défaut | Retourne | Lève ou échoue avec | Notes |
|---|---|---|---|---|---|
EntitlementEvaluator::evaluate() | ?LicenseKey $license, ?DateTimeImmutable $now = null | Fait correspondre une licence vérifiée (ou null) à la décision de droits complète | EntitlementResult | Aucun | Une licence null produit le résultat sans licence, à sécurité intégrée |
EntitlementEvaluator::evaluateEnforced() | ?LicenseKey $license, EnforcementOutcome $outcome | Convertit un résultat d’application pré-calculé en résultat de droits | EntitlementResult | Aucun | L’édition effective provient du résultat ; toute rétrogradation d’application aboutit à Core |
EntitlementEvaluator::resolveBrandingMode(), ::resolveBrandingStrategy() | ?LicenseKey $license, ?DateTimeImmutable $now = null | Résout la décision de marquage pour la sortie générée | BrandingMode / BrandingStrategy | Aucun | Seule autorité de marquage ; seul le canal d’évaluation appose un filigrane |
EntitlementResult | Objet-valeur en lecture seule | Porte le statut, l’édition, le canal, le mode de marquage, les indicateurs d’exécution/mise à jour/support et un avertissement optionnel | — | Aucun | Assistants : isFullyActive(), isExpired(), isDowngradedToCore(), shouldApplyEvaluationBranding() |
EntitlementStatus | Énumération adossée à une chaîne | Active, GracePeriod, DowngradedToCore, EvaluationExpired, NoLicense | — | Aucun | PerpetualFallback est conservé mais déprécié ; maintenu uniquement pour que les consommateurs antérieurs à 6.0 compilent encore |
FeatureGate::hasCapability() | CapabilityCode $capability | Vérifie la capacité face à l’édition effective imposée et à l’état des packs | bool | Aucun | À sécurité intégrée vers core en cas d’erreur du résolveur |
FeatureGate::requireCapability() | CapabilityCode $capability | Passe en silence ou lève avec un contexte de montée en gamme structuré | void | SpectrumAuthenticationException 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 $feature | Contrôle d’identifiant de fonctionnalité hérité | bool / void | SpectrumAuthenticationException SPEC-AUTH-007 (chemin require) | Compatibilité héritée ; préfère les contrôles de capacité |
Accesseurs FeatureGate | Aucun | Introspection de licence | Variable | Aucun | currentEdition(), isLicenseValid(), isInGracePeriod(), getActivePacks(), trialPolicy() |
CapabilityCode | Énumération adossée à une chaîne | Identifiants de capacité canoniques (core.*, pro.*, enterprise.*, pack.*) | — | Aucun | isPack(), packName(), minimumEdition(), forEdition() |
CapabilityRegistry | LicenseKey, motifs de route | Résolution route-vers-capacité et recherche de pack avant la répartition | Variable | Aucun | registerDefaultRoutes() couvre les routes de service documentées |
LicenseKey | Objet-valeur en lecture seule | Revendications de licence analysées et vérifiées | — | Aucun | isExpired(), isInGracePeriod(), isFullyExpired(), hasFeature(), hasCapability(), activePackNames() ; maxSlots est purement contractuel |
LicenseValidator::buildVerifiedLicenseKey() | array $data | Construit un LicenseKey typé à partir d’une charge utile déjà vérifiée | LicenseKey | SpectrumAuthenticationException SPEC-AUTH-001 en cas de violation de schéma | Prend en charge les schémas 2.0, 1.0 et les charges utiles héritées |
PackDefinition / PackRegistry | Objets-valeur en lecture seule | État des packs additionnels avec expiration et grâce indépendantes | Variable | Aucun | isActive(), isFullyExpired(), activePacks(), activeCapabilities() |
TrialPolicy | bool $enabled, int $maxPagesPerSecond = 2, champs de filigrane | Politique de plafonnement du débit d’essai | — | Aucun | fromLicenseKey(), disabled(), isThrottled() ; l’autorité de marquage reste au niveau de l’évaluateur |
ChannelEnforcementPolicy::enforce() | LicenseKey $license, LocalState $state, int $systemNow, bool $revoked = false | Exécute la machine à deux minuteurs plus la révocation et le ré-étiquetage d’essai | EnforcementOutcome | Aucun | La 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ée | EnforcementOutcome / LocalState | Aucun | ONLINE_GRACE_SECONDS accorde 48 heures de grâce de vivacité au-delà du bail |
EnforcementDecision / EnforcementReason / EnforcementOutcome | Énumérations + objet-valeur en lecture seule | Active, Grace, DowngradedToCore plus la raison précise | — | Aucun | Chaque raison correspond de façon déterministe à une décision |
Runtime\EntitlementResolver::currentEntitlement() | Aucun | Interface : le droit imposé que sert l’exécution | EntitlementResult | Défini par l’implémentation | EnforcedEntitlementResolver compose cache, état, politique et évaluateur, à sécurité intégrée vers Core |
LicenseStateCache::get(), ::getOrThrow() | bool $forceRefresh = false | Cache de licence vérifiée qui alimente le contrôleur | ?LicenseKey | getOrThrow() : SpectrumAuthenticationException SPEC-AUTH-008 ; LicenseConfigurationException en cas de câblage invalide | invalidate(), isCacheValid() |
LicenseClient::activate(), ::heartbeat(), ::deactivate(), ::verifyOnline() | string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = null | Un échange de statut signé ; la réponse est vérifiée face à la racine épinglée et liée au nonce envoyé | StatusResponse | LicenseClientException (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 $customerId | Sonde 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 signature | Valide le transport, le schéma d’URL et le jeu d’épingles à la construction | — | LicenseConfigurationException (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\StatusResponse | Objet-valeur en lecture seule | Le statut signé vérifié | — | Aucun | isLive() 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 seule | Revendications de canal et de politique en ligne | — | Aucun | signed_source vs ioncube ; mode en ligne required / optional / disabled avec intervalDays et leaseDays |
LicenseEdition | Énumération adossée à une chaîne | Core, Pro, Enterprise | — | Aucun | satisfies() implémente la hiérarchie des niveaux |
public function __construct(private ?EvaluationBrandingConfig $evaluationBrandingConfig = null)public function evaluate(?LicenseKey $license, ?DateTimeImmutable $now = null): EntitlementResultpublic function evaluateEnforced(?LicenseKey $license, EnforcementOutcome $outcome): EntitlementResultpublic function resolveBrandingMode(?LicenseKey $license, ?DateTimeImmutable $now = null): BrandingModepublic function resolveBrandingStrategy(?LicenseKey $license, ?DateTimeImmutable $now = null): BrandingStrategypublic function __construct(private readonly LicenseStateCache $licenseCache, private readonly EntitlementResolver $entitlementResolver, private readonly string $upgradeInfoUrl = self::DEFAULT_UPGRADE_URL)public function isFeatureEnabled(string $feature): boolpublic function requireFeature(string $feature): voidpublic function currentEdition(): ?stringpublic function isLicenseValid(): boolpublic function isInGracePeriod(): boolpublic function hasCapability(CapabilityCode $capability): boolpublic function requireCapability(CapabilityCode $capability): voidpublic function getActivePacks(): arraypublic function trialPolicy(): TrialPolicypublic 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): StatusResponsepublic function heartbeat(string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = null): StatusResponsepublic function deactivate(string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = null): StatusResponsepublic function verifyOnline(string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = null): StatusResponsepublic function getPinSet(): ?PinSetpublic function checkRenewal(string $licenseId, string $customerId): arrayContrat de comportement
Section intitulée « Contrat de comportement »L’évaluation des droits produit l’un des cinq états actuels, chacun avec une conséquence d’exécution fixe :
| Statut | Exécution | Capacités effectives | Mises à jour / support | Marquage |
|---|---|---|---|---|
Active | autorisée | édition attribuée + packs actifs | oui (payant) ; non (évaluation) | aucun (payant) ; filigrane (évaluation) |
GracePeriod | autorisée | édition attribuée + packs actifs | oui | aucun (payant) |
DowngradedToCore | autorisée | Core uniquement | non | aucun (payant) ; filigrane (essai) |
EvaluationExpired | restreinte | aucune | non | filigrane |
NoLicense | désactivée (à sécurité intégrée) | aucune | non | filigrane |
- L’expiration payante ne désactive jamais l’exécution installée.
runtimeAllowedreste 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::PerpetualFallbacknomme 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::$editionbrut 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
ioncubeavec le mode en lignerequired: 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 canalsigned_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êteX-NextPDF-Pinned-Public-Key, et un jeu d’épingles doit inclure une épingle de secours. - Aucune application de sièges à l’exécution.
maxSlotsest purement contractuel — aucune télémétrie et aucun rappel obligatoire pour le fonctionnement ordinaire.
Cas limites et modes de défaillance
Section intitulée « Cas limites et modes de défaillance »- 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
ioncubepar 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èveLicenseClientException, et undownload_urlqui 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èveSpectrumAuthenticationException. Un statut signé maisrevoked,expiredoureleasedse 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_typevérifié doit correspondre au point de terminaison invoqué. FeatureGatebascule à sécurité intégrée en cas d’erreur du résolveur : l’édition effective se dégrade verscoreet aucune capacité premium n’est accordée.EnforcedEntitlementResolverest à 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.
Comportement en mode FIPS
Section intitulée « Comportement en mode FIPS »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.
Conformité
Section intitulée « Conformité »| Affirmation | Norme | Clause |
|---|---|---|
| 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.
Notes de développement
Section intitulée « Notes de développement »- Construis
LicenseClientavec un transport appliquant la politique (canoniquementSecurityAwareHttpClient). 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 surLicenseKey::$editionbrut. Le contrôleur consulte uniquement l’édition effective imposée et bascule à sécurité intégrée verscore. - N’aiguille pas sur le cas déprécié
EntitlementStatus::PerpetualFallbackdans du nouveau code. Teste plutôtisDowngradedToCore()ou fais correspondreDowngradedToCore. - 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.
Périmètre de publication
Section intitulée « Périmètre de publication »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.
Voir aussi
Section intitulée « Voir aussi »- Gestion des licences — NextPDF Enterprise — la page de capacité avec des conseils d’installation et d’intégration.
- Facturation — Référence détaillée — niveaux de forfait, politiques de dépassement et report.
- SaaS — Référence détaillée — la surface de service multi-locataire que protège la carte des routes.
- Marquage — Référence détaillée — les stratégies de marquage que résout l’évaluateur.