跳到內容
getnextpdf.com

Enterprise 版本

Licensing — 深入參考

本頁是 NextPDF Enterprise 授權介面的深入參考——這個模組會解析所有其他 Enterprise 能力。它涵蓋權益狀態模型(EntitlementEvaluatorEntitlementStatusEntitlementResult)、強制執行的能力閘控(FeatureGateCapabilityCodeCapabilityRegistry)、雙計時器通道強制執行機器(ChannelEnforcementPolicyOnlineCheckScheduler),以及已簽署的線上用戶端(LicenseClient)。一般的權益評估不需要任何網路。線上用戶端的存在是為了明確的 activate、heartbeat、deactivate、verify-online 與續約探測操作。內部機制細節留在原始碼儲存庫的內部文件中,不在本手冊的範圍內。

此能力隨 NextPDF Enterprisenextpdf/enterprise)提供,並在 Enterprise 層級的授權封套下啟用。不具該權益的部署不會載入此能力的類別。比較版本並取得授權

Licensing 是一個基礎 Enterprise 介面。只要 Enterprise 套件與 Core 套件並列安裝,它就一定存在,因為它是解析其他一切的那個介面。NextPDF Pro 沒有獨立的權益介面;狀態模型、強制執行機器與線上用戶端僅隨 nextpdf/enterprise 提供。NextPDF Core(Apache-2.0)完全沒有權益模型——需要未授權 Apache-2.0 行為的主機會直接使用 Core 引擎,而非 Enterprise 管線。

所有型別都位於 NextPDF\Enterprise\Licensing 之下。強制執行機器位於 Channel 子命名空間、執行階段組合位於 Runtime,而已簽署狀態型別位於 Online

符號參數預設行為回傳拋出或失敗於備註
EntitlementEvaluator::evaluate()?LicenseKey $license, ?DateTimeImmutable $now = null將一份已驗證的授權(或 null)對應到完整的權益決定EntitlementResultnull 授權會產生 fail-closed 的 no-license 結果
EntitlementEvaluator::evaluateEnforced()?LicenseKey $license, EnforcementOutcome $outcome將一個預先算出的強制執行結果轉換為權益結果EntitlementResult生效版本來自該結果;每一次強制執行降級都落在 Core
EntitlementEvaluator::resolveBrandingMode(), ::resolveBrandingStrategy()?LicenseKey $license, ?DateTimeImmutable $now = null為所產生的輸出解析品牌標示決定BrandingMode / BrandingStrategy唯一的品牌標示權威;只有評估通道會加浮水印
EntitlementResult唯讀值物件承載狀態、版本、通道、品牌標示模式、執行階段/更新/支援旗標,以及一個可選的警告輔助方法:isFullyActive(), isExpired(), isDowngradedToCore(), shouldApplyEvaluationBranding()
EntitlementStatus字串支援的 enumActive, GracePeriod, DowngradedToCore, EvaluationExpired, NoLicensePerpetualFallback 保留但已棄用;僅為讓 6.0 之前的消費端仍能編譯而保留
FeatureGate::hasCapability()CapabilityCode $capability對照強制執行的生效版本與套件包狀態來檢查該能力bool任何解析器錯誤都會 fail-closed 到 core
FeatureGate::requireCapability()CapabilityCode $capability靜默通過,或以結構化的加售情境拋出voidSpectrumAuthenticationException SPEC-LIC-001(未授權)或 SPEC-LIC-002(套件包已過期)該情境承載 required_capability, required_pack, current_packs, upgrade_info_url
FeatureGate::isFeatureEnabled(), ::requireFeature()string $feature舊版功能識別碼檢查bool / voidSpectrumAuthenticationException SPEC-AUTH-007(require 路徑)舊版相容;建議改用能力檢查
FeatureGate 存取器授權自省視情況而定currentEdition(), isLicenseValid(), isInGracePeriod(), getActivePacks(), trialPolicy()
CapabilityCode字串支援的 enum正規能力識別碼(core.*, pro.*, enterprise.*, pack.*isPack(), packName(), minimumEdition(), forEdition()
CapabilityRegistryLicenseKey, route patterns派送前的路由到能力解析與套件包查找視情況而定registerDefaultRoutes() 涵蓋已記載的服務路由
LicenseKey唯讀值物件已解析、已驗證的授權 claimsisExpired(), isInGracePeriod(), isFullyExpired(), hasFeature(), hasCapability(), activePackNames()maxSlots 僅為合約性質
LicenseValidator::buildVerifiedLicenseKey()array $data從一份已驗證的酬載建立一個有型別的 LicenseKeyLicenseKeyschema 違規時拋出 SpectrumAuthenticationException SPEC-AUTH-001支援 schema 2.0、1.0 與舊版酬載
PackDefinition / PackRegistry唯讀值物件具獨立到期與寬限的附加套件包狀態視情況而定isActive(), isFullyExpired(), activePacks(), activeCapabilities()
TrialPolicybool $enabled, int $maxPagesPerSecond = 2, watermark fields試用吞吐量上限原則fromLicenseKey(), disabled(), isThrottled();品牌標示權威仍歸評估器
ChannelEnforcementPolicy::enforce()LicenseKey $license, LocalState $state, int $systemNow, bool $revoked = false執行雙計時器機器,外加撤銷與試用重新標記EnforcementOutcome撤銷會凌駕每個計時器與試用狀態
OnlineCheckScheduler::evaluate(), ::recordSuccessfulOnlineCheck()License, local state, timestamps雙計時器評估;以已驗證的伺服器時間續租EnforcementOutcome / LocalStateONLINE_GRACE_SECONDS 在租約之後給予 48 小時的活躍寬限
EnforcementDecision / EnforcementReason / EnforcementOutcomeEnum 加唯讀值物件Active, Grace, DowngradedToCore 加上精確的原因每個原因都確定性地對應到一個決定
Runtime\EntitlementResolver::currentEntitlement()介面:執行階段所提供的、強制執行後的權益EntitlementResult由實作定義EnforcedEntitlementResolver 組合快取、狀態、原則與評估器,fail-closed 到 Core
LicenseStateCache::get(), ::getOrThrow()bool $forceRefresh = false支撐閘門的已驗證授權快取?LicenseKeygetOrThrow()SpectrumAuthenticationException SPEC-AUTH-008;接線無效時 LicenseConfigurationExceptioninvalidate(), isCacheValid()
LicenseClient::activate(), ::heartbeat(), ::deactivate(), ::verifyOnline()string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = null一次已簽署狀態交換;回應會對照釘選的根憑證驗證,並綁定到所送出的 nonceStatusResponseLicenseClientException(傳輸、非 200、所提供的 nonce 有誤);SpectrumAuthenticationException(偽造、竄改、過時、nonce 錯誤、授權錯誤、型別錯誤的回應)只會送出加鹽的指紋雜湊,絕不送出原始指紋
LicenseClient::checkRenewal()string $licenseId, string $customerId續約可用性探測;404 是正常的「沒有可用的」回答續約陣列(available, download_url, expires_atLicenseClientException(無法連線、非 200/404,或被原則拒絕的 download_url未簽署主體的 URL 會在能逸出之前先經過 SSRF 篩檢
LicenseClient::__construct()見簽章區塊在建構時驗證傳輸、URL scheme 與釘選集LicenseConfigurationException(不強制執行原則的傳輸、不允許的 scheme、無釘選的純 HTTP、格式錯誤的釘選集)getPinSet() 為輪替工具公開 active 的釘選集
Online\StatusResponse唯讀值物件已驗證的已簽署狀態revoked / expired / releasedisLive() 為 false;承載 leaseExpiresAt、席次計數與一份權益快照
LicenseChannelMode / OnlineMode / OnlinePolicyEnum 加唯讀值物件通道與線上原則 claimssigned_source 相對於 ioncube;線上模式 required / optional / disabled,附 intervalDaysleaseDays
LicenseEdition字串支援的 enumCore, Pro, Enterprisesatisfies() 實作層級階層
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

權益評估會產生五種當前狀態之一,每種都帶有一個固定的執行階段後果:

狀態執行階段生效能力更新/支援品牌標示
Active允許所授權的版本 + active 套件包是(付費);否(評估)無(付費);浮水印(評估)
GracePeriod允許所授權的版本 + active 套件包無(付費)
DowngradedToCore允許僅 Core無(付費);浮水印(試用)
EvaluationExpired受限浮水印
NoLicense停用(fail-closed)浮水印
  • 付費到期絕不會停用已安裝的執行階段。 runtimeAllowed 在每個付費狀態下都維持 true。超過寬限窗後,生效版本會降級為 Core:Core 能力無限期繼續運作、所有 Pro/Enterprise/套件包能力都會閘掉,而更新與支援會被撤銷。已棄用的 EntitlementStatus::PerpetualFallback case 指稱 6.0 之前的到期原則,僅為編譯相容而存在。
  • 並非每個狀態都以 Core 執行收場。 Grace 會保留完整授權的版本,附一則指名日期的續約警告。評估到期會限制執行階段並保留浮水印。no-license 狀態會 fail-closed 地停用 Enterprise 路徑,並對任何舊版輸出明顯加上浮水印,因此它絕不會被誤認為付費執行。
  • 固定的解析順序。 一份完全過期的授權不會解析出任何能力。套件包能力延後交由套件包自身的 active 狀態與獨立到期決定。版本能力則對照強制執行的生效版本、遵循嚴格的階層 Enterprise ⊇ Pro ⊇ Core 來解析。閘控絕不參照原始的 LicenseKey::$edition
  • 兩個計時器;最嚴格者勝出。 權益計時器(兩條通道皆適用)驅動 Active、Grace 與超過寬限後的 Core 降級。線上活躍計時器僅適用於線上模式為 requiredioncube 通道:租約加上 48 小時的活躍寬限必須為有效。在租約之後離線時,premium 會暫停於 Core 層級;稍後一次已驗證的線上檢查會重新建立租約,premium 隨即恢復。signed_source 通道——以及任何非 required 的線上模式——沒有活躍計時器,維持離線且具備 air-gap 能力。
  • 反回捲是確定性的。 強制執行會對照一個單調下限來評估:生效時間取系統時鐘與上次已驗證時間的最大值,因此時鐘往回調不會給予額外時間。一次超過偏移容差與剩餘寬限的回捲,會強制觸發 Core 降級。
  • 租約僅以受信任時間推進。 一次成功的線上檢查會記錄已驗證、已簽署的伺服器時間,絕不記錄本機時鐘,因此本機時鐘往前跳不會膨脹租約。
  • 品牌標示只有一個權威。 只有評估通道會觸發浮水印。付費授權在每個狀態下都解析為無品牌標示,包含降級後的狀態。
  • 試用是疊加在同一組計時器上的原則層。 吞吐量會被上限封頂(預設 2 pages/second)、評估浮水印會套用,而到期嚴格且不附寬限。只有回報的原因會改變;決定與生效版本仍依循付費機器。
  • 線上合約是端到端簽署的。 每個請求都帶有一個 CSPRNG 用戶端 nonce。每個回應都是媒體型別為 application/nextpdf-status+jwt 的 compact EdDSA JWS,經由 x5c 憑證鏈驗證回一個編入建置的釘選根憑證,並綁定到所送出的 nonce、已安裝的授權 id,以及所呼叫的端點。舊版未簽署封套傳輸已退役;恰好只剩一條信任路徑。所設定的 SPKI 釘選以 X-NextPDF-Pinned-Public-Key 標頭傳遞,而一個釘選集必須包含一個備援釘選。
  • 沒有執行階段席次強制執行。 maxSlots 僅為合約性質——一般運作沒有任何遙測,也沒有強制的回報主機(phone-home)。
  • 對一份完全過期的授權所做的能力檢查,會在任何套件包或版本邏輯執行之前,短路到「不可用」。
  • 一個附加套件包可能在基礎授權為 active 時就已過期。屆時拒絕會讀作套件包已過期(SPEC-LIC-002),而非未授權(SPEC-LIC-001),並列出目前 active 的套件包。
  • 一個存在但無法讀取或無法解析的本機強制執行狀態檔,是一個竄改訊號。機器會以 EnforcementReason::CorruptState fail-closed 到 Core 降級。一個正當缺席的檔案並非損毀,會正常繼續。
  • 一次低於單調下限、且超過偏移容差(預設 120 seconds)與剩餘寬限的時鐘回捲,會確定性地強制觸發 Core 降級。
  • 一份失效的活躍租約會使一份原本為 Active 的 ioncube 授權降級;而權益到期則無論租約狀態如何都會降級。
  • evaluate(null) 是 fail-closed:執行階段被禁止、浮水印會套用,而警告會指名定價 URL。需要未授權 Core 行為的主機必須直接建構 Core 引擎。
  • 一份過期的評估授權沒有寬限、也沒有回退;執行階段受限,而浮水印維持。
  • checkRenewal() 把 HTTP 404 視為正常的「沒有可用的」回答。任何其他非 200 都會拋出 LicenseClientException,而一個違反對外原則的 download_url 會在能逸出該方法之前先 fail-closed。
  • 一個偽造、竄改、過時、nonce 錯誤或授權錯誤的狀態回應絕不會產生 StatusResponse;驗證會拋出 SpectrumAuthenticationException。一個已簽署但為 revokedexpiredreleased 的狀態會通過驗證,並以降級訊號的形式浮現(isLive() 為 false)。
  • 一個為不同交換而鑄造的狀態回應會被拒絕:已驗證的 response_type 必須與所呼叫的端點相符。
  • FeatureGate 在任何解析器錯誤時都 fail-closed:生效版本降為 core,且不授予任何 premium 能力。
  • EnforcedEntitlementResolver 是端到端 fail-closed:其鏈中的任何例外都會產生 no-license(Core)結果與一筆 PSR-3 錯誤日誌,絕不授予 premium。

授權層不加入任何自有的密碼學原則。授權與狀態簽章是由主機密碼學提供者執行的 Ed25519 驗證。在一個受 FIPS 限制的建置中,提供者未核可的演算法會在密碼學邊界上以明確錯誤失敗;不會有任何東西默默降級。這些是關於 NextPDF 程式碼的能力聲明:NextPDF 並非經驗證的密碼學模組、不持有任何認證,也不授予任何認證。

聲明標準條款
授權檔案與狀態回應是 compact-serialization JWS,以 fail-closed 方式驗證。RFC 7515§3.1
授權與狀態簽章是 Ed25519。RFC 8032§5.1
已簽署回應中的 x5c 憑證鏈驗證回一個編入建置的釘選信任錨。RFC 5280§6.1
所設定的 SPKI 釘選集必須為一把尚未部署的金鑰包含一個備援釘選。RFC 7469§4.3
已驗證的 claims(issaudexpnbfiat)是已註冊的 claim 名稱。RFC 7519§4.1

所有條款皆為改寫;未重現任何規範性文字。NextPDF 不作任何認證聲明。 支援不等於一致性,而一致性不等於認證。本模組以能力的形式讓其行為與所引用的條款對齊;一份授權或狀態封套是否被接受,是由 NextPDF 自己的釘選根憑證驗證器決定,而非由外部權威決定。

  • 以一個強制執行原則的傳輸來建構 LicenseClient(正規做法是 SecurityAwareHttpClient)。原始的 PSR-18 用戶端會在建構時被拒絕,讓授權流量絕不會在缺少反 SSRF、不轉址、位元組上限與逾時控制的情況下送出。
  • 呼叫端提供的用戶端 nonce 必須解碼為至少 16 bytes 的熵。原始碼將此界限依據於 RFC 8555 §6.5;該條款位於所引用語料之外,因此此界限僅依產品原始碼在此陳述。
  • 透過 FeatureGate 閘控功能;絕不要依原始的 LicenseKey::$edition 分支。該閘門只參照強制執行的生效版本,並 fail-closed 到 core
  • 在新程式碼中不要對已棄用的 EntitlementStatus::PerpetualFallback 做 switch。請改為測試 isDowngradedToCore() 或比對 DowngradedToCore
  • 把一次能力拒絕視為一份補救酬載。請將它的結構化情境與升級 URL 呈現給呼叫端,而不要把它塌縮成一個泛用錯誤。
  • 本模組涉及密碼學功能;在你自己的審查中請將它視為安全敏感。容量與席次條款由授權協議規範,而非由執行階段強制執行。本參考並非法律意見;請洽詢你自己的合規與法律顧問。

本頁僅記載外部可觀察的行為與所支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表、runbook 檔名,以及工單前綴皆不在範圍內。