From 8c5de781ea11163083571409554168596450aa3f3fbb7655c041481b40b02a23 Mon Sep 17 00:00:00 2001 From: AidarKC Date: Mon, 25 May 2026 23:43:43 +0300 Subject: [PATCH] =?UTF-8?q?API:=20=D0=B7=D0=B0=D0=B4=D0=BE=D0=BA=D1=83?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=20?= =?UTF-8?q?rawBlockB64=20=D0=B2=20GetMessageThread=20=D0=B8=20=D0=BE=D0=B1?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D1=81=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dev_Docs/API/06_Channels_Read_API.md | 7 + Dev_Docs/API/07_Channels_Feature_Runbook.md | 5 + .../Протоколы}/SHINE_ARWEAVE_DERIVATION_V1.md | 0 VERSION.properties | 4 +- .../shine-main Описание базовых классов.md | 36 --- doc_todelite/DOC/Описание протокола.md | 286 ------------------ doc_todelite/DOC/Формат Блокцейнов.md | 165 ---------- ... для создания ОПИСАНИЯ ПРООТОКОЛА блокчейна.txt | 2 - .../JSON/handlers/auth/entyties/help.txt | 39 --- .../ws_protocol/JSON/Описание протокола.md | 286 ------------------ .../src/main/doc_to_client_writer.txt | 172 ----------- .../Описанией записей/Начало блокчейна.md | 45 --- .../Смена Пароля/сама схема смены цп.md | 49 --- .../docs/Формат блоков/Что пишем в solana.md | 27 -- .../структура блока/Запись в блокчейн.txt | 66 ---- .../структура блока/типы субблокченов.md | 13 - ...а_вопрос_о_блокчейне_каналах_и_расширяемости.md | 105 ------- 17 files changed, 14 insertions(+), 1293 deletions(-) rename {docs => Dev_Docs/Протоколы}/SHINE_ARWEAVE_DERIVATION_V1.md (100%) delete mode 100644 doc_todelite/DOC/libs/shine-main Описание базовых классов.md delete mode 100644 doc_todelite/DOC/Описание протокола.md delete mode 100644 doc_todelite/DOC/Формат Блокцейнов.md delete mode 100644 doc_todelite/shine-server-blockchain/src/main/промт для создания ОПИСАНИЯ ПРООТОКОЛА блокчейна.txt delete mode 100644 doc_todelite/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/entyties/help.txt delete mode 100644 doc_todelite/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/Описание протокола.md delete mode 100644 doc_todelite/src/main/doc_to_client_writer.txt delete mode 100644 doc_todelite/src/main/docs/Формат блоков/Описанией записей/Начало блокчейна.md delete mode 100644 doc_todelite/src/main/docs/Формат блоков/Смена Пароля/сама схема смены цп.md delete mode 100644 doc_todelite/src/main/docs/Формат блоков/Что пишем в solana.md delete mode 100644 doc_todelite/src/main/docs/Формат блоков/структура блока/Запись в блокчейн.txt delete mode 100644 doc_todelite/src/main/docs/Формат блоков/структура блока/типы субблокченов.md delete mode 100644 docs/Ответ_на_вопрос_о_блокчейне_каналах_и_расширяемости.md diff --git a/Dev_Docs/API/06_Channels_Read_API.md b/Dev_Docs/API/06_Channels_Read_API.md index 5ea7328..6008cc5 100644 --- a/Dev_Docs/API/06_Channels_Read_API.md +++ b/Dev_Docs/API/06_Channels_Read_API.md @@ -202,6 +202,13 @@ } ``` +### MessageNode (дополнение) +- `MessageNode` расширяет формат сообщения из `GetChannelMessages` и дополнительно содержит: + - `channelInfo` — мета-информация о канале (если применимо); + - `rawBlockB64` — сырой `block_bytes` текущего блока в Base64. +- Поле `rawBlockB64` присутствует у узлов во всех частях ответа `GetMessageThread`: `focus`, `ancestors[]`, `descendants[]`. +- В `GetChannelMessages` поле `rawBlockB64` **не добавляется** (лента канала без сырого блока, чтобы не раздувать ответ). + --- ## 4) GetChannelsCounters diff --git a/Dev_Docs/API/07_Channels_Feature_Runbook.md b/Dev_Docs/API/07_Channels_Feature_Runbook.md index a623693..e60af33 100644 --- a/Dev_Docs/API/07_Channels_Feature_Runbook.md +++ b/Dev_Docs/API/07_Channels_Feature_Runbook.md @@ -113,6 +113,11 @@ ### GetMessageThread - `payload.ancestors[]`, `payload.focus`, `payload.descendants[]`. - у узлов должны быть версии и счетчики. +- у каждого узла дополнительно может приходить `rawBlockB64` (Base64 сырого `block_bytes`). + +### Важно по совместимости +- `rawBlockB64` добавлен только в `GetMessageThread`. +- `GetChannelMessages` не содержит `rawBlockB64` (без изменений формата ленты). --- diff --git a/docs/SHINE_ARWEAVE_DERIVATION_V1.md b/Dev_Docs/Протоколы/SHINE_ARWEAVE_DERIVATION_V1.md similarity index 100% rename from docs/SHINE_ARWEAVE_DERIVATION_V1.md rename to Dev_Docs/Протоколы/SHINE_ARWEAVE_DERIVATION_V1.md diff --git a/VERSION.properties b/VERSION.properties index 0de0f55..ff45073 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.2.90 -server.version=1.2.84 +client.version=1.2.91 +server.version=1.2.85 diff --git a/doc_todelite/DOC/libs/shine-main Описание базовых классов.md b/doc_todelite/DOC/libs/shine-main Описание базовых классов.md deleted file mode 100644 index f7b926a..0000000 --- a/doc_todelite/DOC/libs/shine-main Описание базовых классов.md +++ /dev/null @@ -1,36 +0,0 @@ -краткая «памятка себе» по базовым классам и как они связаны. - -server.logic.InboundMessageProcessor (устаревший путь) - -Роль: маршрутизатор бинарного протокола: берёт входящие байты, читает первые 4 байта как op, находит MessageHandler и отдаёт ему сообщение. -Что возвращает: байтовый ответ хэндлера; при ошибках — 4 байта со статусом (BAD_REQUEST/INTERNAL_ERROR). -Важно: сейчас фактически не используется (карта HANDLERS пустая/закомментирована) — это «след» старого бинарного протокола, который вы заменили на JSON-WS. - -server.ws.BlockchainTmpRecoveryOnStartup - -Роль: «автослесарь» при старте: чинит последствия падения во время записи блокчейн-файла. -Логика: ищет *.tmp_bch в data/, сравнивает размеры tmp, main .bch и state.fileSizeBytes из БД. -Решения: -если stateSize == mainSize → tmp мусор, удаляем; -если stateSize == tmpSize → tmp актуален, атомарно заменяем main; -если не сходится / подозрительно (нет state, но есть main+tmp и т.п.) → CRITICAL + стоп сервера. -Итог: гарантирует, что на запуске не будет «тихо битого» блокчейна. - -server.ws.BlockchainWsEndpoint - -Роль: WS-эндпоинт Jetty, который принимает и бинарные, и текстовые сообщения. -Connect: сохраняет Session, кладёт её в ConnectionContext. -Binary: асинхронно вызывает InboundMessageProcessor.process(msg) и отправляет байтовый ответ. (Это тот самый устаревший путь.) -Text (JSON): асинхронно вызывает JsonInboundProcessor.processJson(message, connectionContext) и отправляет строку JSON. -Close: удаляет соединение из ActiveConnectionsRegistry, чистит ConnectionContext. -Смысл: один входной узел WS, где JSON — основной протокол, binary — “наследие”. - -server.ws.WsServer - -Роль: точка входа сервера. - -Порядок запуска: -BlockchainTmpRecoveryOnStartup.runRecoveryOrThrow() — если не смог починить/сопоставить → сервер не стартует; -читает порт из AppConfig (server.port), иначе 7070; -поднимает Jetty, конфигурирует WS-контейнер, маппит /ws → BlockchainWsEndpoint, ставит idleTimeout. -Итог: «бутстрап»: сначала безопасность файлов, потом сеть. \ No newline at end of file diff --git a/doc_todelite/DOC/Описание протокола.md b/doc_todelite/DOC/Описание протокола.md deleted file mode 100644 index b9a06d6..0000000 --- a/doc_todelite/DOC/Описание протокола.md +++ /dev/null @@ -1,286 +0,0 @@ -JSON WebSocket протокол сервера: список существующих запросов (op) - -Общий формат любого запроса (client → server): -op - имя операции (строка) -requestId - идентификатор запроса для связывания с ответом (строка) -payload - объект с параметрами конкретной операции (object) - -Общий формат любого ответа (server → client): -op - имя операции (строка, совпадает с запросом) -requestId - идентификатор запроса (строка, совпадает с запросом) -status - статус результата (200 = успех, другое = ошибка) -payload - объект с полями ответа (object; при ошибке содержит code/message) - -Группа: Авторизация и сессии - -Эта группа управляет входом пользователя, созданием/обновлением сессий и безопасным завершением активных подключений. - ------ AuthChallenge -Одноразовый шаг 1: по логину выдаёт nonce (authNonce), который затем подписывается на шаге 2. - -Запрос: -op - "AuthChallenge" -requestId - id запроса -login - логин пользователя, для которого начинается авторизация - -Ответ (успех): -op - "AuthChallenge" -requestId - id запроса -status - 200 если успех -authNonce - одноразовый nonce, Base64Url(32 bytes) без padding - -Ответ (ошибка): -op - "AuthChallenge" -requestId - id запроса -status - код ошибки -code - строковый код ошибки -message - человекочитаемое описание ошибки - ------ CreateAuthSession -Шаг 2: проверяет подпись владения ключом, создаёт новую active_session и возвращает sessionId/sessionPwd. - -Запрос: -op - "CreateAuthSession" -requestId - id запроса -storagePwd - ключ/пароль хранилища клиента, base64(32 bytes) -timeMs - время на клиенте в мс (для защиты от повторов и проверки рассинхрона) -signatureB64 - подпись Ed25519 над строкой "AUTHORIFICATED:" + timeMs + authNonce (base64) -clientInfo - короткая строка о клиенте/устройстве (до 50 символов), опционально - -Ответ (успех): -op - "CreateAuthSession" -requestId - id запроса -status - 200 если успех -sessionId - идентификатор сессии, Base64Url(32 bytes) -sessionPwd - секрет сессии, Base64Url(32 bytes) - -Ответ (ошибка): -op - "CreateAuthSession" -requestId - id запроса -status - код ошибки -code - строковый код ошибки -message - человекочитаемое описание ошибки - ------ RefreshSession -Повторный вход без подписи: проверяет sessionId+sessionPwd, обновляет метаданные сессии и возвращает storagePwd. - -Запрос: -op - "RefreshSession" -requestId - id запроса -sessionId - идентификатор ранее выданной сессии (base64/url-safe строка) -sessionPwd - секрет ранее выданной сессии (base64/url-safe строка) -clientInfo - короткая строка о клиенте/устройстве (до 50 символов), опционально - -Ответ (успех): -op - "RefreshSession" -requestId - id запроса -status - 200 если успех -storagePwd - пароль хранилища, сохранённый в сессии (base64(32 bytes)) - -Ответ (ошибка): -op - "RefreshSession" -requestId - id запроса -status - код ошибки -code - строковый код ошибки -message - человекочитаемое описание ошибки - ------ ListSessions -Возвращает список всех активных сессий текущего пользователя (для управления устройствами/входами). - -Запрос: -op - "ListSessions" -requestId - id запроса -timeMs - время на клиенте в мс (нужно только если статус AUTH_IN_PROGRESS) -signatureB64 - подпись Ed25519 над строкой "AUTHORIFICATED:" + timeMs + authNonce (нужно только если статус AUTH_IN_PROGRESS) - -Ответ (успех): -op - "ListSessions" -requestId - id запроса -status - 200 если успех -sessions - массив активных сессий пользователя - -Поля элемента sessions[i]: -sessionId - идентификатор сессии, Base64Url(32 bytes) -clientInfoFromClient - что прислал клиент в clientInfo -clientInfoFromRequest - что собрал сервер из окружения (UA/платформа и т.п.) -geo - строка "Country, City" или "unknown" -lastAuthirificatedAtMs - время последней успешной авторизации/refresh (мс) - -Ответ (ошибка): -op - "ListSessions" -requestId - id запроса -status - код ошибки -code - строковый код ошибки -message - человекочитаемое описание ошибки - ------ CloseActiveSession -Закрывает одну активную сессию пользователя (указанную или текущую), при необходимости подтверждая владение ключом подписью. - -Запрос: -op - "CloseActiveSession" -requestId - id запроса -sessionId - идентификатор сессии для закрытия (если пусто, закрывается текущая) -timeMs - время на клиенте в мс (нужно только если статус AUTH_IN_PROGRESS) -signatureB64 - подпись Ed25519 над строкой "AUTHORIFICATED:" + timeMs + authNonce (нужно только если статус AUTH_IN_PROGRESS) - -Ответ (успех): -op - "CloseActiveSession" -requestId - id запроса -status - 200 если успех - -Ответ (ошибка): -op - "CloseActiveSession" -requestId - id запроса -status - код ошибки -code - строковый код ошибки -message - человекочитаемое описание ошибки - -Группа: Блокчейн (загрузка блоков) - -Эта группа отвечает за приём и валидацию блоков (цепочка, линии, подпись/хэш) и атомарную запись в БД+файл. - ------ AddBlock -Добавляет следующий блок в конкретный blockchainName, строго проверяя номера, prev-хэши, линии, подпись и лимит размера. - -Запрос: -op - "AddBlock" -requestId - id запроса -blockchainName - имя цепочки (по нему вычисляется login) -globalNumber - глобальный номер добавляемого блока (должен быть serverLastGlobalNumber+1) -prevGlobalHash - HEX(64) предыдущего глобального хэша (или "" только там, где это допускается правилами) -blockBytesB64 - полный блок (raw+signature+hash) в Base64 - -Ответ (успех): -op - "AddBlock" -requestId - id запроса -status - 200 если успех -reasonCode - null при успехе -serverLastGlobalNumber - последний глобальный номер, который сервер считает актуальным после обработки -serverLastGlobalHash - последний глобальный хэш (HEX(64)) после обработки - -Ответ (ошибка): -op - "AddBlock" -requestId - id запроса -status - код ошибки (например 400/404/413/500) -reasonCode - строка причины (например bad_block_base64, bad_global_number, limit_exceeded и т.п.) -serverLastGlobalNumber - текущий серверный lastGlobalNumber -serverLastGlobalHash - текущий серверный lastGlobalHash (HEX(64), если известен) - -Группа: Параметры пользователя (UserParams) - -Эта группа хранит и отдаёт подписанные клиентом параметры (ключ-значение) для синхронизации и состояния. - ------ UpsertUserParam -Добавляет или обновляет параметр пользователя, проверяя подпись Ed25519 и применяя запись только если time_ms новее. - -Запрос: -op - "UpsertUserParam" -requestId - id запроса -login - логин пользователя -param - имя параметра -time_ms - метка времени значения в мс -value - значение параметра -device_key - публичный ключ устройства, base64(32 bytes) -signature - подпись Ed25519 от строки USER_PARAMETER_PREFIX + login + param + time_ms + value - -Ответ (успех): -op - "UpsertUserParam" -requestId - id запроса -status - 200 если успех - -Ответ (ошибка): -op - "UpsertUserParam" -requestId - id запроса -status - код ошибки -code - строковый код ошибки -message - человекочитаемое описание ошибки - ------ GetUserParam -Возвращает один сохранённый параметр пользователя. - -Запрос: -op - "GetUserParam" -requestId - id запроса -login - логин пользователя -param - имя параметра - -Ответ (успех): -op - "GetUserParam" -requestId - id запроса -status - 200 -login -param -time_ms -value -device_key -signature - -Ответ (не найдено): -op - "GetUserParam" -requestId -status - 404 - -Ответ (ошибка): -op -requestId -status -code -message - ------ ListUserParams -Возвращает все сохранённые параметры пользователя. - -Запрос: -op - "ListUserParams" -requestId -login - -Ответ (успех): -op -requestId -status - 200 -login -params - массив параметров - -Поля params[i]: -login -param -time_ms -value -device_key -signature - -Ответ (ошибка): -op -requestId -status -code -message - -Группа: Тестовые/временные операции - -Эта группа предназначена для отладки и первичного наполнения БД. - ------ AddUser -Тестовая регистрация локального пользователя. - -Запрос: -op - "AddUser" -requestId -login -blockchainName -solanaKey -deviceKey -bchLimit - -Ответ (успех): -op -requestId -status - 200 - -Ответ (ошибка): -op -requestId -status -code -message \ No newline at end of file diff --git a/doc_todelite/DOC/Формат Блокцейнов.md b/doc_todelite/DOC/Формат Блокцейнов.md deleted file mode 100644 index a12008f..0000000 --- a/doc_todelite/DOC/Формат Блокцейнов.md +++ /dev/null @@ -1,165 +0,0 @@ -нет это неправильно откатись к1) Общий формат записи блока (BchBlockEntry) - -Блок хранится как FULL = RAW + TAIL, где RAW участвует в хэшировании/подписи, а TAIL хранит подпись и итоговый хэш. - -RAW (BigEndian) - -recordSize [4] int32 — размер RAW в байтах (включая поля RAW-заголовка и bodyBytes), без signature64 и hash32. - -recordNumber [4] int32 — глобальный порядковый номер блока (сквозной по всему блокчейну). - -timestamp [8] int64 — Unix seconds (время создания блока). - -lineIndex [2] int16 — номер линии (канонические линии см. LineIndex). - -lineNumber [4] int32 — порядковый номер внутри выбранной линии. - -bodyBytes [N] bytes — тело блока, начинается с [type][version] (и дальше подформат конкретного body). - -TAIL (не входит в recordSize) - -signature64 [64] bytes — подпись Ed25519 над hash32. - -hash32 [32] bytes — SHA-256 от preimage (см. ниже). - -2) Как считается хэш и что подписываем (BchCryptoVerifier) - -preimage = - -"SHiNE" (ASCII) - -loginLen[1] + loginBytes[loginLen] (UTF-8, 1..255) - -prevGlobalHash32[32] - -prevLineHash32[32] - -rawBytes[recordSize] - -hash32 = SHA-256(preimage) -Далее верификация: - -hash32 должен совпасть с hash32, записанным в блоке. - -signature64 проверяется как Ed25519 подпись над hash32 публичным ключом пользователя. - -3) Типы body и разновидности (по 1 предложению на тип) - -HeaderBody (type=0) — генезис/идентификация блокчейна: фиксирует владельца (login) и тег формата. - -TextBody (type=1) — текстовое сообщение: либо новое, либо ответ (reply), либо репост (repost) со ссылкой на целевой блок. - -ReactionBody (type=2) — реакция на конкретный блок (в MVP — лайк) по ссылке на блок. - -ConnectionBody (type=3) — событие связи с другим пользователем (friend/contact/follow) или отмена этой связи. - -UserParamBody (type=4) — изменение/заявление одного параметра профиля в формате key/value. - -4) Общий формат bodyBytes (для всех body) - -type [2] int16 — код типа тела (0..4). - -version [2] int16 — версия формата конкретного типа (сейчас везде 1). - -subType [2] uint16 — подтип внутри типа (для Header всегда 0; для Text — NEW/REPLY/REPOST; для Reaction — LIKE; для Connection — set/unset + вид; для UserParam — TEXT_TEXT). - -payload [N] bytes — поля конкретного body (строго по формату; “мусор” в конце запрещён). - -5) Формат каждого типа body (по 1 строке на поле) - 5.1 HeaderBody (type=0, ver=1, lineIndex=0) - -type [2] — 0. - -version [2] — 1. - -subType [2] — 0 (compat). - -tag [5] — ASCII "SHiNE". - -loginLen [1] — длина login в UTF-8 (1..255). - -login [N] — login UTF-8 (^[A-Za-z0-9_]+$). - -5.2 TextBody (type=1, ver=1, lineIndex=1) - -type [2] — 1. - -version [2] — 1. - -subType [2] — 1=NEW, 2=REPLY, 3=REPOST. - -textLenBytes [2] — длина текста в байтах UTF-8 (1..65535). - -text [N] — текст UTF-8 (валидный, не blank). - -toBlockchainNameLen [1] — (только для REPLY/REPOST) длина имени блокчейна цели (1..255). - -toBlockchainName [N] — (только для REPLY/REPOST) UTF-8 имя блокчейна цели. - -toBlockGlobalNumber [4] — (только для REPLY/REPOST) globalNumber целевого блока. - -toBlockHash32 [32] — (только для REPLY/REPOST) raw-хэш целевого блока. - -5.3 ReactionBody (type=2, ver=1, lineIndex=2) - -type [2] — 2. - -version [2] — 1. - -subType [2] — 1=LIKE (зарезервировано под будущие реакции). - -toBlockchainNameLen [1] — длина имени блокчейна цели (1..255). - -toBlockchainName [N] — UTF-8 имя блокчейна цели. - -toBlockGlobalNumber [4] — globalNumber целевого блока. - -toBlockHash32 [32] — raw-хэш целевого блока. - -5.4 ConnectionBody (type=3, ver=1, lineIndex=3) - -type [2] — 3. - -version [2] — 1. - -subType [2] — 10/20/30 (FRIEND/CONTACT/FOLLOW) или 11/21/31 (UNFRIEND/UNCONTACT/UNFOLLOW). - -toLoginLen [1] — длина login цели (1..255). - -toLogin [N] — UTF-8 login цели (^[A-Za-z0-9_]+$). - -toBlockchainNameLen [1] — длина имени блокчейна цели (1..255). - -toBlockchainName [N] — UTF-8 имя блокчейна цели (снимок/якорь). - -toBlockGlobalNumber [4] — lastKnown globalNumber у цели (снимок/якорь). - -toBlockHash32 [32] — lastKnown hash у цели (снимок/якорь). - -5.5 UserParamBody (type=4, ver=1, lineIndex=4) - -type [2] — 4. - -version [2] — 1. - -subType [2] — 1=TEXT_TEXT. - -keyLenBytes [2] — длина ключа в байтах UTF-8 (1..65535). - -keyUtf8 [N] — ключ параметра UTF-8 (валидный, не blank). - -valueLenBytes [2] — длина значения в байтах UTF-8 (1..65535). - -valueUtf8 [M] — значение UTF-8 (валидное, не blank). - -6) Канонические линии (LineIndex) - -0 HEADER — генезис/идентификация. - -1 TEXT — сообщения. - -2 REACTION — реакции. - -3 CONNECTION — связи. - -4 USER_PARAM — параметры профиля. \ No newline at end of file diff --git a/doc_todelite/shine-server-blockchain/src/main/промт для создания ОПИСАНИЯ ПРООТОКОЛА блокчейна.txt b/doc_todelite/shine-server-blockchain/src/main/промт для создания ОПИСАНИЯ ПРООТОКОЛА блокчейна.txt deleted file mode 100644 index 69006b6..0000000 --- a/doc_todelite/shine-server-blockchain/src/main/промт для создания ОПИСАНИЯ ПРООТОКОЛА блокчейна.txt +++ /dev/null @@ -1,2 +0,0 @@ -НАПИШИ ВНАЧАЛЕ ФОРМАТ ОБЩЕГО ЗАГЛАВИЯ. -А ПОТОМ ФОРМАТ ПО КАЖДОМУ ТИПУ (И В НЁМ СУБТИПУ БЛОКОВ) ДЛЯ ЧЕГО НАДО, ЧТО ХРАНИТЬСЯ, КАКИЕ ПРАВИЛА И ОСОБЕННОСТИ ЗАПОЛНЕНИЯ diff --git a/doc_todelite/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/entyties/help.txt b/doc_todelite/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/entyties/help.txt deleted file mode 100644 index 4c56e1f..0000000 --- a/doc_todelite/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/entyties/help.txt +++ /dev/null @@ -1,39 +0,0 @@ -Net_AuthChallenge_Request — запрос вызова авторизации -Net_CreateAuthSession_Request — создание авторизационной сессии -Net_CloseAuthSession_Request — закрытие (завершение) сессии -Net_ListSessions_Request — получение списка активных сессий -Net_RefreshSession_Request — обновление / продление сессии - - - - - -Net_AuthChallenge_Request — запрос вызова авторизации -Net_CreateAuthSession_Request — создание авторизационной сессии - - -закрытие сессии -Net_CloseAuthSession_Request — закрытие (завершение) сессии - елси уже авторифицирован то: -Net_CloseAuthSession_Request с параметром номер сесии или без параметра если прям эту сесиию - если не авторифицирован то: -Net_AuthChallenge_Request — запрос вызова авторизации -Net_CloseAuthSession_Request с параметром номер сесии для закрытия и время и цп для подтвержедния - - -получение списка сессий - -Net_AuthChallenge_Request — запрос вызова авторизации -Net_ListSessions_Request — получение списка активных сессий - - -Net_RefreshSession_Request — обновление / продление сессии - - - -план что сделать - - получить список сесссий -и удалить сессию - -при новом подключении или при активной сесии diff --git a/doc_todelite/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/Описание протокола.md b/doc_todelite/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/Описание протокола.md deleted file mode 100644 index b9a06d6..0000000 --- a/doc_todelite/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/Описание протокола.md +++ /dev/null @@ -1,286 +0,0 @@ -JSON WebSocket протокол сервера: список существующих запросов (op) - -Общий формат любого запроса (client → server): -op - имя операции (строка) -requestId - идентификатор запроса для связывания с ответом (строка) -payload - объект с параметрами конкретной операции (object) - -Общий формат любого ответа (server → client): -op - имя операции (строка, совпадает с запросом) -requestId - идентификатор запроса (строка, совпадает с запросом) -status - статус результата (200 = успех, другое = ошибка) -payload - объект с полями ответа (object; при ошибке содержит code/message) - -Группа: Авторизация и сессии - -Эта группа управляет входом пользователя, созданием/обновлением сессий и безопасным завершением активных подключений. - ------ AuthChallenge -Одноразовый шаг 1: по логину выдаёт nonce (authNonce), который затем подписывается на шаге 2. - -Запрос: -op - "AuthChallenge" -requestId - id запроса -login - логин пользователя, для которого начинается авторизация - -Ответ (успех): -op - "AuthChallenge" -requestId - id запроса -status - 200 если успех -authNonce - одноразовый nonce, Base64Url(32 bytes) без padding - -Ответ (ошибка): -op - "AuthChallenge" -requestId - id запроса -status - код ошибки -code - строковый код ошибки -message - человекочитаемое описание ошибки - ------ CreateAuthSession -Шаг 2: проверяет подпись владения ключом, создаёт новую active_session и возвращает sessionId/sessionPwd. - -Запрос: -op - "CreateAuthSession" -requestId - id запроса -storagePwd - ключ/пароль хранилища клиента, base64(32 bytes) -timeMs - время на клиенте в мс (для защиты от повторов и проверки рассинхрона) -signatureB64 - подпись Ed25519 над строкой "AUTHORIFICATED:" + timeMs + authNonce (base64) -clientInfo - короткая строка о клиенте/устройстве (до 50 символов), опционально - -Ответ (успех): -op - "CreateAuthSession" -requestId - id запроса -status - 200 если успех -sessionId - идентификатор сессии, Base64Url(32 bytes) -sessionPwd - секрет сессии, Base64Url(32 bytes) - -Ответ (ошибка): -op - "CreateAuthSession" -requestId - id запроса -status - код ошибки -code - строковый код ошибки -message - человекочитаемое описание ошибки - ------ RefreshSession -Повторный вход без подписи: проверяет sessionId+sessionPwd, обновляет метаданные сессии и возвращает storagePwd. - -Запрос: -op - "RefreshSession" -requestId - id запроса -sessionId - идентификатор ранее выданной сессии (base64/url-safe строка) -sessionPwd - секрет ранее выданной сессии (base64/url-safe строка) -clientInfo - короткая строка о клиенте/устройстве (до 50 символов), опционально - -Ответ (успех): -op - "RefreshSession" -requestId - id запроса -status - 200 если успех -storagePwd - пароль хранилища, сохранённый в сессии (base64(32 bytes)) - -Ответ (ошибка): -op - "RefreshSession" -requestId - id запроса -status - код ошибки -code - строковый код ошибки -message - человекочитаемое описание ошибки - ------ ListSessions -Возвращает список всех активных сессий текущего пользователя (для управления устройствами/входами). - -Запрос: -op - "ListSessions" -requestId - id запроса -timeMs - время на клиенте в мс (нужно только если статус AUTH_IN_PROGRESS) -signatureB64 - подпись Ed25519 над строкой "AUTHORIFICATED:" + timeMs + authNonce (нужно только если статус AUTH_IN_PROGRESS) - -Ответ (успех): -op - "ListSessions" -requestId - id запроса -status - 200 если успех -sessions - массив активных сессий пользователя - -Поля элемента sessions[i]: -sessionId - идентификатор сессии, Base64Url(32 bytes) -clientInfoFromClient - что прислал клиент в clientInfo -clientInfoFromRequest - что собрал сервер из окружения (UA/платформа и т.п.) -geo - строка "Country, City" или "unknown" -lastAuthirificatedAtMs - время последней успешной авторизации/refresh (мс) - -Ответ (ошибка): -op - "ListSessions" -requestId - id запроса -status - код ошибки -code - строковый код ошибки -message - человекочитаемое описание ошибки - ------ CloseActiveSession -Закрывает одну активную сессию пользователя (указанную или текущую), при необходимости подтверждая владение ключом подписью. - -Запрос: -op - "CloseActiveSession" -requestId - id запроса -sessionId - идентификатор сессии для закрытия (если пусто, закрывается текущая) -timeMs - время на клиенте в мс (нужно только если статус AUTH_IN_PROGRESS) -signatureB64 - подпись Ed25519 над строкой "AUTHORIFICATED:" + timeMs + authNonce (нужно только если статус AUTH_IN_PROGRESS) - -Ответ (успех): -op - "CloseActiveSession" -requestId - id запроса -status - 200 если успех - -Ответ (ошибка): -op - "CloseActiveSession" -requestId - id запроса -status - код ошибки -code - строковый код ошибки -message - человекочитаемое описание ошибки - -Группа: Блокчейн (загрузка блоков) - -Эта группа отвечает за приём и валидацию блоков (цепочка, линии, подпись/хэш) и атомарную запись в БД+файл. - ------ AddBlock -Добавляет следующий блок в конкретный blockchainName, строго проверяя номера, prev-хэши, линии, подпись и лимит размера. - -Запрос: -op - "AddBlock" -requestId - id запроса -blockchainName - имя цепочки (по нему вычисляется login) -globalNumber - глобальный номер добавляемого блока (должен быть serverLastGlobalNumber+1) -prevGlobalHash - HEX(64) предыдущего глобального хэша (или "" только там, где это допускается правилами) -blockBytesB64 - полный блок (raw+signature+hash) в Base64 - -Ответ (успех): -op - "AddBlock" -requestId - id запроса -status - 200 если успех -reasonCode - null при успехе -serverLastGlobalNumber - последний глобальный номер, который сервер считает актуальным после обработки -serverLastGlobalHash - последний глобальный хэш (HEX(64)) после обработки - -Ответ (ошибка): -op - "AddBlock" -requestId - id запроса -status - код ошибки (например 400/404/413/500) -reasonCode - строка причины (например bad_block_base64, bad_global_number, limit_exceeded и т.п.) -serverLastGlobalNumber - текущий серверный lastGlobalNumber -serverLastGlobalHash - текущий серверный lastGlobalHash (HEX(64), если известен) - -Группа: Параметры пользователя (UserParams) - -Эта группа хранит и отдаёт подписанные клиентом параметры (ключ-значение) для синхронизации и состояния. - ------ UpsertUserParam -Добавляет или обновляет параметр пользователя, проверяя подпись Ed25519 и применяя запись только если time_ms новее. - -Запрос: -op - "UpsertUserParam" -requestId - id запроса -login - логин пользователя -param - имя параметра -time_ms - метка времени значения в мс -value - значение параметра -device_key - публичный ключ устройства, base64(32 bytes) -signature - подпись Ed25519 от строки USER_PARAMETER_PREFIX + login + param + time_ms + value - -Ответ (успех): -op - "UpsertUserParam" -requestId - id запроса -status - 200 если успех - -Ответ (ошибка): -op - "UpsertUserParam" -requestId - id запроса -status - код ошибки -code - строковый код ошибки -message - человекочитаемое описание ошибки - ------ GetUserParam -Возвращает один сохранённый параметр пользователя. - -Запрос: -op - "GetUserParam" -requestId - id запроса -login - логин пользователя -param - имя параметра - -Ответ (успех): -op - "GetUserParam" -requestId - id запроса -status - 200 -login -param -time_ms -value -device_key -signature - -Ответ (не найдено): -op - "GetUserParam" -requestId -status - 404 - -Ответ (ошибка): -op -requestId -status -code -message - ------ ListUserParams -Возвращает все сохранённые параметры пользователя. - -Запрос: -op - "ListUserParams" -requestId -login - -Ответ (успех): -op -requestId -status - 200 -login -params - массив параметров - -Поля params[i]: -login -param -time_ms -value -device_key -signature - -Ответ (ошибка): -op -requestId -status -code -message - -Группа: Тестовые/временные операции - -Эта группа предназначена для отладки и первичного наполнения БД. - ------ AddUser -Тестовая регистрация локального пользователя. - -Запрос: -op - "AddUser" -requestId -login -blockchainName -solanaKey -deviceKey -bchLimit - -Ответ (успех): -op -requestId -status - 200 - -Ответ (ошибка): -op -requestId -status -code -message \ No newline at end of file diff --git a/doc_todelite/src/main/doc_to_client_writer.txt b/doc_todelite/src/main/doc_to_client_writer.txt deleted file mode 100644 index c1705f1..0000000 --- a/doc_todelite/src/main/doc_to_client_writer.txt +++ /dev/null @@ -1,172 +0,0 @@ -Сервер SHiNE Blockchain представляет собой бинарный WebSocket-сервис, обрабатывающий запросы клиентов в виде бинарных пакетов и возвращающий также бинарные ответы. Сервер управляет пользовательскими цепочками блоков (файлы формата .bch), проверяет подписи Ed25519 и хэши SHA-256, сохраняет данные на диск и позволяет получать информацию о состоянии цепочек и искать пользователей. Все цепочки и метаданные хранятся локально, без базы данных. Цепочки записываются в файлы data/{id}.bch, а сводная информация о пользователях хранится в JSON-файле data/blockchain_info.json. - -Подключение клиента происходит по WebSocket на адрес ws://localhost:8080/ws или wss://shineup.me/ws. Протокол полностью бинарный, без текстовых или JSON-данных. Каждое сообщение клиента — отдельный бинарный пакет, сервер отвечает отдельным бинарным пакетом. Можно отправлять несколько запросов подряд, они обрабатываются независимо и асинхронно. - -Любое сообщение клиента начинается с 4 байт, которые определяют тип операции (opCode). Данные кодируются в big-endian. После первых четырёх байт следует полезная нагрузка, структура которой зависит от конкретной операции. Ответ сервера также начинается с 4 байт — это код состояния (statusCode), после которого могут следовать дополнительные данные. - -Основные операции протокола имеют следующие коды: 0 — PING, 1 — ADD_BLOCK, 2 — GET_BLOCKCHAIN, 30 — SEARCH_USERS. Код 0 используется для проверки соединения, сервер отвечает кодом 100 (PONG). Код 1 добавляет блок в цепочку. Код 2 возвращает полный бинарный файл блокчейна. Код 30 выполняет поиск пользователей по подстроке логина. - -Коды ответов статусов: 100 (PONG) — ответ на пинг, 200 (OK) — операция успешна, 400 (BAD_REQUEST) — ошибка формата или данных, 404 (NOT_FOUND) — цепочка не найдена, 409 (ALREADY_EXISTS) — блок с таким номером уже существует, 412 (NON_SEQUENTIAL) — получен блок с номером больше ожидаемого, 422 (UNVERIFIED) — не совпал хэш или подпись, 500 (INTERNAL_ERROR) — исключение или внутренняя ошибка сервера. Все коды возвращаются в виде четырёх байт BigEndian. - -Операция PING проста: клиент отправляет 4 байта со значением 0, сервер отвечает 4 байтами со значением 100. Это нужно для проверки активности соединения. - -Главная операция — ADD_BLOCK (код 1). Она используется для добавления нового блока в существующую или новую цепочку. Формат запроса: первые 4 байта — число 1 (код операции), следующие 8 байт — идентификатор цепочки blockchainId в формате long BigEndian. После этого следует бинарный блок формата .bch, который полностью включает данные, подпись и хэш. - -Формат файла .bch состоит из последовательности блоков без промежутков. Каждый блок имеет вид RAW + подпись (64 байта) + хэш (32 байта). RAW-часть состоит из заголовка размером 20 байт и тела произвольной длины. В заголовке содержатся поля: recordSize (4 байта, общий размер RAW), recordNumber (4 байта, порядковый номер блока), timestamp (8 байт, UNIX-время), recordType (2 байта, тип тела, 0=Header, 1=Text), recordTypeVersion (2 байта, версия структуры данного типа). После этого идёт само тело блока (body). - -Тело блока определяется по типу. Тип 0 — HeaderBody, заголовок цепочки, создающий новую цепочку. Тип 1 — TextBody, простой текстовый блок. Для новых цепочек допускается только блок типа 0 с номером 0. - -Когда сервер получает ADD_BLOCK, он сначала извлекает blockchainId и пытается найти информацию о цепочке в BchInfoManager. Если цепочки нет, то сервер допускает только блок-заголовок (type=0, num=0). Он парсится как HeaderBody, проверяется корректность логина, совпадение blockchainId и валидность подписи. Предыдущий хэш для первого блока считается нулевым (32 байта нулей). Если всё совпадает, создаётся новая запись о цепочке, создаётся файл data/{id}.bch, туда записывается бинарный блок, и в blockchain_info.json добавляется запись с логином, публичным ключом и текущим номером блока. Если в этом сценарии блок не является HeaderBody, или подпись невалидна, или blockchainId в теле не совпадает с заголовком — сервер возвращает код ошибки (обычно 400 или 422). - -Если цепочка существует, сервер проверяет, что номер нового блока ровно на единицу больше последнего (lastBlockNumber + 1). Если номер меньше, возвращается 409 (блок уже есть), если больше — 412 (пропуск в номерах). После этого сервер берёт хэш последнего блока, собирает канонический preimage (логин UTF-8 + blockchainId + prevHash32 + rawBytes), вычисляет SHA-256, сравнивает с переданным hash32 и проверяет подпись Ed25519. Если оба совпадают, тело блока парсится (TextBody или другой тип), выполняется его логическая проверка (check). После успешной проверки блок дописывается в файл .bch, обновляется информация о состоянии цепочки (последний номер, новый хэш, общий размер). Если подпись или хэш не совпали, сервер возвращает 422. - -Валидация подписи и хэша выполняется в классе BchCryptoVerifier. Preimage собирается из последовательности байт: сначала логин UTF-8 (без длины), затем 8 байт blockchainId BigEndian, затем 32 байта предыдущего хэша, затем сырые байты блока (RAW без подписи и хэша). Далее вычисляется SHA-256(preimage) и проверяется, что hash32 совпадает с ним. Подпись проверяется как Ed25519(preimage, publicKey32). Если хотя бы одна проверка не пройдена — блок отклоняется. - -Операция GET_BLOCKCHAIN (код 2) используется для получения всего бинарного содержимого цепочки. Формат запроса: первые 4 байта — код 2, следующие 8 байт — blockchainId (BigEndian). Ответ сервера начинается с 4 байт (200 при успехе), затем 4 байта длины данных, затем идут байты содержимого файла целиком. Если цепочка не найдена, возвращается 404. Если произошла ошибка чтения — 500. Таким образом клиент может загрузить весь блокчейн-файл и при необходимости сам распарсить блоки. - -Операция SEARCH_USERS (код 30) выполняет поиск логинов по подстроке. Формат запроса: первые 4 байта — код 30, следующие 4 байта — длина строки поиска N, затем N байт UTF-8 текста. Сервер выполняет поиск без учёта регистра по всем логинам, известным в blockchain_info.json, и возвращает максимум 5 совпадений. Ответ состоит из 4 байт (200 при успехе), затем 4 байт числа найденных пар, затем для каждой пары: 8 байт blockchainId BigEndian, 1 байт длины логина L, и L байт логина UTF-8 в оригинальном регистре. Если ничего не найдено, сервер возвращает 200 и число 0. Если запрос некорректен, возвращается 400. - -Файловая система сервера устроена просто: в каталоге data хранятся все файлы. Каждый блокчейн имеет свой файл с именем {id}.bch. В этом файле последовательно записаны блоки в двоичном виде. Параллельно существует файл blockchain_info.json — JSON-объект, где ключ — blockchainId, а значение — структура с логином, публичным ключом в Base64, последним номером блока, хэшем последнего блока и размером цепочки. При добавлении нового блока сервер обновляет запись и сохраняет JSON на диск. - -Сервер не требует аутентификации — безопасность обеспечивается криптографией: только владелец приватного ключа может подписывать блоки своей цепочки. Публичный ключ хранится в первом блоке HeaderBody и проверяется при добавлении. - -Таким образом, чтобы написать клиент, нужно: - -Уметь подключаться по WebSocket (ws или wss). - -Формировать бинарные пакеты в формате BigEndian. - -Для создания новой цепочки сгенерировать пару ключей Ed25519, собрать HeaderBody (с полями blockchainId, логин, публичный ключ), сериализовать его в байты, упаковать в блок типа 0 с номером 0, подписать preimage, добавить подпись и хэш, и отправить через ADD_BLOCK. - -Для добавления обычного блока (тип 1) использовать тот же алгоритм: собрать preimage из логина, id, предыдущего хэша и RAW-байтов, подписать, прикрепить подпись и хэш, отправить. - -Для чтения — вызвать GET_BLOCKCHAIN и распарсить ответ. - -Для поиска пользователей — отправить SEARCH_USERS и распарсить пары. - -Для проверки соединения — PING. - -Все числовые значения всегда в BigEndian. Все строки в UTF-8. Все подписи — Ed25519 длиной 64 байта. Все хэши — SHA-256 длиной 32 байта. - -Типы тел блоков: -HeaderBody (тип 0) содержит фиксированные поля: ASCII тег "SHiNE", blockchainId (8 байт), длину логина, логин UTF-8, четыре зарезервированных числа (type, number, version, prevId), и 32 байта публичного ключа. -TextBody (тип 1) содержит просто UTF-8-строку без дополнительных полей. - -Клиент, который реализует этот протокол, должен уметь: открывать WebSocket-соединение, отправлять бинарные пакеты по описанным форматам, вычислять SHA-256 и подписи Ed25519, и интерпретировать ответы сервера по первым четырём байтам статуса. Вся логика взаимодействия основана на простых числовых кодах и фиксированных структурах без сложных заголовков. - -Главное правило — сервер никогда не принимает блок, если не совпадает подпись или хэш. Поэтому клиент обязан правильно формировать preimage и использовать правильный публичный/приватный ключ. Также сервер строго следит за порядком номеров блоков. Валидация тела блока проверяет только базовую корректность (непустой логин, корректный UTF-8). Все остальные проверки лежат на клиенте. - -В результате взаимодействия через этот протокол клиент может создавать собственные цепочки блоков, добавлять в них данные, загружать свои или чужие цепочки и искать пользователей по логину. Формат прост, двоичный и полностью детерминирован. - - -Формат блока .bch является центральным элементом протокола. Каждый блок хранится последовательно, без промежутков. Цепочка — это просто последовательность таких блоков, записанных подряд в бинарный файл. Каждый блок состоит из трёх частей: RAW-часть (все данные без подписи и хэша), подпись длиной 64 байта и хэш длиной 32 байта. Общая длина блока равна длине RAW + 96 байт. Сервер при чтении файла просто двигается от начала к концу, разбирая один блок за другим, опираясь на поле recordSize, которое всегда указывает длину RAW-части (тело без подписи и хэша). - -RAW-часть имеет фиксированный формат и начинается с 20 байт заголовка. Эти 20 байт — это общая «шапка» для любого типа блока. В ней хранятся: - -recordSize — 4 байта, целое число BigEndian, равное длине всей RAW-части (20 + длина тела). - -recordNumber — 4 байта, номер блока в цепочке, начиная с нуля. - -timestamp — 8 байт, время создания блока в секундах Unix Time. - -recordType — 2 байта, короткое число, тип тела (0 = HeaderBody, 1 = TextBody, в будущем могут быть другие). - -recordTypeVersion — 2 байта, версия структуры тела (для HeaderBody всегда 1, для TextBody тоже 1). -После этих 20 байт сразу идёт тело блока (body), которое имеет разный формат в зависимости от типа. - -Тип 0 — HeaderBody, заголовочный блок, всегда имеет номер 0 и используется для создания новой цепочки. Его структура тела строго определена и содержит: -• 8 байт ASCII-строки “SHiNE” — это сигнатура формата. -• 8 байт long BigEndian — blockchainId, уникальный идентификатор цепочки. -• 1 байт — длина логина пользователя N. -• N байт — логин пользователя в UTF-8 (без завершающего нуля). -• 4 байта int BigEndian — blockchainType (пока всегда 0). -• 4 байта int BigEndian — blockchainNumber (пока всегда 0). -• 2 байта short BigEndian — версия формата пользователя (всегда 1). -• 8 байт long BigEndian — prevUserBchId (всегда 0). -• 32 байта — публичный ключ пользователя Ed25519 (publicKey32). - -После этих данных никакого дополнительного контента нет. Суммарная длина тела зависит от длины логина. Таким образом, для HeaderBody: длина RAW = 20 + (8 + 8 + 1 + N + 4 + 4 + 2 + 8 + 32). Этот блок полностью описывает владельца цепочки и его публичный ключ. При создании нового блокчейна сервер разрешает только один такой блок с номером 0 и типом 0. - -Тип 1 — TextBody, обычный текстовый блок. Его тело состоит только из текста UTF-8, без дополнительных метаданных. Это могут быть сообщения, комментарии, данные или команды. Любые последующие блоки (номер 1, 2, 3 и т.д.) обычно имеют тип 1. При сериализации тело просто представляет собой байты строки в кодировке UTF-8. - -После RAW-части добавляются две секции: подпись (signature64) и хэш (hash32). Подпись — это 64 байта, результат Ed25519.sign(preimage, privateKey). Хэш — это 32 байта, результат SHA-256(preimage). - -Ключевое понятие — preimage. Это каноническая бинарная последовательность, из которой формируется хэш и подпись. Она состоит из следующих частей, строго в указанном порядке: - -байты логина пользователя в UTF-8 (без длины, просто сами байты); - -8 байт идентификатора цепочки blockchainId в формате long BigEndian; - -32 байта предыдущего хэша prevHash32 (для самого первого блока — это 32 нуля); - -байты RAW-части (включая заголовок и тело, но без подписи и хэша). - -Из этого preimage берутся два результата: -• hash32 = SHA-256(preimage) -• signature64 = Ed25519.sign(preimage, privateKey32) - -Хэш хранится в блоке в конце и используется для проверки целостности при добавлении следующего блока. Следующий блок при вычислении своего preimage уже использует этот хэш как prevHash32. Таким образом, создаётся цепочка зависимых хэшей, образующих полную криптографическую связанность всех блоков. Подпись подтверждает, что именно владелец приватного ключа подписал блок. Сервер проверяет это через Ed25519.verify(preimage, signature64, publicKey32). - -Итоговая структура полного блока (FULL) выглядит так: -• 4 байта recordSize -• 4 байта recordNumber -• 8 байт timestamp -• 2 байта recordType -• 2 байта recordTypeVersion -• M байт body -• 64 байта signature64 -• 32 байта hash32 - -Общая длина блока равна recordSize + 96. При чтении из файла сервер сначала берёт recordSize, по нему знает, где заканчивается тело, а после этого считывает ещё 64 байта подписи и 32 байта хэша. - -Важно понимать: сервер не принимает блок, если хотя бы одно из условий нарушено — несоответствие длины, некорректный UTF-8 в теле, неправильная подпись, неверный хэш или сбитая последовательность номеров. Сервер также не принимает новый блок, если его номер не совпадает с ожидаемым (т.е. если цепочка уже имеет последний номер N, следующий блок должен иметь номер N+1). - -При генерации нового блока клиент должен выполнить последовательность шагов: - -Собрать тело блока (body). Для HeaderBody — с нужным логином и публичным ключом. Для TextBody — просто текст. - -Сформировать RAW-часть: заполнить 20 байт заголовка, указать длину тела, номер блока, время, тип и версию, затем добавить тело. - -Собрать preimage (логин UTF-8 + blockchainId + prevHash32 + rawBytes). Для первого блока prevHash32 — 32 нуля. - -Посчитать SHA-256(preimage) и сохранить как hash32. - -Подписать preimage своим приватным ключом Ed25519 и получить signature64. - -Объединить rawBytes + signature64 + hash32 в один массив. - -Отправить этот массив серверу в запросе ADD_BLOCK (после поля blockchainId). - -Если всё сделано правильно, сервер проверит подпись и хэш, убедится, что цепочка корректна, и добавит блок. В случае успеха сервер вернёт 200. Если подпись или хэш неверные — 422. Если номер блока не совпадает с ожидаемым — 409 или 412. - -Таким образом, клиент может последовательно создавать цепочку блоков, где каждый следующий блок зависит от предыдущего через хэш. Формат абсолютно детерминирован и не допускает вариаций. Все целые числа записываются в формате BigEndian. Все строки кодируются в UTF-8 без завершающего нуля. Все подписи Ed25519 имеют длину 64 байта, все хэши SHA-256 имеют длину 32 байта. Цепочка считается валидной, если каждый блок проходит проверку по своей подписи и хэшу, а номера блоков непрерывны от 0 и далее. - -Эта структура едина как для клиентской стороны, так и для сервера. Клиент, следуя этому формату, способен полностью создавать, подписывать и проверять блоки офлайн, а затем синхронизировать их с сервером, просто отправляя бинарные блоки в ADD_BLOCK. Сервер при получении блока повторяет ту же логику вычисления preimage и сверяет подпись и хэш, гарантируя, что ни один байт блока не был изменён. - -Таким образом, формат блока .bch является криптографически связанной последовательностью структур, каждая из которых включает заголовок, тело, подпись и хэш, и все они формируют надёжную цепочку данных, проверяемую без участия центральной базы данных. - - - - -Рекомендации для клиента и описание операции GET_LAST_BLOCK_INFO. - -Клиент хранит у себя приватный ключ пользователя, который никогда не передаётся серверу. Из этого приватного ключа вычисляется публичный ключ Ed25519, который используется для подписи блоков и проверки на сервере. Публичный ключ передаётся только один раз — внутри первого блока HeaderBody, создающего новую цепочку. После этого сервер хранит у себя только публичный ключ и логин пользователя, и проверяет подписи всех следующих блоков именно по нему. Приватный ключ остаётся исключительно у клиента. - -Клиент может создавать приватный ключ двумя способами. Первый — случайная генерация 32 байт (seed) через криптографический генератор случайных чисел. Второй, более удобный — детерминированная генерация из пароля пользователя: берётся строка пароля UTF-8, вычисляется SHA-256 от неё, и результат (32 байта) используется как приватный ключ. Это позволяет восстановить тот же ключ из одного и того же пароля без хранения seed в явном виде. Из приватного ключа вычисляется публичный через Ed25519. Таким образом, клиент может всегда получить ту же пару (private/public), просто имея пароль. - -На стороне клиента рекомендуется хранить три параметра для каждой цепочки: приватный ключ (или пароль, из которого он создаётся), публичный ключ и идентификатор цепочки blockchainId. Идентификатор цепочки — это уникальное 8-байтное число (long), которое выбирается клиентом при создании новой цепочки. Он может быть сгенерирован случайно, взят из системного счётчика или рассчитан как часть хэша от логина, но сервер не навязывает конкретный способ — важно только, чтобы значение было уникально. - -Для синхронизации с сервером клиент должен отслеживать состояние последнего блока: его номер и хэш. Эти значения необходимы при формировании следующего блока, чтобы корректно подставить prevHash32 в preimage. Сервер предоставляет отдельную операцию для получения этой информации. - -Операция GET_LAST_BLOCK_INFO имеет код 31 и используется для запроса состояния выбранной цепочки. Клиент отправляет запрос, состоящий из 12 байт: первые 4 байта — код операции (int 31 в BigEndian), следующие 8 байт — идентификатор цепочки blockchainId (long BigEndian). Сервер проверяет наличие цепочки и возвращает 40 байт данных. - -Ответ от сервера имеет следующую структуру: -• 4 байта — код статуса (200 при успехе, 404 если цепочка не найдена, 500 при ошибке); -• 4 байта — номер последнего блока (int BigEndian, если цепочка пуста — 0); -• 32 байта — хэш последнего блока SHA-256 (если цепочка пуста, все нули). - -Таким образом, клиент может в любой момент узнать, до какого блока сервер синхронизирован, чтобы не отправлять повторно уже существующие данные. Если сервер вернул 404, это значит, что цепочка с указанным blockchainId ещё не существует, и клиент может начать новую, отправив HeaderBody через ADD_BLOCK. Если сервер вернул 200, клиент использует полученный номер и хэш для формирования следующего блока: новый recordNumber должен быть на единицу больше полученного, а prevHash32 при вычислении preimage — это хэш, возвращённый сервером. - -Рекомендуется, чтобы клиент при каждом запуске сначала вызывал GET_LAST_BLOCK_INFO для своей цепочки, сверял локальное состояние с сервером, и только после этого создавал или отправлял новые блоки. Это обеспечивает целостность цепочки и правильную последовательность номеров. - -Таким образом, клиент хранит у себя всё необходимое для подписи и создания блоков — приватный ключ, логин, blockchainId и последнее состояние. Сервер же хранит только публичный ключ, логин, текущий номер блока и последний хэш. Все вычисления подписи и хэша выполняются клиентом локально. Это гарантирует, что сервер не может подделать или изменить ни один блок, а клиент при необходимости может полностью восстановить всю цепочку, просто имея свой пароль или приватный ключ. diff --git a/doc_todelite/src/main/docs/Формат блоков/Описанией записей/Начало блокчейна.md b/doc_todelite/src/main/docs/Формат блоков/Описанией записей/Начало блокчейна.md deleted file mode 100644 index a418a55..0000000 --- a/doc_todelite/src/main/docs/Формат блоков/Описанией записей/Начало блокчейна.md +++ /dev/null @@ -1,45 +0,0 @@ -* ============================================================================ -* HeaderBody — тело записи типа 0 (заглавие блокчейна) -* ============================================================================ -* -* 🧩 Назначение: -* Первый блок каждой пользовательской цепочки (.bch) — это "заголовок". -* Он хранит базовую информацию о владельце, версии и публичном ключе. -* -* Этот блок всегда имеет: -* • recordType = 0 -* • recordNumber = 0 -* • recordTypeVersion = 1 -* -* ---------------------------------------------------------------------------- -* 🔹 Формат body (без общих 20 байт заголовка блока BchBlock) -* -* | Смещение | Размер | Поле | Формат | Описание | -* |-----------|--------|--------------------|---------|-----------| -* | 0x00 | 8 | tag | ASCII | Статическая сигнатура "SHiNE" | -* -* | 0x10 | 1 | userLoginLength=N | uint8 | Длина логина пользователя | -* | 0x11 | N | userLogin | UTF-8 | Логин пользователя | - -* | 0x11+N | 4 | blockchainType | int BE | Зарезервировано (всегда 0) | - - -* | 0x08 | 8 | blockchainId | long BE | Уникальный идентификатор цепочки | -* | 0x11+N | 4 | blockchainType | int BE | Зарезервировано (всегда 0) | -* | 0x15+N | 4 | blockchainNumber | int BE | Зарезервировано (всегда 0) | -* | 0x19+N | 2 | versionUserBch | short BE| Версия формата (всегда 1) | -* | 0x1B+N | 8 | prevUserBchId | long BE | Зарезервировано (всегда 0) | -* | 0x23+N | 32 | publicKey32 | raw | Публичный ключ (Ed25519, 32 байта) | -* -* ---------------------------------------------------------------------------- -* 💡 Пример структуры в байтах: -* -* 0000: 53 48 69 4E 45 30 30 31 "SHiNE" -* 0008: 00 00 00 00 01 23 45 67 blockchainId -* 0010: 05 userLoginLength = 5 -* 0011: 41 69 64 61 72 userLogin = "Aidar" -* 0016: 00 00 00 00 blockchainType = 0 -* 001A: 00 00 00 00 blockchainNumber = 0 -* 001E: 00 01 versionUserBch = 1 -* 0020: 00 00 00 00 00 00 00 00 prevUserBchId = 0 -* 0028: [32 байта публичного ключа] \ No newline at end of file diff --git a/doc_todelite/src/main/docs/Формат блоков/Смена Пароля/сама схема смены цп.md b/doc_todelite/src/main/docs/Формат блоков/Смена Пароля/сама схема смены цп.md deleted file mode 100644 index 566bc0e..0000000 --- a/doc_todelite/src/main/docs/Формат блоков/Смена Пароля/сама схема смены цп.md +++ /dev/null @@ -1,49 +0,0 @@ -Solana говорит актуальные -userLogin -userId - -Текущий номер блокчейна - -И Список Доверенных (userId, дата добавления) -.. Добавить доверенного -.. Убавить доверенного - - ------------------------- -И на каждый блокчен : -UserBlcId -UserBlcSig -UserBlcLimit лимит МБ этого блокчейна - -uerId -Какой это по счёту блокчейн у пользователя -Ид преведущего блокчейна - ------------------ - Можно в солане -Добавить доверенного -Удалить доверенного -Сменить свою подпись (приложив строки с подписью доверенных) - -И задержка на 30 дней довступления в силу -(А со старта можно и без задержки главное библиотеку для доступа к сушностям в солане на js сразу генерировать вместе с растом :)) - -и ещё создать запись для смены ( и пох если зделал то сделал откатить нельзя можнотолько что бы все остальные не голосовали) --------------- - - -Можно делать технические записи (они совпадают с соланой) - -В самом начале блок №0 -userLogin - userId - -блок №1 -UserBlcId - UserBlcSig - - - -Это чисто записи -Добавить доверенного -Убавить доверенного -Добавить лимит - diff --git a/doc_todelite/src/main/docs/Формат блоков/Что пишем в solana.md b/doc_todelite/src/main/docs/Формат блоков/Что пишем в solana.md deleted file mode 100644 index 22ac27f..0000000 --- a/doc_todelite/src/main/docs/Формат блоков/Что пишем в solana.md +++ /dev/null @@ -1,27 +0,0 @@ -Первый это ссылка (Пда по логину, у него двва ключа "login" и сам логин пользователя (1 байт длинна + логин до 30 символов)) -В логине можно a-z 0-9 и "_" - -В нём записано - Посути нуден только UserId -А так можно -+ вначале 8 байт константа типо ПДА -+ Сам логин с заклавными буквами (не надо) -+ Цп (не надо) - - -Второй блокчен -(ПДА по двум ключам?? Ид) - - -+ вначале 8 байт константа типо ПДА -+ 1 байт - N длинна логина -+ N байт - сам логин (можно с большими буквами) - - - - - - - - - diff --git a/doc_todelite/src/main/docs/Формат блоков/структура блока/Запись в блокчейн.txt b/doc_todelite/src/main/docs/Формат блоков/структура блока/Запись в блокчейн.txt deleted file mode 100644 index c61466b..0000000 --- a/doc_todelite/src/main/docs/Формат блоков/структура блока/Запись в блокчейн.txt +++ /dev/null @@ -1,66 +0,0 @@ - * ============================================================================ - * BchBlockEntry — универсальная запись блокчейна SHiNE (.bch) - * ============================================================================ - *. - * 🧩 Формат файла .bch: - * Каждый блок хранится последовательно, без промежутков. - * Один блок = «заголовок» (RAW) + подпись (64) + хэш (32). - *. - * FULL = RAW + signature(64) + hash(32) - *. - * --------------------------------------------------------------------------- - * 🔹 Структура RAW-части блока (без подписи и хэша) - * --------------------------------------------------------------------------- - * Размеры и порядок строго фиксированы (BigEndian). - *. - * Порядок байтов (сверху вниз, смещения от начала RAW): - *. - * ┌────────────────────────────┬────────┬───────────────────────────────┐ - * │ Поле │ Размер │ Описание │ - * ├────────────────────────────┼────────┼───────────────────────────────┤ - * │ recordSize │ 4 байта│ = M + 20 — общий размер RAW │ - * │ recordNumber │ 4 байта│ порядковый номер блока │ - * │ timestamp │ 8 байт │ UNIX time (секунды) │ - - Номер линии 2 байта линии пока просто пишутся но никак не используются - номер преведущего блока в этой линии 4 байа - - //Можно сказать что здесь уже тело пошло - * │ recordType │ 2 байта│ тип тела (0=Header, 1=Text) │ - * │ recordTypeVersion │ 2 байта│ версия структуры данного типа │ - * │ body │ M байт │ бинарное тело записи │ - * └────────────────────────────┴────────┴───────────────────────────────┘ - *. - * ⇒ RAW_HEADER_SIZE = 4 + 4 + 8 + 2 + 2 = 20 байт. - * ⇒ recordSize = RAW_HEADER_SIZE + body.length - *. - * --------------------------------------------------------------------------- - * 🔹 Структура FULL-блока - * --------------------------------------------------------------------------- - *. - * ┌────────────────────────────┬─────────┬──────────────────────────────┐ - * │ RAW │ M+20 │ тело блока без подписи │ - * │ signature64 │ 64 │ подпись Ed25519(preimage) │ - * │ hash32 │ 32 │ SHA-256(preimage) │ - * └────────────────────────────┴─────────┴──────────────────────────────┘ - *. - * ⇒ Общая длина FULL = recordSize + 96 байт. - *. - * --------------------------------------------------------------------------- - * 🔹 Канонический preimage для подписи/хэша - * --------------------------------------------------------------------------- - Новый вариант преимадже без блокченй ИД !! - так как он может меняться - - * preimage = Заглавие SHiNE - * userLogin(UTF-8, без длины) + - * userId(8B, BE) + - * можно номер блока? - * prevHash32(32B) + - * rawBytes (M+20B) - *. - * hash32 = SHA-256(preimage) - * signature64= Ed25519.sign(preimage, privateKey) - *. - * Проверка осуществляется через {@link utils.crypto.BchCryptoVerifier}. - diff --git a/doc_todelite/src/main/docs/Формат блоков/структура блока/типы субблокченов.md b/doc_todelite/src/main/docs/Формат блоков/структура блока/типы субблокченов.md deleted file mode 100644 index f176303..0000000 --- a/doc_todelite/src/main/docs/Формат блоков/структура блока/типы субблокченов.md +++ /dev/null @@ -1,13 +0,0 @@ -Технический блокчен - -Блоки в солану - -Личнык данные -Связи - - -Публичные сообщения - - - -Личые письма \ No newline at end of file diff --git a/docs/Ответ_на_вопрос_о_блокчейне_каналах_и_расширяемости.md b/docs/Ответ_на_вопрос_о_блокчейне_каналах_и_расширяемости.md deleted file mode 100644 index ccaf767..0000000 --- a/docs/Ответ_на_вопрос_о_блокчейне_каналах_и_расширяемости.md +++ /dev/null @@ -1,105 +0,0 @@ -Дата: 27.04.2026 - -# Ответ по блокчейну, форматам, каналам и расширяемости - -Короткий итог: текущую систему можно запускать и развивать дальше. Архитектура уже в целом готова к расширению версиями, но расширять нужно по строгим правилам совместимости. - -## 1) Что важно зафиксировать про эволюцию форматов - -Да, ваш подход верный: -- новые возможности добавляем через новые `type/subType/version` и/или новый `frameCode`; -- старые блоки не переписываем и не «переподписываем»; -- делаем конвертер/адаптер чтения: старые блоки читаются и приводятся к новой внутренней модели. - -Это и есть правильная схема «старое автоматически читается и представляется в новом формате». - -## 2) Есть ли в коде узкие места, где нельзя расширять - -Критичных тупиков не видно, но есть важные ограничения: -- Парсер сейчас строгий: неизвестные `type/subType/version` и неизвестный frame отклоняются. -- Значит новые форматы нужно явно добавлять в парсер и серверную валидацию. -- Старые блоки без нужных полей не проблема, если новый код умеет читать их как legacy-ветку. - -Вывод: расширение возможно, но только через явную поддержку версий, а не «само появится». - -## 3) Про канал `0` - -Зафиксировано правило: -- канал `0` оставляем как технический root; -- контент-посты туда пока не публикуем. - -Это теперь отмечено в коде комментариями и проверками: -- на клиенте (UI) пост в `lineCode=0` блокируется с понятной ошибкой; -- на сервере добавлена валидация, которая тоже отклоняет `TEXT_POST` в канал `0`. - -## 4) Формат аватара (`ava`) — обновлено - -Раньше: -- `AR:` - -Теперь поддерживается составной формат: -- `SHA256:,AR:` - -Что сделано: -- парсер и сборщик формата в UI обновлены; -- при загрузке нового аватара считается `SHA-256` оптимизированного файла и сохраняется вместе с `AR`; -- при выборе существующего `txId` сначала качается файл, считается `SHA-256`, и только потом пишется `ava`; -- серверный граф связей теперь умеет извлекать `AR` из составной строки (включая fallback для legacy/кривых значений). - -Это улучшает целостность: у вас есть не только адрес файла, но и контрольный хэш. - -## 5) Как устроены ответы в каналах и насколько это надёжно - -Ответы (`REPLY` / `EDIT_REPLY`) сделаны отдельно от линейных постов: -- `REPLY` хранит ссылку на цель (`toBlockchainName + blockNumber + hash32`) и текст; -- `EDIT_REPLY` хранит ссылку на оригинальный reply (`blockNumber + hash32`) и новый текст. - -Сильные стороны: -- ссылка идёт по номеру + хэшу (устойчиво к подмене цели); -- редактирование отделено от оригинала и может агрегироваться в чтении. - -Для будущего это расширяемо: -- можно добавить `TEXT_REPLY_V2` с новым payload, сохранив `V1` для старых клиентов. - -## 6) Вложенные файлы и «мини-разметка» внутри сообщения - -Идея рабочая, но лучше делать аккуратно. - -### Вариант A: «теги в тексте» (ваша идея) - -Плюсы: -- быстро внедрить; -- стандартно для пользователей (похоже на HTML/Markdown). - -Риски: -- экранирование `<` `>` и безопасность рендера; -- сложнее валидировать и безопасно отображать (XSS/инъекции). - -Если идти этим путём, лучше: -- разрешить только whitelist-теги (`img/file/h1/h2/h3/b/i` и т.д.); -- хранить метаданные файла явно: `type,size,sha256,ar`; -- рендерить через безопасный парсер, а не через «сырой HTML». - -### Вариант B: структурированный payload (рекомендуется как основной) - -Сделать `TEXT_POST_V2`: -- массив сегментов: `text`, `image`, `file`, `heading`, `style`; -- для файла хранить `kind`, `mime`, `size`, `sha256`, `storage`, `address`. - -Плюс: -- надёжная валидация и безопасный рендер. - -Оптимальная стратегия: -1. В UI можно дать «мини-разметку» для ввода. -2. На запись преобразовывать её в структурированный payload V2. -3. Для старых клиентов отдавать fallback plain text. - -## 7) Практический roadmap без остановки разработки - -1. Оставить текущий blockchain running. -2. Формально описать versioning policy (что считается breaking/non-breaking). -3. Зафиксировать channel `0` как технический root-only. -4. Использовать `ava = SHA256 + AR` как новый стандарт. -5. Запланировать `TEXT_*_V2` для вложений и форматирования. - -Итог: стартовать и развивать можно уже сейчас. Основа хорошая, если строго держать версионирование и адаптеры чтения для legacy-блоков.