$schema: 'http://json-schema.org/draft-07/schema#'
description: Threema OnPrem Provision File (OPPF) Format
type: object
properties:
  version:
    type: string
    description: OPPF file format version, currently always `1.0`
    examples:
      - '1.0'
  signatureKey:
    type: string
    description: A 32 byte, base64 encoded Ed25519 public key
    examples:
      - ek1qBp4DyRmLL9J5sCmsKSfwbsiGNB4veDAODjkwe/k=
  refresh:
    type: integer
    description: |-
      The refresh interval in seconds

      Clients should fetch the OPPF after the specified amount of time has
      passed.
    minimum: 1800
    examples:
      - 86400
  license:
    type: object
    description: OnPrem license information
    properties:
      id:
        type: string
        description: License ID, for internal use only
      expires:
        type: string
        description: |-
          An ISO-Date that holds the expiration date of the license

          Clients should not accept the OPPF after this date.
        examples:
          - '2024-03-15'
      count:
        type: integer
        description: |-
          The number of licenses in the package

          Servers should not accept more user accounts (active Threema IDs) than
          this.
        examples:
          - 1000
    required:
      - id
      - expires
      - count
  domains:
    type: object
    description: |-
      Configure domains accessed by the Threema clients.

      If this key is missing, then no constraints are applied.
    properties:
      rules:
        type: array
        items:
          type: object
          description: |-
            Domain configuration rule to be applied to a domain (and potentially
            subdomains).

            Note: Generally, rules are applied on a first-match basis. However, the
            exact order of which SPKI will be applied is not well-defined and
            depends on the underlying platform.

            When processing this entry:

            1. If `matchMode` is unknown, log a warning and abort these steps.
            2. If `spkis` is present, run the associated steps for each entry.
          properties:
            fqdn:
              type: string
              description: An FQDN
            matchMode:
              type: string
              description: How to match domains and apply the respective rules.
              anyOf:
                - title: Exact
                  description: The rule shall only be applied to the exact FQDN.
                  const: exact
                - title: Include subdomains
                  description:
                    The rule shall be applied to all subdomains recursively.
                  const: include-subdomains
                - {}
            spkis:
              type: array
              items:
                type: object
                description: |-
                  SPKI for certificate pinning to be applied to one or more domains.

                  When processing this entry:

                  1. Let `fqdn` and `matchMode` be the associated domain's FQDN and
                    match mode.
                  2. If `algorithm` is unknown, log a warning and abort these steps.
                  3. Pin the SPKI to `fqdn` according to `matchMode`. All subsequent
                    TLS-based communication must match the SPKI or be rejected.
                properties:
                  value:
                    type: string
                    description: The base64 encoded public key hash
                    examples:
                      - 'DTJU4+0HObYPrx9lF4Kz8hhjcJL3WBL4k829L++UlSk='
                  algorithm:
                    type: string
                    description: The SPKI hashing algorithm.
                    anyOf:
                      - const: sha256
                      - {}
                required:
                  - value
                  - algorithm
          required:
            - fqdn
            - matchMode
          examples:
            - fqdn: threemaonprem.initrode.com
              matchMode: include-subdomains
              spkis:
                - value: 'DTJU4+0HObYPrx9lF4Kz8hhjcJL3WBL4k829L++UlSk='
                  algorithm: sha256
                - value: 'C19RmQgZXzwovKRRJ2st7bsokiRchKcYjBo3m63fvn8='
                  algorithm: sha256
            - fqdn: another-host.initrode.com
              matchMode: exact
              spkis:
                - value: 'XIglSWPJ6aJ7LeIz6KsOrr0fNgNZ0PzGgDCDEZq5/U4='
                  algorithm: sha256
    required:
      - rules
  chat:
    type: object
    description: Configuration for the chat server
    properties:
      hostname:
        type: string
        description: Chat server hostname
        examples:
          - threemaonprem.initrode.com
      publicKey:
        type: string
        description:
          The 32-byte, base64 encoded permanent public key of the chat server
        examples:
          - r9utIHN9ngo21q9OlZcotsQu1f2HwAW2Wi+u6Psp4Wc=
      ports:
        type: array
        items:
          type: integer
          minimum: 1
          maximum: 65535
        description: Array of chat server ports
        examples:
          - [5222]
    required:
      - hostname
      - publicKey
      - ports
  directory:
    type: object
    description: Configuration for the directory server
    properties:
      url:
        type: string
        description: |-
          Base URL of the directory server (protocol: `https://`, ending with
          `/`, no parameters, no fragment)
        pattern: '^https://.*/$'
    required:
      - url
  blob:
    type: object
    description: Configuration for the blob server
    properties:
      uploadUrl:
        type: string
        description: |-
          URL to the blob upload endpoint (protocol: `https://`, no parameters,
          no fragment)
        pattern: '^https://'
        examples:
          - https://blob-threemaonprem.initrode.com/blob/upload
      downloadUrl:
        type: string
        description: |-
          URL to the blob download endpoint (protocol: `https://`, no
          parameters, no fragment)

          Valid placeholders:

          - `{blobId}`: The blob ID (32 hex nibbles)
          - `{blobIdPrefix}`: The first two hex nibbles of the blob ID
        pattern: '^https://'
        examples:
          - https://blob-{blobIdPrefix}-threemaonprem.initrode.com/blob/{blobId}
      doneUrl:
        type: string
        description: |-
          URL to the blob done endpoint (protocol: `https://`, no parameters, no
          fragment)

          Valid placeholders:

          - `{blobId}`: The blob ID (32 hex nibbles)
          - `{blobIdPrefix}`: The first two hex nibbles of the blob ID
        pattern: '^https://'
        examples:
          - https://blob-{blobIdPrefix}-threemaonprem.initrode.com/blob/{blobId}/done
    required:
      - uploadUrl
      - downloadUrl
      - doneUrl
  work:
    type: object
    description: Configuration for Threema Work
    properties:
      url:
        type: string
        description: |-
          Base URL of the Threema Work server (protocol: `https://`, ending with
          `/`, no parameters, no fragment)
        pattern: '^https://.*/$'
        examples:
          - https://threemaonprem.initrode.com/work/
    required:
      - url
  avatar:
    description:
      Configuration for the avatar server, used for Threema Gateway IDs
    type: object
    properties:
      url:
        type: string
        description: |-
          Base URL of the avatar server (protocol: `https://`, ending with `/`,
          no parameters, no fragment)
        pattern: '^https://.*/$'
        examples:
          - https://threemaonprem.initrode.com/avatar/
    required:
      - url
  safe:
    type: object
    description: Configuration for Threema Safe
    properties:
      url:
        type: string
        description: |-
          Base URL of the Threema Safe server (protocol: `https://`, ending with
          `/`, no parameters, no fragment)
        pattern: '^https://.*/$'
        examples:
          - https://threemaonprem.initrode.com/safe/
    required:
      - url
  web:
    type: object
    description: Configuration for Threema Web
    properties:
      url:
        type: string
        description: |-
          URL to the Threema Web endpoint (protocol: `https://`, may have
          parameters, no fragment)

          Not required for app functionality, but is displayed in the app
          (help/info text) so user knows where to go.
        pattern: '^https://'
      overrideSaltyRtcHost:
        type: string
        description: Override the SaltyRTC host specified in the QR code
      overrideSaltyRtcPort:
        type: integer
        minimum: 1
        maximum: 65535
        description: Override the SaltyRTC port specified in the QR code
    required:
      - url
  rendezvous:
    type: object
    description: |-
      Configuration for the rendezvous server

      Required for multi-device support.
    properties:
      url:
        type: string
        description: |-
          Base URL of the rendezvous server (protocol: `wss://`, ending with
          `/`, no parameters, no fragment)

          Valid placeholders:

          - `{rendezvousPathPrefix4}`: The first hex nibble (4 bits) of the
            rendezvous path
          - `{rendezvousPathPrefix8}`: The first two hex nibbles (8 bits) of the
            rendezvous path
        pattern: '^wss://.*/$'
        examples:
          - wss://threemaonprem.initrode.com/rendezvous/
          - wss://rendezvous-{rendezvousPathPrefix4}.initrode.com/{rendezvousPathPrefix8}/
    required:
      - url
  mediator:
    type: object
    description: |-
      Configuration for the mediator server and blob mirror

      Required for multi-device support.
    properties:
      url:
        type: string
        description: |-
          Base URL of the rendezvous server (protocol: `wss://`, ending with
          `/`, no parameters, no fragment)

          Valid placeholders:

          - `{deviceGroupIdPrefix4}`: The first hex nibble (4 bits) of the
            device group ID
          - `{deviceGroupIdPrefix8}`: The first two hex nibbles (8 bits) of the
            device group ID
        pattern: '^wss://.*/$'
        examples:
          - wss://threemaonprem.initrode.com/mediator/
          - wss://mediator-{deviceGroupIdPrefix4}.initrode.com/{deviceGroupIdPrefix8}/
      blob:
        type: object
        description: Configuration for the blob mirror
        properties:
          uploadUrl:
            type: string
            description: |-
              URL to the blob upload endpoint (protocol: `https://`, no
              parameters, no fragment)
            pattern: '^https://'
            examples:
              - https://blob-mirror-threemaonprem.initrode.com/blob/upload
          downloadUrl:
            type: string
            description: |-
              URL to the blob download endpoint (protocol: `https://`, no
              parameters, no fragment)

              Valid placeholders:

              - `{blobId}`: The blob ID (32 hex nibbles)
              - `{blobIdPrefix}`: The first two hex nibbles of the blob ID
            pattern: '^https://'
            examples:
              - https://blob-mirror-{blobIdPrefix}-threemaonprem.initrode.com/blob/{blobId}
          doneUrl:
            type: string
            description: |-
              URL to the blob done endpoint (protocol: `https://`, no
              parameters, no fragment)

              Valid placeholders:

              - `{blobId}`: The blob ID (32 hex nibbles)
              - `{blobIdPrefix}`: The first two hex nibbles of the blob ID
            pattern: '^https://'
            examples:
              - https://blob-mirror-{blobIdPrefix}-threemaonprem.initrode.com/blob/{blobId}/done
        required:
          - uploadUrl
          - downloadUrl
          - doneUrl
    required:
      - url
      - blob
  updates:
    type: object
    description: URLs for update checks
    properties:
      desktop:
        type: object
        properties:
          autoUpdate:
            type: boolean
            description:
              Whether or not the Threema Servers should be called to check if an
              update is available
required:
  - version
  - signatureKey
  - refresh
  - license
  - chat
  - directory
  - blob
  - work
  - avatar
  - safe
  - web
