Enterprise редакция
Licensing — глубокий справочник
Эта страница — глубокий справочник по поверхности лицензирования NextPDF Enterprise, модулю, который разрешает все остальные возможности Enterprise. Она охватывает модель состояний прав (EntitlementEvaluator, EntitlementStatus, EntitlementResult), навязываемое закрытие возможностей (FeatureGate, CapabilityCode, CapabilityRegistry), машину навязывания канала с двумя таймерами (ChannelEnforcementPolicy, OnlineCheckScheduler) и подписанный онлайн-клиент (LicenseClient). Обычная оценка прав не требует сети. Онлайн-клиент существует для явных операций активации, контрольного сигнала, деактивации, онлайн-проверки и зондирования продления. Детали внутреннего механизма остаются во внутренней документации исходного репозитория и вне области действия этого руководства.
Доступность и лицензирование
Заголовок раздела «Доступность и лицензирование»Эта возможность поставляется в NextPDF Enterprise (nextpdf/enterprise) и активируется лицензионным конвертом уровня Enterprise. Развёртывание без этого права не загружает классы возможности. Сравнить редакции и получить лицензию.
Лицензирование — это базовая поверхность Enterprise. Она всегда присутствует, как только пакет Enterprise установлен рядом с пакетом Core, потому что именно эта поверхность разрешает всё остальное. У NextPDF Pro нет отдельной поверхности прав; модель состояний, машина навязывания и онлайн-клиент поставляются только в nextpdf/enterprise. У NextPDF Core (Apache-2.0) вообще нет модели прав — хост, которому нужно нелицензированное поведение Apache-2.0, использует движок Core напрямую, а не конвейер Enterprise.
Публичная поверхность API
Заголовок раздела «Публичная поверхность API»Все типы находятся в NextPDF\Enterprise\Licensing. Машина навязывания расположена в подпространстве имён Channel, компоновка runtime — в Runtime, а типы подписанного статуса — в Online.
| Символ | Параметры | Поведение по умолчанию | Возвращает | Бросает или проваливается с | Примечания |
|---|---|---|---|---|---|
EntitlementEvaluator::evaluate() | ?LicenseKey $license, ?DateTimeImmutable $now = null | Сопоставляет проверенную лицензию (или null) с полным решением о правах | EntitlementResult | Нет | Null-лицензия даёт fail-closed-результат без лицензии |
EntitlementEvaluator::evaluateEnforced() | ?LicenseKey $license, EnforcementOutcome $outcome | Преобразует заранее вычисленный исход навязывания в результат о правах | EntitlementResult | Нет | Эффективная редакция берётся из исхода; каждое понижение при навязывании приводит к Core |
EntitlementEvaluator::resolveBrandingMode(), ::resolveBrandingStrategy() | ?LicenseKey $license, ?DateTimeImmutable $now = null | Разрешает решение о брендировании для генерируемого вывода | BrandingMode / BrandingStrategy | Нет | Единственная инстанция брендирования; водяной знак ставит только канал ознакомления |
EntitlementResult | Объект-значение только для чтения | Несёт статус, редакцию, канал, режим брендирования, флаги runtime/обновлений/поддержки и необязательное предупреждение | — | Нет | Хелперы: isFullyActive(), isExpired(), isDowngradedToCore(), shouldApplyEvaluationBranding() |
EntitlementStatus | Перечисление на основе строк | Active, GracePeriod, DowngradedToCore, EvaluationExpired, NoLicense | — | Нет | PerpetualFallback сохранён, но устарел; оставлен только чтобы потребители до 6.0 всё ещё компилировались |
FeatureGate::hasCapability() | CapabilityCode $capability | Проверяет возможность против навязываемой эффективной редакции и состояния пакетов | bool | Нет | Fail-closed до core при любой ошибке резолвера |
FeatureGate::requireCapability() | CapabilityCode $capability | Молча пропускает или бросает со структурированным контекстом апсейла | void | SpectrumAuthenticationException SPEC-LIC-001 (не лицензировано) или SPEC-LIC-002 (пакет истёк) | Контекст несёт required_capability, required_pack, current_packs, upgrade_info_url |
FeatureGate::isFeatureEnabled(), ::requireFeature() | string $feature | Устаревшая проверка по идентификатору функции | bool / void | SpectrumAuthenticationException SPEC-AUTH-007 (путь require) | Обратная совместимость; предпочитайте проверки возможностей |
Аксессоры FeatureGate | Нет | Интроспекция лицензии | Разное | Нет | currentEdition(), isLicenseValid(), isInGracePeriod(), getActivePacks(), trialPolicy() |
CapabilityCode | Перечисление на основе строк | Канонические идентификаторы возможностей (core.*, pro.*, enterprise.*, pack.*) | — | Нет | isPack(), packName(), minimumEdition(), forEdition() |
CapabilityRegistry | LicenseKey, шаблоны маршрутов | Разрешение «маршрут → возможность» и поиск пакета до диспетчеризации | Разное | Нет | registerDefaultRoutes() охватывает задокументированные маршруты служб |
LicenseKey | Объект-значение только для чтения | Разобранные, проверенные утверждения лицензии | — | Нет | isExpired(), isInGracePeriod(), isFullyExpired(), hasFeature(), hasCapability(), activePackNames(); maxSlots только договорной |
LicenseValidator::buildVerifiedLicenseKey() | array $data | Строит типизированный LicenseKey из уже проверенной нагрузки | LicenseKey | SpectrumAuthenticationException SPEC-AUTH-001 при нарушении схемы | Поддерживает схемы 2.0, 1.0 и устаревшие нагрузки |
PackDefinition / PackRegistry | Объекты-значения только для чтения | Состояние пакета дополнений с независимым истечением и льготным периодом | Разное | Нет | isActive(), isFullyExpired(), activePacks(), activeCapabilities() |
TrialPolicy | bool $enabled, int $maxPagesPerSecond = 2, поля водяного знака | Политика ограничения пропускной способности пробного режима | — | Нет | fromLicenseKey(), disabled(), isThrottled(); полномочия брендирования остаются у оценщика |
ChannelEnforcementPolicy::enforce() | LicenseKey $license, LocalState $state, int $systemNow, bool $revoked = false | Запускает машину с двумя таймерами плюс отзыв и переобозначение пробного режима | EnforcementOutcome | Нет | Отзыв перекрывает каждый таймер и состояние пробного режима |
OnlineCheckScheduler::evaluate(), ::recordSuccessfulOnlineCheck() | Лицензия, локальное состояние, отметки времени | Оценка двух таймеров; продление аренды по проверенному серверному времени | EnforcementOutcome / LocalState | Нет | ONLINE_GRACE_SECONDS даёт 48 часов льготы жизнеспособности сверх аренды |
EnforcementDecision / EnforcementReason / EnforcementOutcome | Перечисления + объект-значение только для чтения | Active, Grace, DowngradedToCore плюс точная причина | — | Нет | Каждая причина детерминированно отображается в одно решение |
Runtime\EntitlementResolver::currentEntitlement() | Нет | Интерфейс: навязываемое право, которое обслуживает runtime | EntitlementResult | Определяется реализацией | EnforcedEntitlementResolver компонует кэш, состояние, политику и оценщик, fail-closed до Core |
LicenseStateCache::get(), ::getOrThrow() | bool $forceRefresh = false | Кэш проверенной лицензии, обеспечивающий работу гейта | ?LicenseKey | getOrThrow(): SpectrumAuthenticationException SPEC-AUTH-008; LicenseConfigurationException при неверной проводке | invalidate(), isCacheValid() |
LicenseClient::activate(), ::heartbeat(), ::deactivate(), ::verifyOnline() | string $licenseJws, string $deploymentId, ?string $machineFingerprintHash = null, ?string $expectedLicenseId = null, ?string $clientNonce = null | Один обмен подписанным статусом; ответ проверяется против закреплённого корня и привязан к отправленному nonce | StatusResponse | LicenseClientException (транспорт, не-200, неверный поданный nonce); SpectrumAuthenticationException (подделанный, изменённый, устаревший, с неверным nonce, неверной лицензией, неверным типом ответа) | Отправляется только солёный хеш отпечатка, никогда сырой отпечаток |
LicenseClient::checkRenewal() | string $licenseId, string $customerId | Зондирование доступности продления; 404 — нормальный ответ «нет доступных» | Массив продления (available, download_url, expires_at) | LicenseClientException (недостижимо, не-200/404 или отклонённый политикой download_url) | URL в неподписанном теле проверяется на SSRF, прежде чем сможет выйти наружу |
LicenseClient::__construct() | См. блок с сигнатурой | Проверяет транспорт, схему URL и набор закреплений при конструировании | — | LicenseConfigurationException (транспорт без навязывания политики, недопустимая схема, простой HTTP без закреплений, некорректный набор закреплений) | getPinSet() раскрывает активный набор закреплений для инструментов ротации |
Online\StatusResponse | Объект-значение только для чтения | Проверенный подписанный статус | — | Нет | isLive() равен false при revoked / expired / released; несёт leaseExpiresAt, счётчики мест и снимок прав |
LicenseChannelMode / OnlineMode / OnlinePolicy | Перечисления + объект-значение только для чтения | Утверждения канала и онлайн-политики | — | Нет | signed_source против ioncube; онлайн-режим required / optional / disabled с intervalDays и leaseDays |
LicenseEdition | Перечисление на основе строк | Core, Pro, Enterprise | — | Нет | satisfies() реализует иерархию уровней |
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): arrayКонтракт поведения
Заголовок раздела «Контракт поведения»Оценка прав производит одно из пяти текущих состояний, каждое с фиксированным следствием для runtime:
| Статус | Runtime | Эффективные возможности | Обновления / поддержка | Брендирование |
|---|---|---|---|---|
Active | разрешён | лицензированная редакция + активные пакеты | да (платная); нет (ознакомление) | нет (платная); водяной знак (ознакомление) |
GracePeriod | разрешён | лицензированная редакция + активные пакеты | да | нет (платная) |
DowngradedToCore | разрешён | только Core | нет | нет (платная); водяной знак (пробный) |
EvaluationExpired | ограничен | нет | нет | водяной знак |
NoLicense | отключён (fail-closed) | нет | нет | водяной знак |
- Истечение платной лицензии никогда не отключает установленный runtime.
runtimeAllowedостаётся true для каждого платного состояния. За пределами окна льготного периода эффективная редакция понижается до Core: возможности Core продолжают работать бессрочно, все возможности Pro/Enterprise/пакетов закрываются, а обновления и поддержка отзываются. Устаревший случайEntitlementStatus::PerpetualFallbackназывает политику истечения до 6.0 и существует только для совместимости компиляции. - Не каждое состояние заканчивается исполнением на уровне Core. Льготный период сохраняет полную лицензированную редакцию с датированным предупреждением о продлении. Истечение ознакомления ограничивает runtime и сохраняет водяной знак. Состояние без лицензии отключает пути Enterprise по принципу fail-closed и заметно помечает водяным знаком любой унаследованный вывод, поэтому его никогда нельзя принять за платное исполнение.
- Фиксированный порядок разрешения. Полностью истёкшая лицензия не разрешает ни одной возможности. Возможности пакетов откладываются до собственного активного состояния и независимого истечения пакета. Возможности редакции разрешаются против навязываемой эффективной редакции по строгой иерархии Enterprise ⊇ Pro ⊇ Core. Сырое
LicenseKey::$editionникогда не используется для закрытия. - Два таймера; побеждает самый строгий. Таймер прав (оба канала) управляет Active, Grace и понижением до Core за пределами льготного периода. Таймер онлайн-жизнеспособности применяется только к каналу
ioncubeс онлайн-режимомrequired: аренда плюс 48-часовая льгота жизнеспособности должны быть действующими. В офлайне за пределами аренды premium приостанавливается на уровне Core; более поздняя проверенная онлайн-проверка восстанавливает аренду, и premium возобновляется. У каналаsigned_source— и у любого необязательного онлайн-режима — нет таймера жизнеспособности, и он остаётся офлайн- и air-gap-способным. - Противодействие откату детерминировано. Навязывание оценивается против монотонного пола: эффективное время — это максимум системных часов и последнего проверенного времени, поэтому перевод часов назад не даёт лишнего времени. Откат, превышающий допуск расхождения и оставшийся льготный период, принудительно вызывает понижение до Core.
- Аренда продвигается только по доверенному времени. Успешная онлайн-проверка записывает проверенное, подписанное серверное время, а не локальные часы, поэтому локальный скачок часов вперёд не может раздуть аренду.
- У брендирования одна инстанция. Водяной знак включает только канал ознакомления. Платная лицензия разрешается без брендирования в каждом состоянии, включая понижённые.
- Пробный режим — это слой политики поверх тех же таймеров. Пропускная способность ограничена (по умолчанию 2 страницы/секунду), применяется ознакомительный водяной знак, а истечение строгое, без льготного периода. Меняется только сообщаемая причина; решение и эффективная редакция следуют платной машине.
- Онлайн-контракт подписан от начала до конца. Каждый запрос несёт CSPRNG-nonce клиента. Каждый ответ — это компактный EdDSA JWS с медиатипом
application/nextpdf-status+jwt, проверяемый по цепочке x5c до вкомпилированного закреплённого корня и привязанный к отправленному nonce, идентификатору установленной лицензии и вызванной конечной точке. Унаследованный транспорт неподписанного конверта выведен из эксплуатации; остаётся ровно один путь доверия. Настроенные SPKI-закрепления передаются в заголовкеX-NextPDF-Pinned-Public-Key, и набор закреплений должен включать резервное закрепление. - Нет навязывания числа мест во время выполнения.
maxSlotsтолько договорной — нет телеметрии и обязательного отзвона для обычной работы.
Граничные случаи и режимы сбоя
Заголовок раздела «Граничные случаи и режимы сбоя»- Проверка возможности на полностью истёкшей лицензии замыкается на «недоступно» до запуска любой логики пакета или редакции.
- Пакет дополнений может истечь, пока базовая лицензия активна. Отказ тогда читается как «пакет истёк» (
SPEC-LIC-002), а не «не лицензировано» (SPEC-LIC-001), и перечисляет текущие активные пакеты. - Локальный файл состояния навязывания, который присутствует, но нечитаем или неразбираем, — это сигнал вмешательства. Машина проваливается закрыто до понижения Core с
EnforcementReason::CorruptState. Законно отсутствующий файл не считается повреждённым и обрабатывается нормально. - Откат часов ниже монотонного пола, превышающий допуск расхождения (по умолчанию 120 секунд) и оставшийся льготный период, детерминированно вызывает понижение до Core.
- Истёкшая аренда жизнеспособности понижает в остальном Active-лицензию
ioncube; истечение прав понижает независимо от состояния аренды. evaluate(null)работает по принципу fail-closed: runtime запрещён, применяется водяной знак, а предупреждение называет URL с ценами. Хосты, которым нужно нелицензированное поведение Core, должны конструировать движок Core напрямую.- У истёкшей ознакомительной лицензии нет ни льготного периода, ни резервного режима; runtime ограничен, и водяной знак остаётся.
checkRenewal()трактует HTTP 404 как нормальный ответ «нет доступных». Любой другой не-200 поднимаетLicenseClientException, аdownload_url, нарушающий исходящую политику, проваливается закрыто, прежде чем сможет покинуть метод.- Подделанный, изменённый, устаревший, с неверным nonce или неверной лицензией статус-ответ никогда не даёт
StatusResponse; проверка бросаетSpectrumAuthenticationException. Подписанный, ноrevoked,expiredилиreleasedстатус проходит проверку и всплывает как сигнал понижения (isLive()равен false). - Статус-ответ, выпущенный для другого обмена, отклоняется: проверенный
response_typeдолжен совпадать с вызванной конечной точкой. FeatureGateпроваливается закрыто при любой ошибке резолвера: эффективная редакция деградирует доcore, и ни одна premium-возможность не предоставляется.EnforcedEntitlementResolverработает по принципу fail-closed от начала до конца: любое исключение в его цепочке даёт результат без лицензии (Core) и запись ошибки PSR-3, никогда не premium-предоставление.
Поведение в режиме FIPS
Заголовок раздела «Поведение в режиме FIPS»Слой лицензирования не добавляет собственной криптографической политики. Подписи лицензии и статуса — это проверки Ed25519, выполняемые криптопровайдером хоста. В FIPS-ограниченной сборке алгоритм, который провайдер не одобряет, проваливается на криптографической границе с явной ошибкой; ничто не понижается молча. Это утверждения о возможностях кода NextPDF: NextPDF не является валидированным криптографическим модулем, не имеет сертификации и не предоставляет её.
Соответствие
Заголовок раздела «Соответствие»| Утверждение | Стандарт | Пункт |
|---|---|---|
| Файлы лицензий и статус-ответы — это JWS компактной сериализации, проверяемые по принципу fail-closed. | RFC 7515 | §3.1 |
| Подписи лицензии и статуса — Ed25519. | RFC 8032 | §5.1 |
| Цепочка x5c в подписанном ответе валидируется обратно до вкомпилированного закреплённого якоря доверия. | RFC 5280 | §6.1 |
| Настроенный набор SPKI-закреплений должен включать резервное закрепление для ещё не развёрнутого ключа. | RFC 7469 | §4.3 |
Проверенные утверждения (iss, aud, exp, nbf, iat) — зарегистрированные имена утверждений. | RFC 7519 | §4.1 |
Все пункты пересказаны; нормативный текст не воспроизводится. NextPDF не делает заявления о сертификации. Поддержка не равна соответствию, а соответствие не равно сертификации. Модуль согласует своё поведение с процитированными пунктами как возможность; принятие лицензионного или статусного конверта решает собственный верификатор NextPDF с закреплённым корнем, а не внешняя инстанция.
Замечания по разработке
Заголовок раздела «Замечания по разработке»- Конструируйте
LicenseClientс транспортом, навязывающим политику (каноническиSecurityAwareHttpClient). Сырой PSR-18-клиент отклоняется при конструировании, чтобы лицензионный трафик никогда нельзя было отправить без средств контроля anti-SSRF, без перенаправлений, с ограничением байтов и тайм-аутами. - Поданный вызывающим клиентский nonce должен декодироваться минимум в 16 байт энтропии. Исходный код обосновывает эту границу в RFC 8555 §6.5; этот пункт вне процитированного корпуса, поэтому граница указана здесь только по исходному коду продукта.
- Закрывайте функции через
FeatureGate; никогда не ветвитесь по сыромуLicenseKey::$edition. Гейт обращается только к навязываемой эффективной редакции и проваливается закрыто доcore. - Не переключайтесь по устаревшему
EntitlementStatus::PerpetualFallbackв новом коде. Вместо этого проверяйтеisDowngradedToCore()или сопоставляйтеDowngradedToCore. - Трактуйте отказ в возможности как полезную нагрузку для устранения. Выводите её структурированный контекст и URL обновления вызывающему, а не сворачивайте до общей ошибки.
- Этот модуль касается криптографической функциональности; трактуйте его как чувствительный к безопасности в собственной проверке. Условия по ёмкости и местам регулируются лицензионным соглашением, а не навязыванием во время выполнения. Этот справочник не является юридическим заключением; обратитесь к собственным консультантам по соответствию и юридическим вопросам.
Граница публикации
Заголовок раздела «Граница публикации»Эта страница документирует только внешне наблюдаемое поведение и поддерживаемую публичную поверхность API. Внутренние пути пространств имён, вспомогательные классы, таблицы механизмов, имена файлов руководств по эксплуатации и префиксы тикетов вне области действия.
См. также
Заголовок раздела «См. также»- Licensing — NextPDF Enterprise — страница возможности с руководством по настройке и интеграции.
- Billing — глубокий справочник — уровни тарифов, политики превышения и перенос.
- SaaS — глубокий справочник — многоарендная сервисная поверхность, которую охраняет карта маршрутов.
- Branding — глубокий справочник — стратегии брендирования, которые разрешает оценщик.