Pular para o conteúdo
getnextpdf.com

Enterprise edição

Licensing — Referência Profunda

Esta página é a referência aprofundada da superfície de licenciamento do NextPDF Enterprise — o módulo que resolve todas as outras capacidades do Enterprise. Ela cobre o modelo de estados de direito de uso (EntitlementEvaluator, EntitlementStatus, EntitlementResult), a restrição de capacidades imposta (FeatureGate, CapabilityCode, CapabilityRegistry), a máquina de imposição de canal de dois temporizadores (ChannelEnforcementPolicy, OnlineCheckScheduler) e o cliente on-line assinado (LicenseClient). A avaliação comum de direito de uso não precisa de rede. O cliente on-line existe para as operações explícitas de ativação, heartbeat, desativação, verificação on-line e sondagem de renovação. O detalhe de mecanismo interno permanece na documentação interna do repositório de origem e está fora do escopo deste manual.

Esta capacidade é distribuída no NextPDF Enterprise (nextpdf/enterprise) e é ativada com um envelope de licença de nível Enterprise. Uma implantação sem esse direito de uso não carrega as classes da capacidade. Compare edições e obtenha uma licença.

O licenciamento é uma superfície base do Enterprise. Ele está sempre presente assim que o pacote Enterprise é instalado ao lado do pacote Core, porque é a superfície que resolve todo o resto. O NextPDF Pro não tem uma superfície de direito de uso separada; o modelo de estados, a máquina de imposição e o cliente on-line são distribuídos apenas em nextpdf/enterprise. O NextPDF Core (Apache-2.0) não tem nenhum modelo de direito de uso — um host que precisa do comportamento Apache-2.0 sem licença usa o mecanismo Core diretamente, não o pipeline do Enterprise.

Todos os tipos ficam sob NextPDF\Enterprise\Licensing. A máquina de imposição fica no sub-namespace Channel, a composição de runtime em Runtime e os tipos de status assinado em Online.

SímboloParâmetrosComportamento padrãoRetornaLança ou falha comNotas
EntitlementEvaluator::evaluate()?LicenseKey $license, ?DateTimeImmutable $now = nullMapeia uma licença verificada (ou null) para a decisão completa de direito de usoEntitlementResultNenhumaUma licença null produz o resultado fail-closed de sem licença
EntitlementEvaluator::evaluateEnforced()?LicenseKey $license, EnforcementOutcome $outcomeConverte um resultado de imposição pré-computado em um resultado de direito de usoEntitlementResultNenhumaA edição efetiva vem do resultado; todo rebaixamento de imposição termina em Core
EntitlementEvaluator::resolveBrandingMode(), ::resolveBrandingStrategy()?LicenseKey $license, ?DateTimeImmutable $now = nullResolve a decisão de marca para a saída geradaBrandingMode / BrandingStrategyNenhumaAutoridade única de marca; apenas o canal de avaliação aplica marca d’água
EntitlementResultObjeto de valor readonlyCarrega status, edição, canal, modo de marca, sinalizadores de runtime/atualização/suporte e um aviso opcionalNenhumaAuxiliares: isFullyActive(), isExpired(), isDowngradedToCore(), shouldApplyEvaluationBranding()
EntitlementStatusEnum baseado em stringActive, GracePeriod, DowngradedToCore, EvaluationExpired, NoLicenseNenhumaPerpetualFallback é mantido, mas obsoleto; conservado apenas para que consumidores pré-6.0 ainda compilem
FeatureGate::hasCapability()CapabilityCode $capabilityVerifica a capacidade contra a edição efetiva imposta e o estado do pacoteboolNenhumaFail-closed para core em qualquer erro do resolvedor
FeatureGate::requireCapability()CapabilityCode $capabilityPassa silenciosamente ou lança com contexto estruturado de upsellvoidSpectrumAuthenticationException SPEC-LIC-001 (não licenciado) ou SPEC-LIC-002 (pacote expirado)O contexto carrega required_capability, required_pack, current_packs, upgrade_info_url
FeatureGate::isFeatureEnabled(), ::requireFeature()string $featureVerificação legada por identificador de recursobool / voidSpectrumAuthenticationException SPEC-AUTH-007 (caminho require)Compatibilidade legada; prefira verificações de capacidade
Acessores de FeatureGateNenhumIntrospecção de licençaVariaNenhumacurrentEdition(), isLicenseValid(), isInGracePeriod(), getActivePacks(), trialPolicy()
CapabilityCodeEnum baseado em stringIdentificadores canônicos de capacidade (core.*, pro.*, enterprise.*, pack.*)NenhumaisPack(), packName(), minimumEdition(), forEdition()
CapabilityRegistryLicenseKey, padrões de rotaResolução de rota para capacidade e busca de pacote antes do dispatchVariaNenhumaregisterDefaultRoutes() cobre as rotas de serviço documentadas
LicenseKeyObjeto de valor readonlyClaims de licença analisados e verificadosNenhumaisExpired(), isInGracePeriod(), isFullyExpired(), hasFeature(), hasCapability(), activePackNames(); maxSlots é apenas contratual
LicenseValidator::buildVerifiedLicenseKey()array $dataConstrói um LicenseKey tipado a partir de uma carga útil já verificadaLicenseKeySpectrumAuthenticationException SPEC-AUTH-001 em violação de schemaSuporta schema 2.0, 1.0 e cargas úteis legadas
PackDefinition / PackRegistryObjetos de valor readonlyEstado de pacote de complemento com expiração e carência independentesVariaNenhumaisActive(), isFullyExpired(), activePacks(), activeCapabilities()
TrialPolicybool $enabled, int $maxPagesPerSecond = 2, campos de marca d’águaPolítica de teto de taxa de processamento de avaliaçãoNenhumafromLicenseKey(), disabled(), isThrottled(); a autoridade de marca permanece com o avaliador
ChannelEnforcementPolicy::enforce()LicenseKey $license, LocalState $state, int $systemNow, bool $revoked = falseExecuta a máquina de dois temporizadores mais a revogação e a rerrotulagem de avaliaçãoEnforcementOutcomeNenhumaA revogação sobrepõe todo temporizador e estado de avaliação
OnlineCheckScheduler::evaluate(), ::recordSuccessfulOnlineCheck()Licença, estado local, timestampsAvaliação de dois temporizadores; renovação de lease a partir do tempo verificado do servidorEnforcementOutcome / LocalStateNenhumaONLINE_GRACE_SECONDS concede 48 horas de carência de atividade após o lease
EnforcementDecision / EnforcementReason / EnforcementOutcomeEnums + objeto de valor readonlyActive, Grace, DowngradedToCore mais o motivo precisoNenhumaCada motivo mapeia deterministicamente para uma decisão
Runtime\EntitlementResolver::currentEntitlement()NenhumInterface: o direito de uso imposto que o runtime serveEntitlementResultDefinido pela implementaçãoEnforcedEntitlementResolver compõe cache, estado, política e avaliador, fail-closed para Core
LicenseStateCache::get(), ::getOrThrow()bool $forceRefresh = falseCache de licença verificada que dá suporte ao gate?LicenseKeygetOrThrow(): SpectrumAuthenticationException SPEC-AUTH-008; LicenseConfigurationException em ligação inválidainvalidate(), isCacheValid()
LicenseClient::activate(), ::heartbeat(), ::deactivate(), ::verifyOnline()string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = nullUma troca de status assinado; a resposta é verificada contra a raiz fixada (pinned) e vinculada ao nonce enviadoStatusResponseLicenseClientException (transporte, não-200, nonce fornecido inválido); SpectrumAuthenticationException (resposta forjada, adulterada, desatualizada, com nonce incorreto, licença incorreta ou tipo incorreto)Apenas o hash da impressão digital com salt é enviado, nunca uma impressão digital bruta
LicenseClient::checkRenewal()string $licenseId, string $customerIdSondagem de disponibilidade de renovação; 404 é a resposta normal de “nenhuma disponível”Array de renovação (available, download_url, expires_at)LicenseClientException (inacessível, não-200/404 ou um download_url rejeitado pela política)A URL do corpo não assinado passa por triagem anti-SSRF antes de poder escapar
LicenseClient::__construct()Ver bloco de assinaturaValida o transporte, o esquema de URL e o conjunto de pins na construçãoLicenseConfigurationException (transporte que não impõe política, esquema não permitido, HTTP simples sem pins, conjunto de pins malformado)getPinSet() expõe o conjunto de pins ativo para ferramentas de rotação
Online\StatusResponseObjeto de valor readonlyO status assinado verificadoNenhumaisLive() é false em revoked / expired / released; carrega leaseExpiresAt, contagens de slots e um snapshot de direito de uso
LicenseChannelMode / OnlineMode / OnlinePolicyEnums + objeto de valor readonlyClaims de canal e de política on-lineNenhumasigned_source vs ioncube; modo on-line required / optional / disabled com intervalDays e leaseDays
LicenseEditionEnum baseado em stringCore, Pro, EnterpriseNenhumasatisfies() implementa a hierarquia de níveis
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

A avaliação de direito de uso produz um de cinco estados atuais, cada um com uma consequência fixa em tempo de execução:

StatusRuntimeCapacidades efetivasAtualizações / suporteMarca
Activepermitidoedição concedida + pacotes ativossim (paga); não (avaliação)nenhuma (paga); marca d’água (avaliação)
GracePeriodpermitidoedição concedida + pacotes ativossimnenhuma (paga)
DowngradedToCorepermitidoapenas Corenãonenhuma (paga); marca d’água (trial)
EvaluationExpiredrestritonenhumanãomarca d’água
NoLicensedesabilitado (fail-closed)nenhumanãomarca d’água
  • A expiração paga nunca desabilita o runtime instalado. runtimeAllowed permanece true para todo estado pago. Após a janela de carência, a edição efetiva é rebaixada para Core: as capacidades do Core continuam executando indefinidamente, todas as capacidades Pro/Enterprise/pacote são restringidas, e atualizações e suporte são revogados. O caso obsoleto EntitlementStatus::PerpetualFallback nomeia a política de expiração pré-6.0 e existe apenas para compatibilidade de compilação.
  • Nem todo estado termina em execução no Core. A carência mantém a edição concedida completa com um aviso de renovação com data. A expiração de avaliação restringe o runtime e mantém a marca d’água. O estado sem licença desabilita os caminhos do Enterprise de forma fail-closed e aplica marca d’água visível a qualquer saída legada, de modo que nunca possa passar por execução paga.
  • Ordem de resolução fixa. Uma licença totalmente expirada não resolve nenhuma capacidade. As capacidades de pacote recorrem ao próprio estado ativo e à expiração independente do pacote. As capacidades de edição são resolvidas contra a edição efetiva imposta, na hierarquia estrita Enterprise ⊇ Pro ⊇ Core. O LicenseKey::$edition bruto nunca é consultado para restrição.
  • Dois temporizadores; o mais restritivo vence. O temporizador de direito de uso (ambos os canais) determina Ativo, Carência e o rebaixamento para Core após a carência. O temporizador de atividade on-line aplica-se apenas ao canal ioncube com o modo on-line required: o lease, mais uma carência de atividade de 48 horas, deve estar ativo. Offline após o lease, o premium pausa no nível Core; uma verificação on-line verificada posterior restabelece o lease e o premium é retomado. O canal signed_source — e qualquer modo on-line não obrigatório — não tem temporizador de atividade e permanece offline e capaz de operar em air-gap.
  • O anti-rollback é determinístico. A imposição avalia contra um piso monotônico: o tempo efetivo é o máximo entre o relógio do sistema e o último tempo verificado, de modo que uma mudança de relógio para trás não concede tempo extra. Um rollback que excede a tolerância de desvio e a carência restante força o rebaixamento para Core.
  • Os leases avançam apenas com tempo confiável. Uma verificação on-line bem-sucedida registra o tempo do servidor verificado e assinado, nunca o relógio local, de modo que um salto do relógio local para frente não pode inflar o lease.
  • A marca tem uma única autoridade. Apenas o canal de avaliação aciona a marca d’água. Uma licença paga resolve para nenhuma marca em todos os estados, inclusive nos rebaixados.
  • A avaliação (trial) é uma camada de política sobre os mesmos temporizadores. A taxa de processamento é limitada (padrão de 2 páginas/segundo), a marca d’água de avaliação é aplicada, e a expiração é estrita, sem carência. Apenas o motivo relatado muda; a decisão e a edição efetiva seguem a máquina paga.
  • O contrato on-line é assinado de ponta a ponta. Cada requisição carrega um nonce de cliente CSPRNG. Cada resposta é um JWS EdDSA compacto de tipo de mídia application/nextpdf-status+jwt, verificado por uma cadeia x5c até uma raiz fixada compilada no código e vinculado ao nonce enviado, ao id da licença instalada e ao endpoint invocado. O transporte legado de envelope não assinado foi descontinuado; resta exatamente um caminho de confiança. Os pins SPKI configurados viajam no cabeçalho X-NextPDF-Pinned-Public-Key, e um conjunto de pins deve incluir um pin de backup.
  • Nenhuma imposição de assentos em tempo de execução. maxSlots é apenas contratual — sem telemetria e sem phone-home obrigatório para a operação comum.
  • Uma verificação de capacidade em uma licença totalmente expirada faz curto-circuito para “indisponível” antes que qualquer lógica de pacote ou edição seja executada.
  • Um pacote de complemento pode expirar enquanto a licença base está ativa. A negação passa então a ser pacote expirado (SPEC-LIC-002), não não licenciado (SPEC-LIC-001), e lista os pacotes atualmente ativos.
  • Um arquivo local de estado de imposição que está presente, mas ilegível ou não analisável, é um sinal de adulteração. A máquina falha fechada (fail-closed) para o rebaixamento para Core com EnforcementReason::CorruptState. Um arquivo legitimamente ausente não é corrompido e prossegue normalmente.
  • Um rollback de relógio abaixo do piso monotônico que excede a tolerância de desvio (padrão de 120 segundos) e a carência restante força o rebaixamento para Core de forma determinística.
  • Um lease de atividade expirado rebaixa uma licença ioncube que de outra forma estaria Ativa; a expiração de direito de uso rebaixa independentemente do estado do lease.
  • evaluate(null) é fail-closed: o runtime não é permitido, a marca d’água é aplicada, e o aviso nomeia a URL de preços. Hosts que precisam do comportamento Core sem licença devem construir o mecanismo Core diretamente.
  • Uma licença de avaliação expirada não tem carência nem fallback; o runtime fica restrito e a marca d’água permanece.
  • checkRenewal() trata o HTTP 404 como a resposta normal de “nenhuma disponível”. Qualquer outro não-200 lança LicenseClientException, e um download_url que viola a política de saída falha fechado antes de poder escapar do método.
  • Uma resposta de status forjada, adulterada, desatualizada, com nonce incorreto ou com licença incorreta nunca produz um StatusResponse; a verificação lança SpectrumAuthenticationException. Um status assinado, mas revoked, expired ou released, é verificado e se apresenta como um sinal de rebaixamento (isLive() é false).
  • Uma resposta de status emitida para uma troca diferente é rejeitada: o response_type verificado deve corresponder ao endpoint invocado.
  • FeatureGate falha fechado em qualquer erro do resolvedor: a edição efetiva é rebaixada para core e nenhuma capacidade premium é concedida.
  • EnforcedEntitlementResolver é fail-closed de ponta a ponta: qualquer exceção em sua cadeia produz o resultado sem licença (Core) e um log de erro PSR-3, nunca uma concessão premium.

A camada de licenciamento não adiciona nenhuma política criptográfica própria. As assinaturas de licença e de status são verificações Ed25519 realizadas pelo provedor de criptografia do host. Em um build com restrição FIPS, um algoritmo que o provedor não aprova falha no limite criptográfico com um erro explícito; nada é rebaixado silenciosamente. Estas são declarações de capacidade sobre o código do NextPDF: o NextPDF não é um módulo criptográfico validado, não possui nenhuma certificação e não concede nenhuma.

DeclaraçãoPadrãoCláusula
Os arquivos de licença e as respostas de status são JWS de serialização compacta, verificados de forma fail-closed.RFC 7515§3.1
As assinaturas de licença e de status são Ed25519.RFC 8032§5.1
A cadeia x5c em uma resposta assinada valida até uma âncora de confiança fixada compilada no código.RFC 5280§6.1
Um conjunto de pins SPKI configurado deve incluir um pin de backup para uma chave ainda não implantada.RFC 7469§4.3
Os claims verificados (iss, aud, exp, nbf, iat) são nomes de claim registrados.RFC 7519§4.1

Todas as cláusulas são parafraseadas; nenhum texto normativo é reproduzido. O NextPDF não faz nenhuma declaração de certificação. Suporte não é igual a conformidade, e conformidade não é igual a certificação. O módulo alinha seu comportamento com as cláusulas citadas como uma capacidade; a aceitação de um envelope de licença ou de status é decidida pelo próprio verificador de raiz fixada do NextPDF, não por uma autoridade externa.

  • Construa o LicenseClient com um transporte que imponha política (canonicamente SecurityAwareHttpClient). Um cliente PSR-18 bruto é rejeitado na construção, de modo que o tráfego de licença nunca possa ser enviado sem os controles anti-SSRF, de não redirecionamento, de limite de bytes e de tempo limite.
  • Um nonce de cliente fornecido pelo chamador deve decodificar para pelo menos 16 bytes de entropia. A origem fundamenta esse limite na RFC 8555 §6.5; essa cláusula está fora do corpus citado, então o limite é declarado aqui apenas a partir da origem do produto.
  • Restrinja recursos por meio de FeatureGate; nunca ramifique com base no LicenseKey::$edition bruto. O gate consulta apenas a edição efetiva imposta e falha fechado para core.
  • Não faça switch sobre o caso obsoleto EntitlementStatus::PerpetualFallback em código novo. Em vez disso, teste isDowngradedToCore() ou faça match em DowngradedToCore.
  • Trate uma negação de capacidade como uma carga útil de remediação. Apresente seu contexto estruturado e a URL de upgrade ao chamador em vez de reduzi-la a um erro genérico.
  • Este módulo diz respeito a funcionalidade criptográfica; trate-o como sensível à segurança em sua própria revisão. Os termos de capacidade e de assentos são regidos pelo contrato de licença, não pela imposição em tempo de execução. Esta referência não é um parecer jurídico; consulte seus próprios assessores de conformidade e jurídicos.

Esta página documenta apenas o comportamento observável externamente e a superfície pública de API suportada. Caminhos de namespace internos, classes auxiliares, tabelas de mecanismo, nomes de arquivo de runbook e prefixos de tíquete estão fora do escopo.