Множественные изменения и +3 события
This commit is contained in:
parent
2ab79a3523
commit
72bfaea76d
39
Error/HandshakeFailed.md
Normal file
39
Error/HandshakeFailed.md
Normal 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
16
Error/README.md
Normal file
@ -0,0 +1,16 @@
|
||||
Все ошибки без исключения должны иметь следующий формат:
|
||||
|
||||
- Код ошибки
|
||||
- _Ключ:_ 0x01
|
||||
- _Тип:_ `uint8_t`
|
||||
- Код, описывающий ошибку конкретнее.
|
||||
- Подробные данные
|
||||
- _Ключ:_ 0x02
|
||||
- _Тип:_ `char[]`
|
||||
- Бинарное описание ошибки.
|
||||
- Текстовое описание
|
||||
- _Ключ:_ 0x03
|
||||
- _Тип:_ `char[]`
|
||||
- Текстовое описание ошибки.
|
||||
|
||||
Различия допустимы только в интепретации кода ошибки.
|
30
Handshake/Accepted.md
Normal file
30
Handshake/Accepted.md
Normal 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
45
Handshake/Request.md
Normal 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._
|
88
OVERVIEW.md
88
OVERVIEW.md
@ -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`, являющийся идентификатором серверной сессии. Клиент обязан хранить его и прикреплять к каждому пакету (кроме особо-оговорённых случаев) до момента отключения от сервера.
|
||||
|
||||
Если при проверке хэша полезной нагрузки пакета обнаруживается, что подпись неверна - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инцеденте.
|
||||
### Пользовательские сессии и подпись
|
||||
|
||||
Если при проверке ID серверной сессии обнаруживается несоответствие - сервер отвечает ошибкой, соединение разрывается.
|
||||
Каждый принятый сервером пакет, содержащий хэш полезной нагрузки, должен проверяться на соответствие подписи. Если сервер обнаруживает, что подпись неверна - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инциденте.
|
||||
|
||||
Каждые n секунд клиент отправляет запрос на обновление статуса аккаунта. Если спустя указанное на этапе обмена характеристиками время нет ни одного пакета от клиента - сервер разрывает соединение.
|
||||
Каждый принятый клиентом пакет, содержащий хэш полезной нагрузки, может быть проверен на соответствие подписи. Если клиент обнаруживает, что подпись неверна - он должен оповестить пользователя.
|
||||
|
||||
<!-- TODO: решить: должен ли сервер иметь свою подпись; как и нужно-ли, чтобы сервер являлся средой нулевого доверия в плане передачи подписей пользователей (скорее всего "Да." х 2) -->
|
||||
|
||||
Полезная нагрузка пакета может быть проверена на целостность сервером или клиентом с использованием подписанного хеша, но данная проверка может быть отключена, по усмотрению владельца сервера или пользователя клиента.
|
||||
|
||||
Если при проверке ID серверной сессии обнаруживается несоответствие - сервер отвечает ошибкой, соединение разрывается.
|
@ -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._
|
Loading…
Reference in New Issue
Block a user