Множественные изменения и +3 события

This commit is contained in:
Shr3dd3r 2023-07-01 05:31:44 +03:00
parent 2ab79a3523
commit 72bfaea76d
6 changed files with 219 additions and 30 deletions

39
Error/HandshakeFailed.md Normal file
View File

@ -0,0 +1,39 @@
# Error.HandshakeFailed
**Значение: 0x0501**
## Client2Server
_Не применимо._
## Server2Client
Отрицательный ответ на инициирование рукопожатия. Сообщает о произошедшей проблеме.
**Ячейки:**
- Код ошибки
- _Ключ:_ 0x01
- _Тип:_ `uint8_t`
- Код, описывающий ошибку конкретнее.
- 0x01: магическое число неверно.
- 0x02: неподдерживаемая версия протокола.
- 0x03: невозможно выделить новый порт для подключения.
- 0x04: указанный транспортный протокол не поддерживается.
- 0x05: указанный размер пакета недопустим.
- Подробные данные
- _Ключ:_ 0x02
- _Тип:_ `char[]`
- Бинарное описание ошибки или сопровождающая информация.
- Текстовое описание
- _Ключ:_ 0x03
- _Тип:_ `char[]`
- Текстовое описание ошибки.
## Server2Server
_Также как и Server2Client._

16
Error/README.md Normal file
View File

@ -0,0 +1,16 @@
Все ошибки без исключения должны иметь следующий формат:
- Код ошибки
- _Ключ:_ 0x01
- _Тип:_ `uint8_t`
- Код, описывающий ошибку конкретнее.
- Подробные данные
- _Ключ:_ 0x02
- _Тип:_ `char[]`
- Бинарное описание ошибки.
- Текстовое описание
- _Ключ:_ 0x03
- _Тип:_ `char[]`
- Текстовое описание ошибки.
Различия допустимы только в интепретации кода ошибки.

30
Handshake/Accepted.md Normal file
View File

@ -0,0 +1,30 @@
# Handshake.Accepted
**Значение: 0x1002**
## Client2Server
_Не применимо._
## Server2Client
Положительный ответ на инициирование рукопожатия. Передаёт все ключевые данные для осуществления дальнейшей коммуникации.
**Фиксированная схема:**
- Магическое число
- _Размер:_ 8 байт
- _Тип:_ `uint64_t`
- Магическое число протокола, по которому определяется совместимость цели с протоколом MFP. Являет из себя строку "MarafonP" в кодировке ASCII.
- Порт для переподключения
- _Размер:_ 2 байта
- _Тип:_ `uint16_t`
- Предоставляет номер порта для переподключения. Установлен в 0, если не требуется.
## Server2Server
_Также как и Server2Client._

45
Handshake/Request.md Normal file
View File

@ -0,0 +1,45 @@
# Handshake.Request
**Значение: 0x1001**
## Client2Server
Инициирующее рукопожатие событие. Передаёт все ключевые данные для осуществления дальнейшей коммуникации.
**Фиксированная схема:**
- Магическое число
- _Размер:_ 8 байт
- _Тип:_ `uint64_t`
- Магическое число протокола, по которому определяется совместимость цели с протоколом MFP. Являет из себя строку "MarafonP" в кодировке ASCII.
- Версия протокола
- _Размер:_ 4 байта
- _Тип:_ `uint8_t[4]`
- Максимальная поддерживаемая запрашивающим версия протокола.
- Флаги переподключения
- _Размер:_ 2 байта
- _Тип:_ `uint16_t`
- Описывает параметры нового подключения:
- 0b0000000000000000: оставить текущее подключение
- 0b0000000000000001: переподключиться к тому-же порту
- 0b0000000000000010: запросить новый порт для подключения
- 0b0000000000000100: использовать TCP
- 0b0000000000001000: использовать TLS
- 0b0000111111110000: резерв под расширение
- 0b1111000000000000: резерв под под нужды сторонних реализаций
- Размер пакета
- _Размер:_ 4 байта
- _Тип:_ `uint32_t`
- Устанавливает используемый при коммуникации размер пакета.
## Server2Client
_Не применимо._
## Server2Server
_Также как и Client2Server._

View File

@ -1,6 +1,6 @@
# Спецификация Marafon Protocol (MFP) v1.0
Marafon Protocol это протокол для одноимённого полнофункционального мессенджера, работающего поверх TCP. Основной фокус при работе над оным идёт на:
Marafon Protocol это протокол для одноимённого полнофункционального мессенджера, работающего поверх TCP (в будущем будет добавлена поддержка UDP и QUIC). Основной фокус при работе над оным идёт на:
- Снижение оверхэдов, по сравнению с классическими решениями (Matrix, Discord, WhatsApp, пр.).
- Устойчивость к цензуре.
@ -13,29 +13,52 @@ Marafon Protocol это протокол для одноимённого пол
## Пакеты
## Поведение сервера и клиента
Существует три уровня категорий пакетов:
Сервер **обязан**:
1. Оповещать клиент и сервера в федерации о всех ошибках, кроме:
- Связанных с безопасностью
- Связанных с внутренними неполадками
2. Отдавать предпочтение данным других серверов, нежели клиентов.
3. Отдавать предпочтение сетевым настройкам входящих соединений, нежели локальным (не считая лимиты).
Клиент **обязан**:
1. Хранить тишину о всех ошибках.
2. Явно уведомлять юзера при возникновении проблем с безопасностью, как минимум по умолчанию.
## События, пакеты и их структура
Существует три уровня категорий событий:
1. **Надкатегория:** Client2Server, Server2Client, Server2Server.
2. **Категория:** Authentication, User, Message, т.д.
3. **Подкатегория:** Login, Create, Delete, т.д.
Надкатегория никак не указывается в пакете и зависит от контекста. Он-же определяет структуру некоторых пакетов, которая может менятся в конкретных случаях. Остальные две занимают по одному байту соответственно.
Надкатегория никак не указывается в пакете, зависит от контекста и при упоминании - чаще всего опускается. Она также определяет структуру некоторых событий, которая может меняться в конкретных случаях. Остальные две занимают по одному байту соответственно.
Пакеты всех категорий, кроме явно оговорённых или принадлежащих к надкатегории Server2Client, содержат идентификатор серверной сессии, являющийся четырёхбайтным числом без знака.
Все категории вместе являются типом события. Значение типа - это число, которое указывается в начале пакета.
Пакеты всех категорий из надкатегории Client2Server, кроме явно оговорённых, содержат хэш полезной нагрузки, зашифрованный с помощью закрытого ключа подписи клиента.
События всех категорий, кроме явно оговорённых или принадлежащих к надкатегории Server2Client, содержат идентификатор серверной сессии, являющийся четырёхбайтным числом без знака (`uint64_t`).
Данные (AKA "полезная нагрузка") являются расположенными последовательно парами "ключ-значение" и могут быть расположены относительно друг-друга в произвольном порядке. Они следующий формат:
События всех категорий из надкатегории Client2Server, кроме явно оговорённых, содержат хэш полезной нагрузки, зашифрованный с помощью закрытого ключа подписи клиента.
`[2b: key][2b: data length][>0 b: data]`
Данные (AKA "полезная нагрузка") являются расположенными последовательно парами "ключ-значение" и могут быть расположены в пакете относительно друг-друга в произвольном порядке. Одна пара имеет следующий формат:
`[1b: key][2b: data length][>0 b: data]`
Все пакеты размером ниже установленного дополняются псевдослучайной последовательностью байт. (???)
<!-- ATTENTION: ^ под вопросом ^ -->
Исходя из всего вышеописанного, итоговая примерная структура пакета выглядит следующим образом:
`[1b: category][1b: subcategory][4b: server session][>0 b: payload]`
`[1b: category][1b: subcategory][4b: server session][?b: payload hash][>0b: payload][~b: random bytes]`
Размер пакета определяется ответом сервера на этапе обмена характеристиками, но не может быть больше, чем 65535 байт. До этого этапа размер пакета составляет 512 байт.
Размер пакета определяется запросом клиента на этапе обмена характеристиками, но не может быть больше, чем 65535 байт или меньше 128 байт. До этого этапа (включительно) размер пакета составляет 512 байт.
Магическим числом протокола является следующая последовательность байт:
@ -48,29 +71,48 @@ DEC: 77 97 114 97 102 111 110 80
## Сессии, аутентификация и соединение
## Соединение, аутентификация и сессии
После успешной установки защищённого TLS соединения начинается этап обмена характеристиками. Клиент отправляет некоторые метаданные, в числе которых:
Первичное подключение к серверу может выполнятся разными способами, в том числе подразумевающими маскировку траффика под существующие протоколы, но при использовании вне локальных сетей - должно сводиться к установке защищённого соединения. Данная версия протокола подразумевает поддержку пока лишь двух способов подключения: напрямую (без шифрования) и с использованием TLS-over-TCP.
- Магическое число: 8 байт
- Версия протокола: 4 байта
- ID серверной сессии: 4 байта (0 если нет; на случай, если соединение надо восстановить, а не создать с нуля)
### Рукопожатие
На что сервер отвечает своим набором метаданных:
- Магическое число: 8 байт
- Интервал обновления: 2 байта (x * 0.01 = интервал в секундах)
После успешной установки защищённого соединения, происходит обмен характеристиками, AKA "рукопожатие". Клиент отправляет событие типа `Handshake.Request`, на что сервер отвечает либо ошибкой, либо событием типа `Handshake.Accepted`.
<!-- TODO: надо ещё обдумать, какими данными обмениваться клиентосерверу -->
Если при обмене метаданными клиент или сервер обнаруживают несоответствие магических чисел, то они разрывают соединение. Если сервер не поддерживает указанную клиентом версию протокола - он отвечает ошибкой и разрывает соединение. Если при попытке восстановить соединение клиентом, ID серверной сессии не существует в списке недавно-разорванных, то он отвечает ошибкой и разрывает соединение.
Сервер отвечает ошибкой `Error.HandshakeFailed` и разрывает соединение, если:
- При обмене данными клиент или сервер обнаруживают несоответствие магических чисел.
- Сервер не поддерживает указанную клиентом версию протокола.
- Невозможно выделить новый порт для подключения.
- Указанный транспортный протокол не поддерживается.
- Размер пакета не попадает в рамки жёсткого лимита сервера.
Если при хэндшейке клиентом был указан новый способ подключения и получен валидный ответ от сервера - то они обязаны разорвать текущее соединение, затем, спустя случайное количество времени, от 50 мс до 500 мс, создать новое.
### Регистрация
При успешной регистрации учётной записи, клиент генерирует пару ключей (открытый-закрытый) в качестве подписи, после чего открытый ключ отправляется серверу и тот сохраняет его.
### Вход в учётную запись
Вход в учётную запись происходит путём отправки логина и хэша пароля на сервер. При этом клиент может указать ID серверной сессии, если произошло непредвиденное отключение и ему необходимо переподключиться.
Если логин или пароль несовпадают - сервер отвечает ошибкой и разрывает соединение. Если полезная нагрузка подписана ложно - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инциденте.
Если ID серверной сессии нет в списке недавно-разорванных - сервер отвечает ошибкой и разрывает соединение.
При успешном входе в учётную запись, сервер генерирует `uint32_t`, являющийся идентификатором серверной сессии. Клиент обязан хранить его и прикреплять к каждому пакету (кроме особо-оговорённых случаев) до момента отключения от сервера.
Если при проверке хэша полезной нагрузки пакета обнаруживается, что подпись неверна - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инцеденте.
### Пользовательские сессии и подпись
Каждый принятый сервером пакет, содержащий хэш полезной нагрузки, должен проверяться на соответствие подписи. Если сервер обнаруживает, что подпись неверна - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инциденте.
Каждый принятый клиентом пакет, содержащий хэш полезной нагрузки, может быть проверен на соответствие подписи. Если клиент обнаруживает, что подпись неверна - он должен оповестить пользователя.
<!-- TODO: решить: должен ли сервер иметь свою подпись; как и нужно-ли, чтобы сервер являлся средой нулевого доверия в плане передачи подписей пользователей (скорее всего "Да." х 2) -->
Полезная нагрузка пакета может быть проверена на целостность сервером или клиентом с использованием подписанного хеша, но данная проверка может быть отключена, по усмотрению владельца сервера или пользователя клиента.
Если при проверке ID серверной сессии обнаруживается несоответствие - сервер отвечает ошибкой, соединение разрывается.
Каждые n секунд клиент отправляет запрос на обновление статуса аккаунта. Если спустя указанное на этапе обмена характеристиками время нет ни одного пакета от клиента - сервер разрывает соединение.

View File

@ -1,22 +1,39 @@
# Category.Subcategory
# Категория.Субкатегория
**Значение: 0xBA98**
## Client2Server
Some description.
Какое-то описание метода.
**Fields:**
**Ячейки:**
- Field_1: 0xabcd; description of data.
- Field_2: 0x1234; description of data too.
- Ячейка_1
- _Ключ:_ 0xAB
- _Тип:_ `char[]`
- Описание данных.
- Ячейка_2
- _Ключ:_ 0x12
- _Тип:_ `uint64_t`
- Тоже описание данных.
## Server2Client
_Same as for Client2Server._
**Фиксированная схема:**
- Какая-то ячейка
- _Размер:_ 8 байт
- _Тип:_ `uint64_t`
- Описание, ага.
- Тоже ячейка
- _Размер:_ 2 байта
- _Тип:_ `wchar_t`
- Точно описание.
## Server2Server
_Same as for Client2Server._
_Также как и Client2Server._