Множественные изменения и +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 (MFP) v1.0
|
||||||
|
|
||||||
Marafon Protocol это протокол для одноимённого полнофункционального мессенджера, работающего поверх TCP. Основной фокус при работе над оным идёт на:
|
Marafon Protocol это протокол для одноимённого полнофункционального мессенджера, работающего поверх TCP (в будущем будет добавлена поддержка UDP и QUIC). Основной фокус при работе над оным идёт на:
|
||||||
|
|
||||||
- Снижение оверхэдов, по сравнению с классическими решениями (Matrix, Discord, WhatsApp, пр.).
|
- Снижение оверхэдов, по сравнению с классическими решениями (Matrix, Discord, WhatsApp, пр.).
|
||||||
- Устойчивость к цензуре.
|
- Устойчивость к цензуре.
|
||||||
@ -13,29 +13,52 @@ Marafon Protocol это протокол для одноимённого пол
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Пакеты
|
## Поведение сервера и клиента
|
||||||
|
|
||||||
Существует три уровня категорий пакетов:
|
Сервер **обязан**:
|
||||||
|
|
||||||
|
1. Оповещать клиент и сервера в федерации о всех ошибках, кроме:
|
||||||
|
- Связанных с безопасностью
|
||||||
|
- Связанных с внутренними неполадками
|
||||||
|
2. Отдавать предпочтение данным других серверов, нежели клиентов.
|
||||||
|
3. Отдавать предпочтение сетевым настройкам входящих соединений, нежели локальным (не считая лимиты).
|
||||||
|
|
||||||
|
Клиент **обязан**:
|
||||||
|
|
||||||
|
1. Хранить тишину о всех ошибках.
|
||||||
|
2. Явно уведомлять юзера при возникновении проблем с безопасностью, как минимум по умолчанию.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## События, пакеты и их структура
|
||||||
|
|
||||||
|
Существует три уровня категорий событий:
|
||||||
|
|
||||||
1. **Надкатегория:** Client2Server, Server2Client, Server2Server.
|
1. **Надкатегория:** Client2Server, Server2Client, Server2Server.
|
||||||
2. **Категория:** Authentication, User, Message, т.д.
|
2. **Категория:** Authentication, User, Message, т.д.
|
||||||
3. **Подкатегория:** Login, Create, Delete, т.д.
|
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 если нет; на случай, если соединение надо восстановить, а не создать с нуля)
|
|
||||||
|
|
||||||
На что сервер отвечает своим набором метаданных:
|
После успешной установки защищённого соединения, происходит обмен характеристиками, AKA "рукопожатие". Клиент отправляет событие типа `Handshake.Request`, на что сервер отвечает либо ошибкой, либо событием типа `Handshake.Accepted`.
|
||||||
|
|
||||||
- Магическое число: 8 байт
|
|
||||||
- Интервал обновления: 2 байта (x * 0.01 = интервал в секундах)
|
|
||||||
|
|
||||||
<!-- TODO: надо ещё обдумать, какими данными обмениваться клиентосерверу -->
|
<!-- TODO: надо ещё обдумать, какими данными обмениваться клиентосерверу -->
|
||||||
|
|
||||||
Если при обмене метаданными клиент или сервер обнаруживают несоответствие магических чисел, то они разрывают соединение. Если сервер не поддерживает указанную клиентом версию протокола - он отвечает ошибкой и разрывает соединение. Если при попытке восстановить соединение клиентом, ID серверной сессии не существует в списке недавно-разорванных, то он отвечает ошибкой и разрывает соединение.
|
Сервер отвечает ошибкой `Error.HandshakeFailed` и разрывает соединение, если:
|
||||||
|
|
||||||
|
- При обмене данными клиент или сервер обнаруживают несоответствие магических чисел.
|
||||||
|
- Сервер не поддерживает указанную клиентом версию протокола.
|
||||||
|
- Невозможно выделить новый порт для подключения.
|
||||||
|
- Указанный транспортный протокол не поддерживается.
|
||||||
|
- Размер пакета не попадает в рамки жёсткого лимита сервера.
|
||||||
|
|
||||||
|
Если при хэндшейке клиентом был указан новый способ подключения и получен валидный ответ от сервера - то они обязаны разорвать текущее соединение, затем, спустя случайное количество времени, от 50 мс до 500 мс, создать новое.
|
||||||
|
|
||||||
|
### Регистрация
|
||||||
|
|
||||||
При успешной регистрации учётной записи, клиент генерирует пару ключей (открытый-закрытый) в качестве подписи, после чего открытый ключ отправляется серверу и тот сохраняет его.
|
При успешной регистрации учётной записи, клиент генерирует пару ключей (открытый-закрытый) в качестве подписи, после чего открытый ключ отправляется серверу и тот сохраняет его.
|
||||||
|
|
||||||
|
### Вход в учётную запись
|
||||||
|
|
||||||
|
Вход в учётную запись происходит путём отправки логина и хэша пароля на сервер. При этом клиент может указать ID серверной сессии, если произошло непредвиденное отключение и ему необходимо переподключиться.
|
||||||
|
|
||||||
|
Если логин или пароль несовпадают - сервер отвечает ошибкой и разрывает соединение. Если полезная нагрузка подписана ложно - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инциденте.
|
||||||
|
|
||||||
|
Если ID серверной сессии нет в списке недавно-разорванных - сервер отвечает ошибкой и разрывает соединение.
|
||||||
|
|
||||||
При успешном входе в учётную запись, сервер генерирует `uint32_t`, являющийся идентификатором серверной сессии. Клиент обязан хранить его и прикреплять к каждому пакету (кроме особо-оговорённых случаев) до момента отключения от сервера.
|
При успешном входе в учётную запись, сервер генерирует `uint32_t`, являющийся идентификатором серверной сессии. Клиент обязан хранить его и прикреплять к каждому пакету (кроме особо-оговорённых случаев) до момента отключения от сервера.
|
||||||
|
|
||||||
Если при проверке хэша полезной нагрузки пакета обнаруживается, что подпись неверна - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инцеденте.
|
### Пользовательские сессии и подпись
|
||||||
|
|
||||||
Если при проверке ID серверной сессии обнаруживается несоответствие - сервер отвечает ошибкой, соединение разрывается.
|
Каждый принятый сервером пакет, содержащий хэш полезной нагрузки, должен проверяться на соответствие подписи. Если сервер обнаруживает, что подпись неверна - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инциденте.
|
||||||
|
|
||||||
Каждые n секунд клиент отправляет запрос на обновление статуса аккаунта. Если спустя указанное на этапе обмена характеристиками время нет ни одного пакета от клиента - сервер разрывает соединение.
|
Каждый принятый клиентом пакет, содержащий хэш полезной нагрузки, может быть проверен на соответствие подписи. Если клиент обнаруживает, что подпись неверна - он должен оповестить пользователя.
|
||||||
|
|
||||||
|
<!-- TODO: решить: должен ли сервер иметь свою подпись; как и нужно-ли, чтобы сервер являлся средой нулевого доверия в плане передачи подписей пользователей (скорее всего "Да." х 2) -->
|
||||||
|
|
||||||
|
Полезная нагрузка пакета может быть проверена на целостность сервером или клиентом с использованием подписанного хеша, но данная проверка может быть отключена, по усмотрению владельца сервера или пользователя клиента.
|
||||||
|
|
||||||
|
Если при проверке ID серверной сессии обнаруживается несоответствие - сервер отвечает ошибкой, соединение разрывается.
|
@ -1,22 +1,39 @@
|
|||||||
# Category.Subcategory
|
# Категория.Субкатегория
|
||||||
|
|
||||||
|
**Значение: 0xBA98**
|
||||||
|
|
||||||
## Client2Server
|
## Client2Server
|
||||||
|
|
||||||
Some description.
|
Какое-то описание метода.
|
||||||
|
|
||||||
**Fields:**
|
**Ячейки:**
|
||||||
|
|
||||||
- Field_1: 0xabcd; description of data.
|
- Ячейка_1
|
||||||
- Field_2: 0x1234; description of data too.
|
- _Ключ:_ 0xAB
|
||||||
|
- _Тип:_ `char[]`
|
||||||
|
- Описание данных.
|
||||||
|
- Ячейка_2
|
||||||
|
- _Ключ:_ 0x12
|
||||||
|
- _Тип:_ `uint64_t`
|
||||||
|
- Тоже описание данных.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Server2Client
|
## Server2Client
|
||||||
|
|
||||||
_Same as for Client2Server._
|
**Фиксированная схема:**
|
||||||
|
|
||||||
|
- Какая-то ячейка
|
||||||
|
- _Размер:_ 8 байт
|
||||||
|
- _Тип:_ `uint64_t`
|
||||||
|
- Описание, ага.
|
||||||
|
- Тоже ячейка
|
||||||
|
- _Размер:_ 2 байта
|
||||||
|
- _Тип:_ `wchar_t`
|
||||||
|
- Точно описание.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Server2Server
|
## Server2Server
|
||||||
|
|
||||||
_Same as for Client2Server._
|
_Также как и Client2Server._
|
Loading…
Reference in New Issue
Block a user