Добавить ESP pairing через доверенные сессии

This commit is contained in:
AidarKC
2026-06-14 18:21:23 +04:00
parent 5d13112b00
commit 3e04727022
36 changed files with 2500 additions and 6 deletions
+35 -1
View File
@@ -2,7 +2,7 @@
Этот файл описывает именно этапы авторизации клиента, то есть как создать новую сессию и как войти в уже существующую.
Здесь четыре метода:
Здесь четыре базовых метода обычной авторизации:
- `AuthChallenge`
- `CreateAuthSession`
@@ -36,6 +36,16 @@
Ниже в документе сначала описан сценарий, а потом зафиксированы точные форматы запросов и ответов.
Отдельно появился новый серверный сценарий pairing через доверенный homeserver/ESP. Он не заменяет обычный вход и описан в:
- `Dev_Docs/Протоколы/ESP_Pairing_и_режимы_подключения.md`
Кратко:
- `AuthChallenge/CreateAuthSession` и `SessionChallenge/SessionLogin` остаются каноническими потоками обычной авторизации;
- pairing через ESP идёт отдельными `op` и только подготавливает безопасное добавление новой сессии;
- решение об одобрении pairing принимает любая уже авторизованная доверенная сессия пользователя.
## 1. Поток авторизации
Поддерживаются два сценария:
@@ -289,6 +299,30 @@ SESSION_LOGIN:{sessionId}:{timeMs}:{nonce}
---
## 6. Pairing через homeserver/ESP
Новые `op`, относящиеся к этому сценарию:
- `UpsertEspPairingSettings`
- `StartEspPairing`
- `ListEspPairingRequests`
- `ApproveEspPairing`
- `RejectEspPairing`
- `GetEspPairingStatus`
В этом потоке:
- новое устройство не владеет `deviceKey` и не проходит обычный `CreateAuthSession`;
- пароль проверяется сервером только как фильтр;
- решение об одобрении принимает уже авторизованная доверенная сессия пользователя;
- сервер не расшифровывает `encryptedPayload` и не становится источником приватных ключей.
Точные форматы этих операций см. в `03_Session_Management_API.md` и в протокольном документе:
- `Dev_Docs/Протоколы/ESP_Pairing_и_режимы_подключения.md`
---
## 6. Пример ошибки
```json
+235
View File
@@ -7,6 +7,18 @@
- `ListSessions` — получить список активных сессий пользователя;
- `CloseActiveSession` — закрыть одну из активных сессий.
Дополнительно в этом же слое управления сессиями появился сценарий pairing через доверенную уже авторизованную сессию пользователя:
- `UpsertEspPairingSettings`
- `ListEspPairingRequests`
- `ApproveEspPairing`
- `RejectEspPairing`
Анонимное новое устройство работает с двумя связанными операциями:
- `StartEspPairing`
- `GetEspPairingStatus`
Логика раздела такая:
- сначала пользователь проходит `SessionLogin`;
@@ -151,3 +163,226 @@ K9v3nQ4u8jYk0a2p7cD4mLx1zR0sT5wV6bN8eH3fQ1M
Важно: это **не человеко-читаемое имя**, а непрозрачный идентификатор.
Нужно передавать его как есть, без нормализации регистра и без URL-экранирования внутри JSON.
---
## 5. ESP pairing через доверенную сессию
Этот блок относится к сценарию добавления новой сессии через доверенное устройство пользователя.
### 5.1. `UpsertEspPairingSettings`
Доступно для любой уже авторизованной доверенной сессии пользователя.
### Запрос
```json
{
"op": "UpsertEspPairingSettings",
"requestId": "esp-set-001",
"payload": {
"enabled": true,
"passwordHash": "argon2id$...",
"ttlSeconds": 180
}
}
```
### Успешный ответ
```json
{
"op": "UpsertEspPairingSettings",
"requestId": "esp-set-001",
"status": 200,
"ok": true,
"payload": {
"enabled": true,
"ttlSeconds": 180
}
}
```
### Ошибки
- `400 / EMPTY_PASSWORD_HASH` — попытка включить pairing без `passwordHash`.
- `463 / PAIRING_REQUIRES_AUTH_SESSION` — операция вызвана без уже авторизованной доверенной сессии пользователя.
### 5.2. `StartEspPairing`
Эта операция доступна без уже существующей пользовательской сессии.
### Запрос
```json
{
"op": "StartEspPairing",
"requestId": "esp-start-001",
"payload": {
"login": "alice",
"passwordHash": "argon2id$...",
"requesterSessionKey": "ed25519/BASE64_PUBLIC_KEY",
"requesterSessionType": 1,
"requesterClientPlatform": "Android",
"payloadType": 1
}
}
```
Поле `trustedSessionOnline` показывает, что у пользователя сейчас есть хотя бы одна онлайн доверенная сессия, способная принять pairing-заявку.
### Успешный ответ
```json
{
"op": "StartEspPairing",
"requestId": "esp-start-001",
"status": 200,
"ok": true,
"payload": {
"pairingId": "base64url",
"state": "created",
"shortCode": "4920709",
"fingerprintB58": "ASvYDPQidnAroKzQjtCjTuEQE8ckktV5nmmhYRhDzGaA",
"expiresAtMs": 1781441990538,
"trustedSessionOnline": true
}
}
```
### Ошибки
- `400 / EMPTY_LOGIN`
- `400 / EMPTY_PASSWORD_HASH`
- `400 / EMPTY_REQUESTER_SESSION_KEY`
- `400 / BAD_REQUESTER_SESSION_KEY`
- `400 / BAD_SESSION_TYPE`
- `400 / BAD_PAYLOAD_TYPE`
- `422 / PAIRING_NOT_AVAILABLE`
- `422 / PAIRING_PASSWORD_INVALID`
- `429 / PAIRING_RATE_LIMITED`
### 5.3. `ListEspPairingRequests`
Доступно для любой уже авторизованной доверенной сессии пользователя.
### Успешный ответ
```json
{
"op": "ListEspPairingRequests",
"requestId": "esp-list-001",
"status": 200,
"ok": true,
"payload": {
"requests": [
{
"pairingId": "base64url",
"state": "created",
"requesterSessionKey": "ed25519/BASE64_PUBLIC_KEY",
"requesterSessionType": 1,
"requesterClientPlatform": "Android",
"payloadType": 1,
"shortCode": "4920709",
"fingerprintB58": "ASvYDPQidnAroKzQjtCjTuEQE8ckktV5nmmhYRhDzGaA",
"createdAtMs": 1781441810538,
"expiresAtMs": 1781441990538,
"deliveredToHomeserver": true
}
]
}
}
```
### Ошибки
- `463 / PAIRING_REQUIRES_AUTH_SESSION`
### 5.4. `ApproveEspPairing`
Доступно для любой уже авторизованной доверенной сессии пользователя.
### Запрос
```json
{
"op": "ApproveEspPairing",
"requestId": "esp-approve-001",
"payload": {
"pairingId": "base64url",
"encryptedPayload": "BASE64_OR_OTHER_OPAQUE_PAYLOAD"
}
}
```
### Успешный ответ
```json
{
"op": "ApproveEspPairing",
"requestId": "esp-approve-001",
"status": 200,
"ok": true,
"payload": {
"pairingId": "base64url",
"state": "approved"
}
}
```
### Ошибки
- `400 / EMPTY_PAIRING_ID`
- `400 / EMPTY_ENCRYPTED_PAYLOAD`
- `404 / PAIRING_NOT_FOUND`
- `422 / PAIRING_OF_ANOTHER_USER`
- `422 / PAIRING_NOT_PENDING`
- `422 / PAIRING_EXPIRED`
- `463 / PAIRING_REQUIRES_AUTH_SESSION`
### 5.5. `RejectEspPairing`
Доступно для любой уже авторизованной доверенной сессии пользователя. Похоже на approve, но переводит заявку в `state=rejected`.
### 5.6. `GetEspPairingStatus`
Операция для нового устройства.
### Запрос
```json
{
"op": "GetEspPairingStatus",
"requestId": "esp-status-001",
"payload": {
"pairingId": "base64url"
}
}
```
### Успешный ответ после approve
```json
{
"op": "GetEspPairingStatus",
"requestId": "esp-status-001",
"status": 200,
"ok": true,
"payload": {
"pairingId": "base64url",
"state": "approved",
"shortCode": "4920709",
"fingerprintB58": "ASvYDPQidnAroKzQjtCjTuEQE8ckktV5nmmhYRhDzGaA",
"payloadType": 1,
"encryptedPayload": "AQIDBA==",
"expiresAtMs": 1781441990538
}
}
```
### Возможные `state`
- `created`
- `approved`
- `rejected`
- `expired`
+6
View File
@@ -19,6 +19,12 @@
| `CreateAuthSession` | `02_Authentication_API.md` | создание новой авторизованной сессии |
| `SessionChallenge` | `02_Authentication_API.md` | challenge для входа в существующую сессию |
| `SessionLogin` | `02_Authentication_API.md` | вход в существующую сессию |
| `UpsertEspPairingSettings` | `03_Session_Management_API.md` | включение/обновление pairing-настроек доверенной сессией |
| `StartEspPairing` | `03_Session_Management_API.md` | создание pairing-заявки для нового устройства |
| `ListEspPairingRequests` | `03_Session_Management_API.md` | список активных pairing-заявок для доверенной сессии |
| `ApproveEspPairing` | `03_Session_Management_API.md` | подтверждение pairing-заявки доверенной сессией |
| `RejectEspPairing` | `03_Session_Management_API.md` | отклонение pairing-заявки доверенной сессией |
| `GetEspPairingStatus` | `03_Session_Management_API.md` | чтение статуса и результата pairing-заявки |
| `ListSessions` | `03_Session_Management_API.md` | список активных сессий |
| `CloseActiveSession` | `03_Session_Management_API.md` | закрытие активной сессии |
| `AddBlock` | `04_Add_Block_to_Blockchain_API.md` | добавление блока в блокчейн |