Enterprise editie
Licensing — Diepe referentie
In één oogopslag
Sectie met titel “In één oogopslag”Deze pagina is de diepe referentie voor het NextPDF Enterprise licensing-oppervlak — de module die elke andere Enterprise-capaciteit resolveert. Ze behandelt het entitlementstatusmodel (EntitlementEvaluator, EntitlementStatus, EntitlementResult), de gehandhaafde capaciteitsafscherming (FeatureGate, CapabilityCode, CapabilityRegistry), de twee-timer kanaalhandhavingsmachine (ChannelEnforcementPolicy, OnlineCheckScheduler), en de ondertekende online client (LicenseClient). Gewone entitlementevaluatie heeft geen netwerk nodig. De online client bestaat voor expliciete activate-, heartbeat-, deactivate-, verify-online- en renewal-probe-bewerkingen. Interne mechanismedetails blijven in de interne documentatie van de bronrepository en vallen buiten de scope van deze handleiding.
Beschikbaarheid & licentie
Sectie met titel “Beschikbaarheid & licentie”Deze capaciteit wordt meegeleverd in NextPDF Enterprise (nextpdf/enterprise) en activeert met een licentie-envelop op Enterprise-niveau. Een implementatie zonder dat entitlement laadt de klassen van de capaciteit niet. Vergelijk edities en vraag een licentie aan.
Licensing is een basis-Enterprise-oppervlak. Het is altijd aanwezig zodra het Enterprise-pakket naast het Core-pakket is geïnstalleerd, omdat het het oppervlak is dat al het andere resolveert. NextPDF Pro heeft geen apart entitlementoppervlak; het statusmodel, de handhavingsmachine en de online client worden alleen meegeleverd in nextpdf/enterprise. NextPDF Core (Apache-2.0) heeft helemaal geen entitlementmodel — een host die ongelicentieerd Apache-2.0-gedrag nodig heeft, gebruikt de Core-engine rechtstreeks, niet de Enterprise-pijplijn.
Publiek API-oppervlak
Sectie met titel “Publiek API-oppervlak”Alle typen bevinden zich onder NextPDF\Enterprise\Licensing. De handhavingsmachine zit in de Channel-subnamespace, de runtimesamenstelling in Runtime, en de signed-status-typen in Online.
| Symbool | Parameters | Standaardgedrag | Retourneert | Werpt of faalt met | Opmerkingen |
|---|---|---|---|---|---|
EntitlementEvaluator::evaluate() | ?LicenseKey $license, ?DateTimeImmutable $now = null | Mapt een geverifieerde licentie (of null) naar de volledige entitlementbeslissing | EntitlementResult | Geen | Een null-licentie levert het fail-closed no-license-resultaat op |
EntitlementEvaluator::evaluateEnforced() | ?LicenseKey $license, EnforcementOutcome $outcome | Zet een vooraf berekende handhavingsuitkomst om in een entitlementresultaat | EntitlementResult | Geen | De effectieve editie komt uit de uitkomst; elke handhavings-downgrade komt uit op Core |
EntitlementEvaluator::resolveBrandingMode(), ::resolveBrandingStrategy() | ?LicenseKey $license, ?DateTimeImmutable $now = null | Resolveert de brandingbeslissing voor gegenereerde uitvoer | BrandingMode / BrandingStrategy | Geen | Enig brandinggezag; alleen het evaluatiekanaal plaatst een watermerk |
EntitlementResult | Readonly value-object | Draagt status, editie, kanaal, brandingmodus, runtime-/update-/ondersteuningsvlaggen en een optionele waarschuwing | — | Geen | Helpers: isFullyActive(), isExpired(), isDowngradedToCore(), shouldApplyEvaluationBranding() |
EntitlementStatus | String-backed enum | Active, GracePeriod, DowngradedToCore, EvaluationExpired, NoLicense | — | Geen | PerpetualFallback blijft behouden maar is deprecated; alleen bewaard zodat pre-6.0-consumers nog compileren |
FeatureGate::hasCapability() | CapabilityCode $capability | Controleert de capaciteit tegen de gehandhaafde effectieve editie en packstatus | bool | Geen | Fail-closed naar core bij elke resolver-fout |
FeatureGate::requireCapability() | CapabilityCode $capability | Slaagt stil of werpt met gestructureerde upsell-context | void | SpectrumAuthenticationException SPEC-LIC-001 (niet gelicentieerd) of SPEC-LIC-002 (pack verlopen) | De context draagt required_capability, required_pack, current_packs, upgrade_info_url |
FeatureGate::isFeatureEnabled(), ::requireFeature() | string $feature | Legacy feature-identifier-controle | bool / void | SpectrumAuthenticationException SPEC-AUTH-007 (require-pad) | Legacy-compatibiliteit; geef de voorkeur aan capaciteitscontroles |
FeatureGate-accessors | Geen | Licentie-introspectie | Wisselt | Geen | currentEdition(), isLicenseValid(), isInGracePeriod(), getActivePacks(), trialPolicy() |
CapabilityCode | String-backed enum | Canonieke capaciteitsidentifiers (core.*, pro.*, enterprise.*, pack.*) | — | Geen | isPack(), packName(), minimumEdition(), forEdition() |
CapabilityRegistry | LicenseKey, routepatronen | Route-naar-capaciteit-resolutie en pack-lookup vóór dispatch | Wisselt | Geen | registerDefaultRoutes() dekt de gedocumenteerde serviceroutes |
LicenseKey | Readonly value-object | Geparseerde, geverifieerde licentieclaims | — | Geen | isExpired(), isInGracePeriod(), isFullyExpired(), hasFeature(), hasCapability(), activePackNames(); maxSlots is alleen contractueel |
LicenseValidator::buildVerifiedLicenseKey() | array $data | Bouwt een getypeerde LicenseKey uit een reeds geverifieerde payload | LicenseKey | SpectrumAuthenticationException SPEC-AUTH-001 bij schemaschending | Ondersteunt schema 2.0, 1.0 en legacy-payloads |
PackDefinition / PackRegistry | Readonly value-objects | Add-on-packstatus met onafhankelijk verloop en grace | Wisselt | Geen | isActive(), isFullyExpired(), activePacks(), activeCapabilities() |
TrialPolicy | bool $enabled, int $maxPagesPerSecond = 2, watermerkvelden | Trial-doorvoerbegrenzingsbeleid | — | Geen | fromLicenseKey(), disabled(), isThrottled(); het brandinggezag blijft bij de evaluator |
ChannelEnforcementPolicy::enforce() | LicenseKey $license, LocalState $state, int $systemNow, bool $revoked = false | Draait de twee-timer machine plus herroeping en trial-herlabeling | EnforcementOutcome | Geen | Herroeping overschrijft elke timer- en trial-status |
OnlineCheckScheduler::evaluate(), ::recordSuccessfulOnlineCheck() | Licentie, lokale status, timestamps | Twee-timer evaluatie; lease-vernieuwing op basis van geverifieerde servertijd | EnforcementOutcome / LocalState | Geen | ONLINE_GRACE_SECONDS verleent 48 uur liveness-grace voorbij de lease |
EnforcementDecision / EnforcementReason / EnforcementOutcome | Enums + readonly value-object | Active, Grace, DowngradedToCore plus de precieze reden | — | Geen | Elke reden mapt deterministisch naar één beslissing |
Runtime\EntitlementResolver::currentEntitlement() | Geen | Interface: het gehandhaafde entitlement dat de runtime bedient | EntitlementResult | Implementatie-afhankelijk | EnforcedEntitlementResolver stelt cache, status, beleid en evaluator samen, fail-closed naar Core |
LicenseStateCache::get(), ::getOrThrow() | bool $forceRefresh = false | Geverifieerde-licentiecache achter de gate | ?LicenseKey | getOrThrow(): SpectrumAuthenticationException SPEC-AUTH-008; LicenseConfigurationException bij ongeldige bedrading | invalidate(), isCacheValid() |
LicenseClient::activate(), ::heartbeat(), ::deactivate(), ::verifyOnline() | string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = null | Eén signed-status-uitwisseling; het antwoord wordt geverifieerd tegen de pinned root en gebonden aan de verzonden nonce | StatusResponse | LicenseClientException (transport, non-200, ongeldige opgegeven nonce); SpectrumAuthenticationException (vervalst, gemanipuleerd, verouderd, verkeerde-nonce, verkeerde-licentie, verkeerd-type antwoord) | Alleen de gesalte fingerprint-hash wordt ooit verzonden, nooit een ruwe fingerprint |
LicenseClient::checkRenewal() | string $licenseId, string $customerId | Beschikbaarheidsprobe voor vernieuwing; 404 is het normale “geen beschikbaar”-antwoord | Renewal-array (available, download_url, expires_at) | LicenseClientException (onbereikbaar, non-200/404, of een door beleid geweigerde download_url) | De URL in de unsigned body wordt SSRF-gescreend voordat deze kan ontsnappen |
LicenseClient::__construct() | Zie signatuurblok | Valideert het transport, URL-schema en de pinset bij constructie | — | LicenseConfigurationException (transport dat geen beleid afdwingt, niet-toegestaan schema, plain HTTP zonder pins, misvormde pinset) | getPinSet() stelt de actieve pinset beschikbaar voor rotatietooling |
Online\StatusResponse | Readonly value-object | De geverifieerde ondertekende status | — | Geen | isLive() is false bij revoked / expired / released; draagt leaseExpiresAt, slot-aantallen en een entitlement-snapshot |
LicenseChannelMode / OnlineMode / OnlinePolicy | Enums + readonly value-object | Kanaal- en online-beleidsclaims | — | Geen | signed_source vs ioncube; online-modus required / optional / disabled met intervalDays en leaseDays |
LicenseEdition | String-backed enum | Core, Pro, Enterprise | — | Geen | satisfies() implementeert de tier-hiërarchie |
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): arrayGedragscontract
Sectie met titel “Gedragscontract”Entitlementevaluatie levert een van vijf huidige statussen op, elk met een vast runtime-gevolg:
| Status | Runtime | Effectieve capaciteiten | Updates / ondersteuning | Branding |
|---|---|---|---|---|
Active | toegestaan | gerechtigde editie + actieve packs | ja (betaald); nee (evaluatie) | geen (betaald); watermerk (evaluatie) |
GracePeriod | toegestaan | gerechtigde editie + actieve packs | ja | geen (betaald) |
DowngradedToCore | toegestaan | alleen Core | nee | geen (betaald); watermerk (trial) |
EvaluationExpired | beperkt | geen | nee | watermerk |
NoLicense | uitgeschakeld (fail-closed) | geen | nee | watermerk |
- Betaald verloop schakelt de geïnstalleerde runtime nooit uit.
runtimeAllowedblijft true voor elke betaalde status. Voorbij het grace-venster downgradet de effectieve editie naar Core: Core-capaciteiten blijven onbeperkt draaien, alle Pro-/Enterprise-/pack-capaciteiten schakelen uit, en updates en ondersteuning worden herroepen. De deprecatedEntitlementStatus::PerpetualFallback-case benoemt het pre-6.0-verloopbeleid en bestaat alleen voor compile-compatibiliteit. - Niet elke status eindigt in Core-uitvoering. Grace behoudt de volledige gerechtigde editie met een gedateerde vernieuwingswaarschuwing. Evaluatieverloop beperkt de runtime en behoudt het watermerk. De no-license-status schakelt Enterprise-paden fail-closed uit en voorziet elke legacy-uitvoer zichtbaar van een watermerk, zodat deze nooit kan doorgaan voor een betaalde uitvoering.
- Vaste resolutievolgorde. Een volledig verlopen licentie resolveert geen enkele capaciteit. Pack-capaciteiten schuiven door naar de eigen actieve status en het onafhankelijke verloop van het pack. Editiecapaciteiten resolveren tegen de gehandhaafde effectieve editie op de strikte hiërarchie Enterprise ⊇ Pro ⊇ Core. Ruwe
LicenseKey::$editionwordt nooit geraadpleegd voor afscherming. - Twee timers; de meest beperkende wint. De entitlement-timer (beide kanalen) stuurt Active, Grace en de post-grace Core-downgrade aan. De online-liveness-timer geldt alleen voor het
ioncube-kanaal met online-modusrequired: de lease, plus 48 uur liveness-grace, moet live zijn. Offline voorbij de lease pauzeert premium op de Core-tier; een latere geverifieerde online check herstelt de lease en premium hervat. Hetsigned_source-kanaal — en elke niet-vereiste online-modus — heeft geen liveness-timer en blijft offline en air-gap-capabel. - Anti-rollback is deterministisch. Handhaving evalueert tegen een monotone ondergrens: de effectieve tijd is het maximum van de systeemklok en de laatst geverifieerde tijd, zodat een terugwaartse klokwijziging geen extra tijd oplevert. Een rollback die de skew-tolerantie en de resterende grace overschrijdt, forceert de Core-downgrade.
- Leases lopen alleen vooruit op vertrouwde tijd. Een geslaagde online check registreert de geverifieerde, ondertekende servertijd, nooit de lokale klok, zodat een lokale voorwaartse kloksprong de lease niet kan opblazen.
- Branding heeft één gezag. Alleen het evaluatiekanaal activeert het watermerk. Een betaalde licentie resolveert in elke status naar geen branding, inclusief de gedowngradede statussen.
- Trial is een beleidslaag op dezelfde timers. De doorvoer wordt begrensd (standaard 2 pagina’s/seconde), het evaluatiewatermerk is van toepassing, en het verloop is strikt zonder grace. Alleen de gerapporteerde reden verandert; de beslissing en de effectieve editie volgen de betaalde machine.
- Het online contract is end-to-end ondertekend. Elke aanvraag draagt een CSPRNG-client-nonce. Elk antwoord is een compacte EdDSA JWS met mediatype
application/nextpdf-status+jwt, geverifieerd via een x5c-keten naar een ingecompileerde pinned root en gebonden aan de verzonden nonce, de geïnstalleerde license-id en het aangeroepen endpoint. Het legacy unsigned-enveloptransport is uitgefaseerd; er blijft precies één trust-pad over. Geconfigureerde SPKI-pins reizen mee als deX-NextPDF-Pinned-Public-Key-header, en een pinset moet een backuppin bevatten. - Geen runtime seat-handhaving.
maxSlotsis alleen contractueel — geen telemetrie en geen verplichte phone-home voor gewone werking.
Randgevallen & foutmodi
Sectie met titel “Randgevallen & foutmodi”- Een capaciteitscontrole op een volledig verlopen licentie kortsluit naar “niet beschikbaar” voordat er pack- of editielogica draait.
- Een add-on-pack kan verlopen terwijl de basislicentie actief is. De weigering leest dan pack verlopen (
SPEC-LIC-002), niet niet-gelicentieerd (SPEC-LIC-001), en somt de momenteel actieve packs op. - Een lokaal handhavingsstatusbestand dat aanwezig maar onleesbaar of niet-parseerbaar is, is een manipulatiesignaal. De machine faalt gesloten naar de Core-downgrade met
EnforcementReason::CorruptState. Een legitiem ontbrekend bestand is niet corrupt en verloopt normaal. - Een klok-rollback onder de monotone ondergrens die de skew-tolerantie (standaard 120 seconden) en de resterende grace overschrijdt, forceert de Core-downgrade deterministisch.
- Een verlopen liveness-lease downgradet een verder Active
ioncube-licentie; entitlementverloop downgradet ongeacht de lease-status. evaluate(null)is fail-closed: de runtime is niet toegestaan, het watermerk is van toepassing, en de waarschuwing benoemt de pricing-URL. Hosts die ongelicentieerd Core-gedrag nodig hebben, moeten de Core-engine rechtstreeks construeren.- Een verlopen evaluatielicentie heeft geen grace en geen fallback; de runtime is beperkt en het watermerk blijft.
checkRenewal()behandelt HTTP 404 als het normale “geen beschikbaar”-antwoord. Elke andere non-200 werptLicenseClientException, en eendownload_urldie het uitgaande beleid schendt, faalt gesloten voordat deze de methode kan ontsnappen.- Een vervalst, gemanipuleerd, verouderd, verkeerde-nonce- of verkeerde-licentie-statusantwoord levert nooit een
StatusResponseop; verificatie werptSpectrumAuthenticationException. Een ondertekende maarrevoked-,expired- ofreleased-status verifieert en verschijnt als een downgrade-signaal (isLive()is false). - Een statusantwoord dat voor een andere uitwisseling is aangemaakt, wordt afgewezen: het geverifieerde
response_typemoet overeenkomen met het aangeroepen endpoint. FeatureGatefaalt gesloten bij elke resolver-fout: de effectieve editie degradeert naarcoreen er wordt geen premium-capaciteit verleend.EnforcedEntitlementResolveris end-to-end fail-closed: elke exception in zijn keten levert het no-license (Core)-resultaat en een PSR-3-foutlog op, nooit een premium-verlening.
FIPS-modusgedrag
Sectie met titel “FIPS-modusgedrag”De licensing-laag voegt geen eigen cryptografisch beleid toe. Licentie- en statushandtekeningen zijn Ed25519-verificaties uitgevoerd door de crypto-provider van de host. In een FIPS-beperkte build faalt een algoritme dat de provider niet goedkeurt op de cryptografische grens met een expliciete fout; er degradeert niets stilzwijgend. Dit zijn capaciteitsclaims over NextPDF-code: NextPDF is geen gevalideerde cryptografische module, houdt geen certificering en verleent er geen.
Conformiteit
Sectie met titel “Conformiteit”| Claim | Standaard | Clausule |
|---|---|---|
| Licentiebestanden en statusantwoorden zijn compact-serialization JWS, fail-closed geverifieerd. | RFC 7515 | §3.1 |
| Licentie- en statushandtekeningen zijn Ed25519. | RFC 8032 | §5.1 |
| De x5c-keten in een ondertekend antwoord valideert terug naar een ingecompileerde pinned trust-anchor. | RFC 5280 | §6.1 |
| Een geconfigureerde SPKI-pinset moet een backuppin bevatten voor een nog-niet-uitgerolde sleutel. | RFC 7469 | §4.3 |
Geverifieerde claims (iss, aud, exp, nbf, iat) zijn geregistreerde claim-namen. | RFC 7519 | §4.1 |
Alle clausules zijn geparafraseerd; er wordt geen normatieve tekst gereproduceerd. NextPDF doet geen enkele certificeringsclaim. Ondersteuning staat niet gelijk aan conformiteit, en conformiteit staat niet gelijk aan certificering. De module stemt haar gedrag af op de aangehaalde clausules als een capaciteit; de acceptatie van een licentie- of status-envelop wordt beslist door NextPDF’s eigen pinned-root-verifier, niet door een externe autoriteit.
Ontwikkelnotities
Sectie met titel “Ontwikkelnotities”- Construeer
LicenseClientmet een transport dat beleid afdwingt (canoniekSecurityAwareHttpClient). Een ruwe PSR-18-client wordt bij constructie afgewezen, zodat licentieverkeer nooit kan worden verzonden zonder de anti-SSRF-, no-redirect-, byte-cap- en time-outcontroles. - Een door de aanroeper opgegeven client-nonce moet decoderen naar minstens 16 bytes entropie. De bron grondt deze ondergrens in RFC 8555 §6.5; die clausule valt buiten het aangehaalde corpus, dus de ondergrens wordt hier alleen op basis van de productbron vermeld.
- Scherm functies af via
FeatureGate; vertak nooit op ruweLicenseKey::$edition. De gate raadpleegt alleen de gehandhaafde effectieve editie en faalt gesloten naarcore. - Schakel in nieuwe code niet op de deprecated
EntitlementStatus::PerpetualFallback. Test in plaats daarvanisDowngradedToCore()of matchDowngradedToCore. - Behandel een capaciteitsweigering als een remediatiepayload. Toon de gestructureerde context en upgrade-URL aan de aanroeper in plaats van deze te reduceren tot een generieke fout.
- Deze module betreft cryptografische functionaliteit; behandel deze in je eigen review als beveiligingsgevoelig. Capaciteits- en seat-voorwaarden worden beheerst door de licentieovereenkomst, niet door runtime-handhaving. Deze referentie is geen juridisch advies; raadpleeg je eigen compliance- en juridische adviseurs.
Publicatiegrens
Sectie met titel “Publicatiegrens”Deze pagina documenteert alleen extern waarneembaar gedrag en het ondersteunde publieke API-oppervlak. Interne namespace-paden, helperklassen, mechanismetabellen, runbook-bestandsnamen en ticketprefixen vallen buiten de scope.
Zie ook
Sectie met titel “Zie ook”- Licensing — NextPDF Enterprise — de capaciteitspagina met setup- en integratiebegeleiding.
- Billing — Diepe referentie — plan-tiers, overage-beleid en rollover.
- SaaS — Diepe referentie — het multi-tenant service-oppervlak dat de route-map bewaakt.
- Branding — Diepe referentie — de brandingstrategieën die de evaluator resolveert.