Salta ai contenuti
getnextpdf.com

Enterprise edizione

Licensing — Riferimento approfondito

Questa pagina è il riferimento approfondito della superficie di licensing di NextPDF Enterprise — il modulo che risolve ogni altra capability di Enterprise. Copre il modello degli stati di entitlement (EntitlementEvaluator, EntitlementStatus, EntitlementResult), il gating applicato delle capability (FeatureGate, CapabilityCode, CapabilityRegistry), la macchina di enforcement di canale a due timer (ChannelEnforcementPolicy, OnlineCheckScheduler) e il client online firmato (LicenseClient). La normale valutazione dell’entitlement non richiede rete. Il client online esiste per le operazioni esplicite di attivazione, heartbeat, disattivazione, verifica online e sonda di rinnovo. I dettagli del meccanismo interno restano nella documentazione interna del repository sorgente e sono fuori ambito per questo manuale.

Questa capability è inclusa in NextPDF Enterprise (nextpdf/enterprise) e si attiva con un envelope di licenza di tier Enterprise. Una distribuzione priva di quell’entitlement non carica le classi della capability. Confronta le edizioni e ottieni una licenza.

Il licensing è una superficie di base di Enterprise. È sempre presente una volta installato il pacchetto Enterprise accanto al pacchetto Core, perché è la superficie che risolve tutto il resto. NextPDF Pro non ha una superficie di entitlement separata; il modello degli stati, la macchina di enforcement e il client online sono inclusi esclusivamente in nextpdf/enterprise. NextPDF Core (Apache-2.0) non dispone affatto di un modello di entitlement — un host che necessiti del comportamento Apache-2.0 senza licenza usa direttamente il motore Core, non la pipeline Enterprise.

Tutti i tipi risiedono in NextPDF\Enterprise\Licensing. La macchina di enforcement si trova nel sotto-namespace Channel, la composizione di runtime in Runtime e i tipi di stato firmato in Online.

SimboloParametriComportamento predefinitoRestituisceLancia o fallisce conNote
EntitlementEvaluator::evaluate()?LicenseKey $license, ?DateTimeImmutable $now = nullMappa una licenza verificata (o null) sulla decisione di entitlement completaEntitlementResultNessunaUna licenza null produce il risultato no-license fail-closed
EntitlementEvaluator::evaluateEnforced()?LicenseKey $license, EnforcementOutcome $outcomeConverte un esito di enforcement pre-calcolato in un risultato di entitlementEntitlementResultNessunaL’edizione effettiva proviene dall’esito; ogni downgrade di enforcement approda a Core
EntitlementEvaluator::resolveBrandingMode(), ::resolveBrandingStrategy()?LicenseKey $license, ?DateTimeImmutable $now = nullRisolve la decisione di branding per l’output generatoBrandingMode / BrandingStrategyNessunaUnica autorità sul branding; solo il canale di valutazione applica la filigrana
EntitlementResultValue object readonlyTrasporta stato, edizione, canale, modalità di branding, flag di runtime/aggiornamenti/supporto e un avviso facoltativoNessunaHelper: isFullyActive(), isExpired(), isDowngradedToCore(), shouldApplyEvaluationBranding()
EntitlementStatusEnum a backing stringActive, GracePeriod, DowngradedToCore, EvaluationExpired, NoLicenseNessunaPerpetualFallback è mantenuto ma deprecato; conservato solo perché i consumer pre-6.0 continuino a compilare
FeatureGate::hasCapability()CapabilityCode $capabilityVerifica la capability rispetto all’edizione effettiva applicata e allo stato dei pacchettiboolNessunaFail-closed a core in caso di qualsiasi errore del resolver
FeatureGate::requireCapability()CapabilityCode $capabilityPassa silenziosamente o lancia con contesto di upsell strutturatovoidSpectrumAuthenticationException SPEC-LIC-001 (non concesso in licenza) o SPEC-LIC-002 (pacchetto scaduto)Il contesto trasporta required_capability, required_pack, current_packs, upgrade_info_url
FeatureGate::isFeatureEnabled(), ::requireFeature()string $featureControllo legacy per identificatore di funzionalitàbool / voidSpectrumAuthenticationException SPEC-AUTH-007 (percorso require)Compatibilità legacy; preferire i controlli di capability
Accessori di FeatureGateNessunoIntrospezione della licenzaVariabileNessunacurrentEdition(), isLicenseValid(), isInGracePeriod(), getActivePacks(), trialPolicy()
CapabilityCodeEnum a backing stringIdentificatori canonici di capability (core.*, pro.*, enterprise.*, pack.*)NessunaisPack(), packName(), minimumEdition(), forEdition()
CapabilityRegistryLicenseKey, pattern di rottaRisoluzione rotta-a-capability e lookup dei pacchetti prima del dispatchVariabileNessunaregisterDefaultRoutes() copre le rotte di servizio documentate
LicenseKeyValue object readonlyClaim di licenza analizzati e verificatiNessunaisExpired(), isInGracePeriod(), isFullyExpired(), hasFeature(), hasCapability(), activePackNames(); maxSlots è solo contrattuale
LicenseValidator::buildVerifiedLicenseKey()array $dataCostruisce un LicenseKey tipizzato da un payload già verificatoLicenseKeySpectrumAuthenticationException SPEC-AUTH-001 in caso di violazione dello schemaSupporta gli schemi 2.0, 1.0 e i payload legacy
PackDefinition / PackRegistryValue object readonlyStato dei pacchetti add-on con scadenza e tolleranza indipendentiVariabileNessunaisActive(), isFullyExpired(), activePacks(), activeCapabilities()
TrialPolicybool $enabled, int $maxPagesPerSecond = 2, campi filigranaPolicy di limitazione del throughput per il trialNessunafromLicenseKey(), disabled(), isThrottled(); l’autorità sul branding resta al valutatore
ChannelEnforcementPolicy::enforce()LicenseKey $license, LocalState $state, int $systemNow, bool $revoked = falseEsegue la macchina a due timer più la revoca e la rietichettatura del trialEnforcementOutcomeNessunaLa revoca prevale su ogni timer e su ogni stato di trial
OnlineCheckScheduler::evaluate(), ::recordSuccessfulOnlineCheck()Licenza, stato locale, timestampValutazione a due timer; rinnovo del lease dal tempo server verificatoEnforcementOutcome / LocalStateNessunaONLINE_GRACE_SECONDS concede 48 ore di tolleranza di liveness oltre il lease
EnforcementDecision / EnforcementReason / EnforcementOutcomeEnum + value object readonlyActive, Grace, DowngradedToCore più il motivo precisoNessunaOgni motivo mappa in modo deterministico su una sola decisione
Runtime\EntitlementResolver::currentEntitlement()NessunoInterfaccia: l’entitlement applicato che il runtime serveEntitlementResultDefinito dall’implementazioneEnforcedEntitlementResolver compone cache, stato, policy e valutatore, fail-closed a Core
LicenseStateCache::get(), ::getOrThrow()bool $forceRefresh = falseCache della licenza verificata a supporto del gate?LicenseKeygetOrThrow(): SpectrumAuthenticationException SPEC-AUTH-008; LicenseConfigurationException in caso di wiring non validoinvalidate(), isCacheValid()
LicenseClient::activate(), ::heartbeat(), ::deactivate(), ::verifyOnline()string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = nullUn singolo scambio di stato firmato; la risposta è verificata rispetto alla root pinnata e legata al nonce inviatoStatusResponseLicenseClientException (trasporto, non-200, nonce fornito errato); SpectrumAuthenticationException (risposta contraffatta, manomessa, obsoleta, con nonce errato, licenza errata o tipo errato)Viene sempre inviato solo l’hash con salt del fingerprint, mai un fingerprint grezzo
LicenseClient::checkRenewal()string $licenseId, string $customerIdSonda di disponibilità del rinnovo; 404 è la normale risposta «nessuno disponibile»Array di rinnovo (available, download_url, expires_at)LicenseClientException (irraggiungibile, non-200/404 o download_url respinto dalla policy)L’URL del corpo non firmato è sottoposto a screening anti-SSRF prima di poter uscire
LicenseClient::__construct()Vedere il blocco della firmaConvalida il trasporto, lo schema URL e il set di pin al momento della costruzioneLicenseConfigurationException (trasporto che non applica policy, schema non consentito, HTTP in chiaro senza pin, set di pin malformato)getPinSet() espone il set di pin attivo per gli strumenti di rotazione
Online\StatusResponseValue object readonlyLo stato firmato verificatoNessunaisLive() è false in stato revoked / expired / released; trasporta leaseExpiresAt, i conteggi degli slot e uno snapshot dell’entitlement
LicenseChannelMode / OnlineMode / OnlinePolicyEnum + value object readonlyClaim di canale e di policy onlineNessunasigned_source vs ioncube; modalità online required / optional / disabled con intervalDays e leaseDays
LicenseEditionEnum a backing stringCore, Pro, EnterpriseNessunasatisfies() implementa la gerarchia dei tier
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

La valutazione dell’entitlement produce uno di cinque stati correnti, ciascuno con una conseguenza fissa in fase di esecuzione:

StatoRuntimeCapability effettiveAggiornamenti / supportoBranding
Activeconsentitoedizione concessa + pacchetti attivisì (pagata); no (valutazione)nessuno (pagata); filigrana (valutazione)
GracePeriodconsentitoedizione concessa + pacchetti attivinessuno (pagata)
DowngradedToCoreconsentitosolo Corenonessuno (pagata); filigrana (trial)
EvaluationExpiredlimitatonessunanofiligrana
NoLicensedisabilitato (fail-closed)nessunanofiligrana
  • La scadenza di una licenza pagata non disabilita mai il runtime installato. runtimeAllowed resta true per ogni stato pagato. Oltre la finestra di tolleranza l’edizione effettiva degrada a Core: le capability Core continuano a funzionare indefinitamente, tutte le capability Pro/Enterprise/pacchetto vengono disattivate dal gate e aggiornamenti e supporto sono revocati. Il caso deprecato EntitlementStatus::PerpetualFallback nomina la policy di scadenza pre-6.0 ed esiste solo per compatibilità di compilazione.
  • Non ogni stato termina con l’esecuzione a livello Core. La tolleranza mantiene l’intera edizione concessa con un avviso di rinnovo datato. La scadenza della valutazione limita il runtime e mantiene la filigrana. Lo stato no-license disabilita i percorsi Enterprise in modalità fail-closed e contrassegna visibilmente con filigrana qualsiasi output legacy, così da non poter mai passare per esecuzione pagata.
  • Ordine di risoluzione fisso. Una licenza completamente scaduta non risolve alcuna capability. Le capability di pacchetto rinviano allo stato attivo e alla scadenza indipendente propri del pacchetto. Le capability di edizione si risolvono rispetto all’edizione effettiva applicata sulla gerarchia rigorosa Enterprise ⊇ Pro ⊇ Core. LicenseKey::$edition grezzo non viene mai consultato per il gating.
  • Due timer; vince il più restrittivo. Il timer di entitlement (entrambi i canali) governa Active, Grace e il downgrade a Core oltre la tolleranza. Il timer di liveness online si applica solo al canale ioncube con modalità online required: il lease, più una tolleranza di liveness di 48 ore, deve essere vivo. Offline oltre il lease, il premium si mette in pausa al tier Core; un successivo controllo online verificato ristabilisce il lease e il premium riprende. Il canale signed_source — e qualsiasi modalità online diversa da required — non ha timer di liveness e resta capace di funzionare offline e in ambienti air-gap.
  • L’anti-rollback è deterministico. L’enforcement valuta rispetto a un limite inferiore monotono: il tempo effettivo è il massimo tra l’orologio di sistema e l’ultimo tempo verificato, quindi un’alterazione all’indietro dell’orologio non concede tempo aggiuntivo. Un rollback che superi la tolleranza di scostamento e la tolleranza residua forza il downgrade a Core.
  • I lease avanzano solo su tempo fidato. Un controllo online riuscito registra il tempo server verificato e firmato, mai l’orologio locale, così un salto in avanti dell’orologio locale non può gonfiare il lease.
  • Il branding ha un’unica autorità. Solo il canale di valutazione attiva la filigrana. Una licenza pagata si risolve in nessun branding in ogni stato, compresi quelli in downgrade.
  • Il trial è uno strato di policy sugli stessi timer. Il throughput è limitato (predefinito 2 pagine/secondo), la filigrana di valutazione si applica e la scadenza è rigorosa senza tolleranza. Cambia solo il motivo riportato; la decisione e l’edizione effettiva seguono la macchina della licenza pagata.
  • Il contratto online è firmato end-to-end. Ogni richiesta trasporta un nonce client CSPRNG. Ogni risposta è un JWS EdDSA compatto di media type application/nextpdf-status+jwt, verificato tramite una catena x5c fino a una root pinnata compilata nel codice e legato al nonce inviato, all’id di licenza installato e all’endpoint invocato. Il trasporto legacy con envelope non firmato è dismesso; resta esattamente un solo percorso di fiducia. I pin SPKI configurati viaggiano nell’header X-NextPDF-Pinned-Public-Key e un set di pin deve includere un pin di backup.
  • Nessuna applicazione delle postazioni in fase di esecuzione. maxSlots è solo contrattuale — nessuna telemetria e nessun phone-home obbligatorio per il normale funzionamento.
  • Un controllo di capability su una licenza completamente scaduta va in cortocircuito a «non disponibile» prima dell’esecuzione di qualsiasi logica di pacchetto o di edizione.
  • Un pacchetto add-on può scadere mentre la licenza di base è attiva. Il diniego riporta allora «pacchetto scaduto» (SPEC-LIC-002), non «non concesso in licenza» (SPEC-LIC-001), ed elenca i pacchetti attualmente attivi.
  • Un file di stato di enforcement locale presente ma illeggibile o non analizzabile è un segnale di manomissione. La macchina fallisce in modo chiuso verso il downgrade a Core con EnforcementReason::CorruptState. Un file legittimamente assente non è corrotto e procede normalmente.
  • Un rollback dell’orologio al di sotto del limite inferiore monotono che superi la tolleranza di scostamento (predefinita 120 secondi) e la tolleranza residua forza il downgrade a Core in modo deterministico.
  • Un lease di liveness scaduto degrada una licenza ioncube altrimenti Active; la scadenza dell’entitlement causa il downgrade indipendentemente dallo stato del lease.
  • evaluate(null) è fail-closed: il runtime è negato, la filigrana si applica e l’avviso nomina l’URL dei prezzi. Gli host che necessitano del comportamento Core senza licenza devono costruire direttamente il motore Core.
  • Una licenza di valutazione scaduta non ha tolleranza né fallback; il runtime è limitato e la filigrana resta.
  • checkRenewal() tratta l’HTTP 404 come la normale risposta «nessuno disponibile». Qualsiasi altro non-200 solleva LicenseClientException, e un download_url che viola la policy in uscita fallisce in modo chiuso prima di poter uscire dal metodo.
  • Una risposta di stato contraffatta, manomessa, obsoleta, con nonce errato o licenza errata non produce mai uno StatusResponse; la verifica lancia SpectrumAuthenticationException. Uno stato firmato ma revoked, expired o released si verifica ed emerge come segnale di downgrade (isLive() è false).
  • Una risposta di stato coniata per uno scambio diverso viene respinta: il response_type verificato deve corrispondere all’endpoint invocato.
  • FeatureGate fallisce in modo chiuso in caso di qualsiasi errore del resolver: l’edizione effettiva degrada a core e nessuna capability premium viene concessa.
  • EnforcedEntitlementResolver è fail-closed end-to-end: qualsiasi eccezione nella sua catena produce il risultato no-license (Core) e un log di errore PSR-3, mai una concessione premium.

Il layer di licensing non aggiunge alcuna politica crittografica propria. Le firme di licenza e di stato sono verifiche Ed25519 eseguite dal provider crittografico dell’host. In una build vincolata a FIPS, un algoritmo che il provider non approva fallisce al confine crittografico con un errore esplicito; nulla degrada silenziosamente. Queste sono affermazioni di capability sul codice NextPDF: NextPDF non è un modulo crittografico validato, non detiene alcuna certificazione e non ne concede alcuna.

AffermazioneStandardClausola
I file di licenza e le risposte di stato sono JWS in serializzazione compatta, verificati fail-closed.RFC 7515§3.1
Le firme di licenza e di stato sono Ed25519.RFC 8032§5.1
La catena x5c in una risposta firmata si convalida fino a un trust anchor pinnato compilato nel codice.RFC 5280§6.1
Un set di pin SPKI configurato deve includere un pin di backup per una chiave non ancora distribuita.RFC 7469§4.3
I claim verificati (iss, aud, exp, nbf, iat) sono nomi di claim registrati.RFC 7519§4.1

Tutte le clausole sono parafrasate; nessun testo normativo è riprodotto. NextPDF non avanza alcuna pretesa di certificazione. Il supporto non equivale alla conformità e la conformità non equivale alla certificazione. Il modulo allinea il proprio comportamento alle clausole citate come capability; l’accettazione di un envelope di licenza o di stato è decisa dal verificatore a root pinnata di NextPDF, non da un’autorità esterna.

  • Costruire LicenseClient con un trasporto che applica policy (canonicamente SecurityAwareHttpClient). Un client PSR-18 grezzo viene respinto in costruzione, così il traffico di licenza non possa mai essere inviato senza i controlli anti-SSRF, no-redirect, di limite di byte e di timeout.
  • Un nonce client fornito dal chiamante deve decodificarsi in almeno 16 byte di entropia. Il sorgente fonda questo limite su RFC 8555 §6.5; quella clausola è al di fuori del corpus citato, quindi il limite è qui indicato solo dal sorgente del prodotto.
  • Applicare il gate alle funzionalità tramite FeatureGate; non diramare mai su LicenseKey::$edition grezzo. Il gate consulta solo l’edizione effettiva applicata e fallisce in modo chiuso a core.
  • Non usare lo switch sul deprecato EntitlementStatus::PerpetualFallback nel nuovo codice. Testare invece isDowngradedToCore() o fare match su DowngradedToCore.
  • Trattare il diniego di una capability come un payload di rimedio. Esporre al chiamante il suo contesto strutturato e l’URL di upgrade anziché ridurlo a un errore generico.
  • Questo modulo riguarda funzionalità crittografiche; trattarlo come sensibile alla sicurezza nella propria revisione. I termini di capacità e di postazioni sono governati dal contratto di licenza, non dall’applicazione in fase di esecuzione. Questo riferimento non è un parere legale; consultare i propri consulenti di conformità e legali.

Questa pagina documenta esclusivamente il comportamento osservabile dall’esterno e la superficie API pubblica supportata. I percorsi di namespace interni, le classi helper, le tabelle di meccanismo, i nomi di file di runbook e i prefissi di ticket sono fuori ambito.