{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://spec.meridian-office.ru/license/license-file.schema.json",
  "title": "Meridian Office license file (.mlic), format 1",
  "description": "JSON-представление лицензионного файла .mlic. В файле контейнер и payload сериализуются в CBOR (RFC 8949): payload — встроенная байтовая строка (bstr), подписываемая как есть; схема применяется к развёрнутому JSON-виду (license_json в ответах API, вывод keygen/CLI) и к payload перед сериализацией на сервере. / JSON view of the .mlic license file. On disk the container and payload are CBOR; payload is an embedded byte string signed verbatim.",
  "type": "object",
  "required": ["v", "payload", "signature"],
  "additionalProperties": false,
  "properties": {
    "v": { "const": 1, "description": "Версия контейнера / container version" },
    "payload": { "$ref": "#/$defs/Payload" },
    "signature": { "$ref": "#/$defs/Signature" }
  },
  "$defs": {
    "Signature": {
      "type": "object",
      "required": ["alg", "key_id", "sig"],
      "additionalProperties": false,
      "properties": {
        "alg": { "const": "Ed25519" },
        "key_id": {
          "type": "string",
          "pattern": "^(mo-lic-[0-9a-f]{8}|srv-[0-9a-f]{8}|dev)$",
          "description": "mo-lic-<8hex> — ключ издателя (SHA-256 raw pubkey, первые 8 hex); srv-<8hex> — делегированный ключ on-prem сервера; dev — ключ устройства (только .mreq) / publisher, delegated server or device key id"
        },
        "sig": { "$ref": "#/$defs/Base64", "description": "64 байта Ed25519 над \"MRDN-LIC-v1\" ‖ payload bytes / 64-byte signature" }
      }
    },
    "Payload": {
      "type": "object",
      "required": [
        "format_version", "license_id", "product", "major_version", "issuer", "edition", "kind", "features", "seats",
        "holder", "issued_at", "valid_from", "expires_at", "grace_days", "update_channel", "update_until", "limits",
        "policy", "validation", "revocation_check_interval", "nonce"
      ],
      "additionalProperties": false,
      "properties": {
        "format_version": { "const": 1, "description": "Версия схемы payload / payload schema version" },
        "license_id": { "type": "string", "pattern": "^lic_[0-9A-HJKMNP-TV-Z]{26}$", "description": "lic_ + ULID" },
        "product": { "const": "meridian-office" },
        "major_version": { "type": "integer", "minimum": 1, "maximum": 99, "description": "Мажорная версия продукта, для которой действует лицензия / product major version" },
        "issuer": { "type": "string", "format": "uri", "pattern": "^https://", "description": "Базовый URL сервера, выдавшего лицензию / issuing server base URL" },
        "key_fingerprint": { "type": "string", "pattern": "^[0-9a-f]{32}$", "description": "Отпечаток ключа MRDN (см. license-key-format.md §4.5); отсутствует для покупок через аккаунт и trial" },
        "edition": { "$ref": "#/$defs/Edition" },
        "kind": { "$ref": "#/$defs/Kind" },
        "features": {
          "type": "array",
          "uniqueItems": true,
          "items": { "$ref": "#/$defs/Feature" },
          "description": "Явный список флагов; флаги ядра не передаются / explicit feature list, core flags omitted"
        },
        "seats": { "type": "integer", "minimum": 1, "maximum": 65535, "description": "Всего мест в праве / total seats in the entitlement" },
        "holder": { "$ref": "#/$defs/Holder" },
        "device": { "$ref": "#/$defs/Device", "description": "Обязательно для всех kind, кроме лицензии on-prem сервера (delegation) / required except for server licenses" },
        "issued_at": { "$ref": "#/$defs/DateTime" },
        "valid_from": { "$ref": "#/$defs/DateTime" },
        "expires_at": { "oneOf": [{ "$ref": "#/$defs/DateTime" }, { "type": "null" }], "description": "null — вечная лицензия / null = perpetual" },
        "grace_days": { "type": "integer", "minimum": 0, "maximum": 365, "description": "Льготный период после expires_at или последней успешной проверки / grace period in days" },
        "update_channel": { "type": "string", "enum": ["stable", "lts", "beta", "nightly"], "description": "Максимальный разрешённый канал обновлений / max allowed update channel" },
        "update_until": { "oneOf": [{ "$ref": "#/$defs/DateTime" }, { "type": "null" }], "description": "Для вечных — конец права на функциональные обновления; null — на весь срок / end of update entitlement for perpetual licenses" },
        "limits": { "$ref": "#/$defs/Limits" },
        "policy": { "$ref": "#/$defs/Policy" },
        "validation": { "$ref": "#/$defs/Validation" },
        "revocation_check_interval": { "type": "integer", "minimum": 0, "maximum": 31536000, "description": "Интервал проверки CRL, секунды; 0 — офлайн-лицензия / CRL check interval in seconds" },
        "float": { "$ref": "#/$defs/Float", "description": "Только kind = float_lease / only for floating leases" },
        "delegation": { "$ref": "#/$defs/Delegation", "description": "Только лицензия on-prem сервера / only for server licenses" },
        "nonce": { "$ref": "#/$defs/Base64", "description": "16 случайных байт / 16 random bytes" },
        "ext": { "type": "object", "description": "Расширения; неизвестные ключи игнорируются клиентом / extensions, unknown keys ignored" }
      },
      "allOf": [
        {
          "if": { "properties": { "kind": { "const": "float_lease" } } },
          "then": { "required": ["float", "device"] }
        },
        {
          "if": { "properties": { "delegation": { "type": "object" } }, "required": ["delegation"] },
          "then": { "properties": { "kind": { "enum": ["subscription", "perpetual"] }, "edition": { "const": "enterprise" } } },
          "else": { "required": ["device"] }
        },
        {
          "if": { "properties": { "kind": { "const": "perpetual" } } },
          "then": { "properties": { "expires_at": { "type": "null" } } }
        },
        {
          "if": { "properties": { "kind": { "enum": ["subscription", "trial", "float_lease", "volume", "partner"] } } },
          "then": { "properties": { "expires_at": { "$ref": "#/$defs/DateTime" } } }
        }
      ]
    },
    "Edition": { "type": "string", "enum": ["home", "pro", "business", "enterprise", "education", "trial"] },
    "Kind": { "type": "string", "enum": ["perpetual", "subscription", "volume", "trial", "partner", "float_lease"] },
    "Feature": {
      "type": "string",
      "description": "Имена Feature::* в snake_case; см. docs/10-licensing-accounts.md §2.2 / Feature::* names in snake_case",
      "enum": [
        "app_paint", "app_draw", "app_notes", "app_mail", "app_calendar", "app_base", "app_forms", "app_publisher", "app_plan",
        "pdf_edit", "pdf_forms", "pdf_sign", "pdf_convert", "pdf_ocr",
        "write_compare", "write_mail_merge", "write_master_doc", "write_bibliography",
        "sheets_external_data", "sheets_solver", "sheets_large_grid", "sheets_db_connectors",
        "slides_video_export", "slides_presenter_remote", "draw_vsdx_export", "draw_stencils_pro",
        "scripts_run", "scripts_edit", "scripts_store", "scripts_python", "scripts_vba_translate", "scripts_org_signed",
        "cloud_storage", "cloud_collab", "cloud_share", "cloud_version_history", "cloud_on_prem",
        "assist_local", "assist_cloud",
        "forms_publish", "forms_org_responses",
        "doc_sign", "doc_sign_gost", "doc_encrypt",
        "org_console", "org_sso", "org_policies", "org_key_distribution", "org_audit", "org_scim", "org_cloud_quota",
        "offline_activation", "floating_license", "volume_activation", "on_prem_server", "custom_build",
        "support_priority", "support_sla", "update_channel_beta", "update_channel_lts",
        "templates_premium", "template_store"
      ]
    },
    "Holder": {
      "type": "object",
      "required": ["display", "anonymous"],
      "additionalProperties": false,
      "properties": {
        "account_id": { "type": "string", "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$" },
        "org_id": { "type": "string", "pattern": "^org_[0-9A-HJKMNP-TV-Z]{26}$" },
        "display": { "type": "string", "maxLength": 120, "description": "Имя/название для показа; редактируемое / display name" },
        "anonymous": { "type": "boolean", "description": "true — право без аккаунта (ключ) / entitlement without an account" }
      },
      "oneOf": [
        { "required": ["account_id"] },
        { "required": ["org_id"] },
        { "properties": { "anonymous": { "const": true } }, "not": { "anyOf": [{ "required": ["account_id"] }, { "required": ["org_id"] }] } }
      ]
    },
    "Device": {
      "type": "object",
      "required": ["fingerprint_hash", "components", "os", "arch", "virtual"],
      "additionalProperties": false,
      "properties": {
        "fingerprint_hash": { "$ref": "#/$defs/Sha256Hex", "description": "SHA-256(SALT ‖ sorted component hashes)" },
        "components": {
          "type": "array", "minItems": 2, "maxItems": 3, "uniqueItems": true,
          "items": { "$ref": "#/$defs/Sha256Hex" },
          "description": "Хэши компонентов (ОС, плата, носитель), отсортированы; совпадение ≥ 2 из 3 / component hashes, match 2 of 3"
        },
        "components_meta": {
          "type": "array", "items": { "type": "string", "enum": ["os_id", "firmware_uuid", "disk_serial", "fallback_mac", "unavailable"] },
          "description": "Какие источники использованы (по позиции до сортировки — информативно) / which sources were used"
        },
        "name": { "type": "string", "maxLength": 64, "description": "Имя устройства, редактируемое пользователем / user-editable device name" },
        "os": { "type": "string", "enum": ["windows", "macos", "linux"] },
        "os_version": { "type": "string", "maxLength": 32 },
        "arch": { "type": "string", "enum": ["x86_64", "aarch64"] },
        "virtual": { "type": "boolean" },
        "weak_fingerprint": { "type": "boolean", "default": false, "description": "Меньше 3 стабильных компонентов / fewer than 3 stable components" },
        "user_scope": { "$ref": "#/$defs/Sha256Hex", "description": "SHA-256(SALT ‖ fingerprint_hash ‖ user SID/UID) при policy.license_scope = user (RDS/VDI)" }
      }
    },
    "Limits": {
      "type": "object",
      "additionalProperties": { "type": "integer", "minimum": 0 },
      "properties": {
        "devices": { "type": "integer", "minimum": 1, "maximum": 65535 },
        "cloud_quota_bytes": { "type": "integer", "minimum": 0 },
        "assist_requests_per_month": { "type": "integer", "minimum": 0 },
        "collab_participants": { "type": "integer", "minimum": 0 },
        "version_history_days": { "type": "integer", "minimum": 0 },
        "sheets_max_rows": { "type": "integer", "minimum": 0, "description": "0 — без ограничения / 0 = unlimited" }
      }
    },
    "Policy": {
      "type": "object",
      "description": "Политика организации (docs §8.7); для личных лицензий — {} / organization policy, {} for personal licenses",
      "additionalProperties": true,
      "properties": {
        "version": { "type": "integer", "minimum": 1 },
        "cloud": { "type": "string", "enum": ["allow", "deny", "onprem_only"] },
        "cloud_endpoint": { "type": "string", "format": "uri" },
        "sso_required": { "type": "boolean" },
        "mfa_required_roles": { "type": "array", "items": { "type": "string" } },
        "update_channel_max": { "type": "string", "enum": ["stable", "lts", "beta", "nightly"] },
        "update_defer_days": { "type": "integer", "minimum": 0, "maximum": 365 },
        "scripts": {
          "type": "object", "additionalProperties": false,
          "properties": {
            "run": { "type": "string", "enum": ["deny", "signed_only", "ask", "allow"] },
            "allowed_publishers": { "type": "array", "items": { "type": "string" } },
            "store": { "type": "boolean" },
            "python": { "type": "boolean" }
          }
        },
        "assist": { "type": "string", "enum": ["deny", "local_only", "cloud"] },
        "telemetry": { "type": "string", "enum": ["off", "crash_only", "full"] },
        "license_scope": { "type": "string", "enum": ["device", "user"] },
        "device_limit_per_user": { "type": "integer", "minimum": 1 },
        "deny_virtual_devices": { "type": "boolean" },
        "offline_grace_days": { "type": "integer", "minimum": 0, "maximum": 365 },
        "allowed_cidrs": { "type": "array", "items": { "type": "string" } },
        "data_region": { "type": "string", "enum": ["ru", "eu"] },
        "doc_defaults": { "type": "object" }
      }
    },
    "Validation": {
      "type": "object",
      "required": ["interval_days", "revocation_check_interval_days", "server_time_at_issue"],
      "additionalProperties": false,
      "properties": {
        "interval_days": { "type": "integer", "minimum": 0, "maximum": 365, "description": "Период онлайн-проверки; 0 — не требуется (офлайн, вечная без CRL) / online validation period, 0 = none" },
        "revocation_check_interval_days": { "type": "integer", "minimum": 0, "maximum": 365 },
        "server_time_at_issue": { "$ref": "#/$defs/DateTime", "description": "Серверное время выпуска — начальный якорь часов клиента / clock anchor" },
        "soft_expiry_days": { "type": "integer", "minimum": 0, "maximum": 30, "default": 7, "description": "Мягкий режим после ответа expired при наличии сети / soft mode after online 'expired'" }
      }
    },
    "Float": {
      "type": "object",
      "required": ["server_id", "lease_id", "lease_expires_at", "offline_reserve_until"],
      "additionalProperties": false,
      "properties": {
        "server_id": { "type": "string", "pattern": "^srv_[0-9A-HJKMNP-TV-Z]{26}$" },
        "pool": { "type": "string", "maxLength": 32 },
        "lease_id": { "type": "string", "pattern": "^lse_[0-9A-HJKMNP-TV-Z]{26}$" },
        "lease_expires_at": { "$ref": "#/$defs/DateTime", "description": "Конец аренды (60 мин от выдачи/продления) / lease end" },
        "offline_reserve_until": { "$ref": "#/$defs/DateTime", "description": "Офлайн-резерв (24 ч) или checkout до 30 дней / offline reserve" },
        "checkout": { "type": "boolean", "default": false },
        "server_license": { "$ref": "#/$defs/Base64", "description": "server.mlic издателя для проверки цепочки (CBOR, base64) / issuer-signed server license for chain validation" }
      }
    },
    "Delegation": {
      "type": "object",
      "required": ["delegate_pubkey", "delegate_key_id", "may_issue"],
      "additionalProperties": false,
      "properties": {
        "delegate_pubkey": { "$ref": "#/$defs/Base64", "description": "32 байта Ed25519 публичного ключа сервера / server public key" },
        "delegate_key_id": { "type": "string", "pattern": "^srv-[0-9a-f]{8}$" },
        "may_issue": { "type": "array", "uniqueItems": true, "items": { "type": "string", "enum": ["float_lease", "volume", "subscription"] } },
        "pools": {
          "type": "object", "additionalProperties": { "type": "integer", "minimum": 0 },
          "description": "Размеры пулов по имени: {\"float\": 200, \"volume\": 500} / pool sizes by name"
        },
        "max_lease_minutes": { "type": "integer", "minimum": 5, "maximum": 1440, "default": 60 },
        "max_offline_reserve_hours": { "type": "integer", "minimum": 0, "maximum": 720, "default": 24 },
        "max_checkout_days": { "type": "integer", "minimum": 0, "maximum": 90, "default": 30 }
      }
    },
    "DateTime": { "type": "string", "format": "date-time", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?Z$", "description": "RFC 3339, UTC, суффикс Z / UTC only" },
    "Sha256Hex": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
    "Base64": { "type": "string", "pattern": "^(base64:)?[A-Za-z0-9+/]+={0,2}$" }
  },
  "examples": [
    {
      "v": 1,
      "payload": {
        "format_version": 1,
        "license_id": "lic_01J9ZK4M2XQ8R7S6T5V4W3Y2Z1",
        "product": "meridian-office",
        "major_version": 1,
        "issuer": "https://license.meridian-office.ru",
        "key_fingerprint": "136acb0924097e5febcc424907458f8c",
        "edition": "pro",
        "kind": "subscription",
        "features": ["app_paint", "app_draw", "app_notes", "app_mail", "app_calendar", "app_base", "app_forms", "pdf_edit", "pdf_forms", "pdf_sign", "pdf_convert", "scripts_run", "scripts_edit", "scripts_store", "scripts_python", "cloud_storage", "cloud_collab", "cloud_share", "cloud_version_history", "assist_local", "assist_cloud", "doc_sign", "doc_encrypt", "support_priority", "update_channel_beta"],
        "seats": 5,
        "holder": { "account_id": "usr_01J9ZJX0A1B2C3D4E5F6G7H8J9", "display": "Иван Петров", "anonymous": false },
        "device": {
          "fingerprint_hash": "0d9c1f3e9b2f7f1b6f0a3f6b4e1b9b6a0f2b7c8d9e1f2a3b4c5d6e7f8a9b0c1d",
          "components": ["1c3f2e4d5b6a79880f1e2d3c4b5a69788796a5b4c3d2e1f00f1e2d3c4b5a6978", "7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"],
          "components_meta": ["os_id", "firmware_uuid", "disk_serial"],
          "name": "IVAN-DESKTOP", "os": "windows", "os_version": "11.0.26100", "arch": "x86_64", "virtual": false
        },
        "issued_at": "2027-02-01T10:15:30Z",
        "valid_from": "2027-02-01T00:00:00Z",
        "expires_at": "2028-02-01T00:00:00Z",
        "grace_days": 30,
        "update_channel": "beta",
        "update_until": null,
        "limits": { "devices": 5, "cloud_quota_bytes": 107374182400, "assist_requests_per_month": 2000, "version_history_days": 90 },
        "policy": {},
        "validation": { "interval_days": 7, "revocation_check_interval_days": 7, "server_time_at_issue": "2027-02-01T10:15:30Z", "soft_expiry_days": 7 },
        "revocation_check_interval": 604800,
        "nonce": "base64:7dX1k2Zq3n8w0Jk5Lm9pQg=="
      },
      "signature": { "alg": "Ed25519", "key_id": "mo-lic-ce69679b", "sig": "Ze92SkziiShJsvvPq1R/0RobS3yOd1IvqIqYQ0Ozmn4BksVyY2fvZL0/JA6eSgxPrj3quVt5sZ9IhZ1zKwU6BQ==" }
    },
    {
      "v": 1,
      "payload": {
        "format_version": 1,
        "license_id": "lic_01J9ZM7Q0P1R2S3T4V5W6X7Y8Z",
        "product": "meridian-office",
        "major_version": 1,
        "issuer": "https://license.meridian-office.ru",
        "key_fingerprint": "2b55530fe3a20f6fc38a3b13dcc983cc",
        "edition": "home",
        "kind": "perpetual",
        "features": ["app_paint", "app_draw", "app_notes", "app_mail", "app_calendar", "app_forms", "pdf_edit", "pdf_forms", "scripts_run", "scripts_edit", "scripts_store"],
        "seats": 3,
        "holder": { "display": "Ключ MRDN-28800-…-T2E7W", "anonymous": true },
        "device": {
          "fingerprint_hash": "5b1d7e9f0a2c4e6a8c0e2a4c6e8a0c2e4a6c8e0a2c4e6a8c0e2a4c6e8a0c2e4a",
          "components": ["0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9", "9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a0"],
          "components_meta": ["os_id", "disk_serial", "unavailable"],
          "name": "home-laptop", "os": "linux", "os_version": "ubuntu 26.04", "arch": "x86_64", "virtual": false, "weak_fingerprint": true
        },
        "issued_at": "2027-03-16T09:12:44Z",
        "valid_from": "2027-03-16T00:00:00Z",
        "expires_at": null,
        "grace_days": 0,
        "update_channel": "stable",
        "update_until": "2029-03-16T00:00:00Z",
        "limits": { "devices": 3, "sheets_max_rows": 1000000 },
        "policy": {},
        "validation": { "interval_days": 30, "revocation_check_interval_days": 30, "server_time_at_issue": "2027-03-16T09:12:44Z" },
        "revocation_check_interval": 2592000,
        "nonce": "base64:Qm9yaW5nTm9uY2VCeXRlcw=="
      },
      "signature": { "alg": "Ed25519", "key_id": "mo-lic-ce69679b", "sig": "base64:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" }
    }
  ]
}
