Регистрация устройства по одноразовому токену и запросу сертификата
POST /d/v1/enroll
https://devices.tanba-ooh.kz/d/v1/enroll
Первый вызов плеера. Администратор выпускает токен регистрации в консоли (действует 24 часа, одноразовый). Плеер создает ключ ECDSA P-256, отправляет запрос сертификата для него вместе с токеном и получает сертификат устройства на один год и цепочку до центра сертификации устройств. Дальше все вызовы, кроме этого и чтения списков отзыва, предъявляют этот сертификат. Единственные учетные данные этого вызова это токен. Число вызовов с одного адреса ограничено.
Протокол устройства находится в статусе «бета»: идентификаторы (OID) подписанных атрибутов конверта пока лежат в тестовой дуге 1.3.6.1.4.1.59999.1. Зарегистрированная дуга заменит ее до того, как протокол будет объявлен стабильным.
Аутентификация
Открытый вызов: учетными данными служит одноразовый токен регистрации в теле запроса.
Тело запроса
application/json
| Имя | Тип | Обязательный | Описание | Пример |
|---|---|---|---|---|
token | string | да | Одноразовый токен регистрации из консоли. | "tdt_4f9c2a71b86e3d05" |
csr | string | да | Запрос сертификата для ключа устройства, PEM или base64 от DER; ECDSA P-256. | "MIIBEjCBuAIBADAZMRcwFQYDVQQDEw5leGFtcGxlLXBsYXllcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABA" |
model | string | Модель плеера. | "XP-100" | |
firmware | string | Версия прошивки плеера. | "4.2.1" | |
serial_no | string | Серийный номер плеера. | "XP100-0042" | |
spec_version | string | Версия спецификации соответствия, которую заявляет плеер. | "1.1" |
Пример
{
"token": "tdt_4f9c2a71b86e3d05",
"csr": "MIIBEjCBuAIBADAZMRcwFQYDVQQDEw5leGFtcGxlLXBsYXllcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABA",
"model": "XP-100",
"firmware": "4.2.1",
"serial_no": "XP100-0042",
"spec_version": "1.1"
}
Ответы
200 Устройство зарегистрировано.
application/json
| Имя | Тип | Обязательный | Описание | Пример |
|---|---|---|---|---|
device_id | string (uuid) | да | Идентификатор устройства; он есть в сертификате. | "5c0e8f3a-71d2-4b6e-9a14-d8e2f7b30c59" |
certificate_pem | string | да | Сертификат устройства в формате PEM. | "-----BEGIN CERTIFICATE-----\nMIIB...\n-----END CERTIFICATE-----\n" |
chain_pem | string | да | Цепочка до центра сертификации устройств в формате PEM. | "-----BEGIN CERTIFICATE-----\nMIIB...\n-----END CERTIFICATE-----\n" |
nonce | string | да | Одноразовое число для первого heartbeat. | "3b9f0c6e2a7d41f85e0b9a3c7d2e1f60" |
not_after | string (date-time) | да | Когда истекает сертификат. | "2027-10-14T09:00:00Z" |
revocation_list | object | null | Новейший список отзыва: его версия и адрес. | ||
revocation_list.version | integer | Версия списка. | 42 | |
revocation_list.url | string | Адрес списка. | "https://devices.tanba-ooh.kz/d/v1/revocations/42" |
Пример
{
"device_id": "5c0e8f3a-71d2-4b6e-9a14-d8e2f7b30c59",
"certificate_pem": "-----BEGIN CERTIFICATE-----\nMIIB...\n-----END CERTIFICATE-----\n",
"chain_pem": "-----BEGIN CERTIFICATE-----\nMIIB...\n-----END CERTIFICATE-----\n",
"nonce": "3b9f0c6e2a7d41f85e0b9a3c7d2e1f60",
"not_after": "2027-10-14T09:00:00Z",
"revocation_list": {
"version": 42,
"url": "https://devices.tanba-ooh.kz/d/v1/revocations/42"
}
}
Ошибки
Ошибки приходят документом problem (application/problem+json) со стабильным полем code.
| Статус | Значение |
|---|---|
| 403 | Токен неизвестен, уже использован или просрочен (invalid_token). |
| 422 | Ошибки полей (validation_failed). |
| 429 | Превышен предел частоты; см. Retry-After. |
| 503 | Канал устройств выключен (device_channel_disabled). |
| default | Ошибка в виде документа problem. |
Примеры кода
curl
curl -X POST 'https://devices.tanba-ooh.kz/d/v1/enroll' \
-H 'Content-Type: application/json' \
-d '{
"token": "tdt_4f9c2a71b86e3d05",
"csr": "MIIBEjCBuAIBADAZMRcwFQYDVQQDEw5leGFtcGxlLXBsYXllcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABA",
"model": "XP-100",
"firmware": "4.2.1",
"serial_no": "XP100-0042",
"spec_version": "1.1"
}'
Python
import requests
response = requests.post(
"https://devices.tanba-ooh.kz/d/v1/enroll",
headers={
"Content-Type": "application/json",
},
json={
"token": "tdt_4f9c2a71b86e3d05",
"csr": "MIIBEjCBuAIBADAZMRcwFQYDVQQDEw5leGFtcGxlLXBsYXllcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABA",
"model": "XP-100",
"firmware": "4.2.1",
"serial_no": "XP100-0042",
"spec_version": "1.1",
},
)
print(response.status_code, response.text)
Go
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"token": "tdt_4f9c2a71b86e3d05",
"csr": "MIIBEjCBuAIBADAZMRcwFQYDVQQDEw5leGFtcGxlLXBsYXllcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABA",
"model": "XP-100",
"firmware": "4.2.1",
"serial_no": "XP100-0042",
"spec_version": "1.1"
}`)
req, err := http.NewRequest("POST", "https://devices.tanba-ooh.kz/d/v1/enroll", body)
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(resp.Status, string(data))
}