# ESP Pairing и режимы подключения

Этот документ фиксирует текущие и новые режимы входа/подключения в SHiNE без клиентской UI-реализации. Он нужен как отдельная точка входа по сценариям подключения, чтобы не смешивать обычную авторизацию и серверный pairing через доверенное уже авторизованное устройство пользователя.

## 1. Текущие режимы

### 1. Создание новой сессии через `deviceKey`

Поток:

`AuthChallenge -> CreateAuthSession`

Смысл:

- новое устройство уже владеет приватным `deviceKey`;
- сервер проверяет подпись `deviceKey`;
- создаётся обычная активная сессия пользователя;
- этот поток остаётся без изменений.

### 2. Повторный вход в существующую сессию через `sessionKey`

Поток:

`SessionChallenge -> SessionLogin`

Смысл:

- устройство уже владеет приватным `sessionKey`;
- сервер проверяет подпись `sessionKey`;
- соединение снова входит в существующую сессию;
- этот поток тоже остаётся без изменений.

## 2. Новый режим: добавление сессии через доверенное устройство пользователя

Новый поток не заменяет обычный логин, а живёт рядом с ним.

Цель:

- новое устройство знает `login + pairing password`;
- сервер использует пароль только как фильтр от мусора;
- реальное доверие даёт любая уже онлайн доверенная сессия пользователя;
- сервер не выдаёт приватные ключи сам от себя.

Поток версии `v1`:

1. Любая доверенная сессия пользователя создаёт на сервере pairing-настройку:
   `UpsertEspPairingSettings`
2. Новое устройство создаёт pending-заявку:
   `StartEspPairing`
3. Онлайн доверенная сессия видит список активных заявок:
   `ListEspPairingRequests`
4. Доверенная сессия либо подтверждает заявку:
   `ApproveEspPairing`
5. Либо отклоняет:
   `RejectEspPairing`
6. Новое устройство читает результат:
   `GetEspPairingStatus`

## 3. Что именно делает сервер

- хранит включённость pairing и opaque `passwordHash`;
- хранит pending/approved/rejected pairing-заявки;
- рассчитывает короткий код `shortCode` из `7` цифр;
- рассчитывает длинный `fingerprintB58` из `SHA-256` заявки;
- уведомляет онлайн доверенные сессии событием `IncomingEspPairingRequest`, если такие сессии подключены;
- хранит переданный `encryptedPayload` как непрозрачную строку и не анализирует его содержимое.

## 4. Чего сервер в этой версии не делает

- не передаёт приватный `deviceKey`;
- не расшифровывает `encryptedPayload`;
- не проверяет криптографию содержимого payload;
- не делает клиентский UI;
- не навязывает конкретную схему `Ed25519 -> X25519` в коде сервера.

Это намеренно: серверная версия `v1` подготавливает безопасный каркас маршрутизации и состояния, а настоящая E2E-логика упаковки ключей будет жить на клиентах и ESP-устройствах.

## 5. Роли и ограничения

- любая уже авторизованная доверенная сессия пользователя может вызывать:
  - `UpsertEspPairingSettings`
  - `ListEspPairingRequests`
  - `ApproveEspPairing`
  - `RejectEspPairing`
- новое устройство может вызвать `StartEspPairing` и `GetEspPairingStatus` без уже существующей авторизованной сессии;
- `payloadType` поддерживается в вариантах:
  - `1` — минимальный пакет
  - `2` — расширенный пакет
  - `3` — полный пакет

Сервер не интерпретирует эти три типа глубже, а только фиксирует их в состоянии заявки.

## 6. Статусы pairing-заявки

- `created` — заявка создана и ждёт решения доверенной сессии;
- `approved` — доверенная сессия подтвердила и приложила `encryptedPayload`;
- `rejected` — доверенная сессия отклонила заявку;
- `expired` — TTL заявки истёк до подтверждения.

## 7. Практический смысл

Эта схема даёт нужное разделение доверия:

- пароль на сервере только отсеивает лишних;
- онлайн доверенная сессия решает, добавлять ли новую сессию;
- сервер остаётся маршрутизатором и хранилищем состояния, а не владельцем секретов.
