From 94777c58c6bd019d79546457f38e64a14cdac8bdac6740f9e7fbd5c4ba71e936 Mon Sep 17 00:00:00 2001 From: AidarKC Date: Mon, 5 Jan 2026 17:17:39 +0300 Subject: [PATCH] =?UTF-8?q?05=2001=2025=20=D0=94=D0=BE=D0=BA=D1=83=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=D1=8B:=20=D0=9E=D0=BF=D0=B8=D1=81=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=91=D0=94=20=D0=B8=20=D0=B2=D1=81=D0=B5?= =?UTF-8?q?=D1=85=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=B0=D0=BA=D1=82=D1=83=D0=B0=D0=BB=D0=B8=D0=B7=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BB!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DOC/doc-BD.md | 95 ------ DOC/Описание БД.md | 107 ++++++ DOC/Описание протокола.md | 286 ++++++++++++++++ .../java/shine/db/dao/SolanaUsersDAO.java | 28 +- .../shine/db/entities/SolanaUserEntry.java | 32 +- .../ws_protocol/JSON/Описание протокола.md | 318 +++++++++++++++--- 6 files changed, 714 insertions(+), 152 deletions(-) delete mode 100644 DOC/doc-BD.md create mode 100644 DOC/Описание БД.md create mode 100644 DOC/Описание протокола.md diff --git a/DOC/doc-BD.md b/DOC/doc-BD.md deleted file mode 100644 index 4bf9190..0000000 --- a/DOC/doc-BD.md +++ /dev/null @@ -1,95 +0,0 @@ -Документ: shine-server-bd — таблицы и структура -Таблицы (что хранят) - -solana_users — локальная таблица пользователей (логин + ключ устройства + опциональный solanaKey). - -active_sessions — активные сессии пользователей (секреты сессии, время, push-подписки, IP/клиент-инфо). - -users_params — сохранённые параметры пользователя (например, состояние просмотренности лент и прочие настройки), с подписью. - -ip_geo_cache — кэш геолокации по IP (чтобы не дергать внешние сервисы каждый раз). - -blockchain_state — агрегатное “текущее состояние” блокчейна по blockchainName (лимит, размер, последние хэши/номера). - -blocks — сохранённые блоки/сообщения блокчейна (байты блока + связи “кому/куда” для адресации). - -solana_users — пользователи и их ключи - -login TEXT — логин пользователя (PRIMARY KEY) -deviceKey TEXT — публичный ключ устройства (обязателен) -solanaKey TEXT — дополнительный ключ Solana (может быть NULL) - -active_sessions — активные сессии пользователя - -sessionId TEXT — идентификатор сессии (PRIMARY KEY) -login TEXT — логин владельца сессии (FK → solana_users.login) -sessionPwd TEXT — пароль/секрет сессии (используется сервером) -storagePwd TEXT — пароль/секрет для шифрования хранилища/данных -sessionCreatedAtMs INTEGER — время создания сессии (ms) -lastAuthirificatedAtMs INTEGER — время последней успешной аутентификации/refresh (ms) -pushEndpoint TEXT — endpoint для web-push (nullable) -pushP256dhKey TEXT — ключ p256dh для web-push (nullable) -pushAuthKey TEXT — auth key для web-push (nullable) -clientIp TEXT — IP клиента при auth/refresh (nullable) -clientInfoFromClient TEXT — строка client-info от клиента (nullable) -clientInfoFromRequest TEXT — строка client-info, собранная сервером (nullable) -userLanguage TEXT — предпочитаемый язык пользователя (nullable) - -users_params — параметры/состояния пользователя - -login TEXT — логин владельца параметра (FK → solana_users.login) -param TEXT — имя параметра (в паре с login образует UNIQUE) -bch_channel_id INTEGER — id канала/ленты/контекста блокчейна (по умолчанию 0) -value TEXT — значение параметра (nullable) -time_ms INTEGER — время обновления параметра (ms) -pubkey_num INTEGER — номер/индекс публичного ключа, которым подписано значение -signature TEXT — подпись значения параметра (строка) - -ip_geo_cache — кэш геоданных по IP - -ip TEXT — IP-адрес (PRIMARY KEY) -geo TEXT — строка гео-описания (“Country, City” и т.п.) (nullable) -updated_at_ms INTEGER — время последнего обновления (ms) - -blockchain_state — текущее состояние блокчейна по blockchainName - -blockchainName TEXT — имя/идентификатор блокчейна (PRIMARY KEY) -login TEXT — владелец блокчейна (FK → solana_users.login) -blockchainKey TEXT — публичный ключ блокчейна (используется для подписи блоков) -size_limit INTEGER — лимит размера блокчейн-файла (байты) -file_size_bytes INTEGER — текущий размер файла блокчейна (байты) -last_global_number INTEGER — номер последнего глобального блока (genesis обычно -1) -last_global_hash TEXT — хэш последнего глобального блока (пусто для “нулевого” состояния) -updated_at_ms INTEGER — время обновления состояния (ms) -line0_last_number INTEGER — последний номер в линии 0 -line0_last_hash TEXT — последний хэш в линии 0 -line1_last_number INTEGER — последний номер в линии 1 -line1_last_hash TEXT — последний хэш в линии 1 -line2_last_number INTEGER — последний номер в линии 2 -line2_last_hash TEXT — последний хэш в линии 2 -line3_last_number INTEGER — последний номер в линии 3 -line3_last_hash TEXT — последний хэш в линии 3 -line4_last_number INTEGER — последний номер в линии 4 -line4_last_hash TEXT — последний хэш в линии 4 -line5_last_number INTEGER — последний номер в линии 5 -line5_last_hash TEXT — последний хэш в линии 5 -line6_last_number INTEGER — последний номер в линии 6 -line6_last_hash TEXT — последний хэш в линии 6 -line7_last_number INTEGER — последний номер в линии 7 -line7_last_hash TEXT — последний хэш в линии 7 - -blocks — блоки/сообщения блокчейна (байтовое тело + адресация) - -login TEXT — владелец (FK → solana_users.login) -bchName TEXT — имя блокчейна (FK → blockchain_state.blockchainName) -blockGlobalNumber INTEGER — глобальный номер блока -blockGlobalPreHashe TEXT — предыдущий глобальный хэш (строка) -blockLineIndex INTEGER — индекс линии (0..7) -blockLineNumber INTEGER — номер блока внутри линии -blockLinePreHashe TEXT — предыдущий хэш внутри линии -msgType INTEGER — тип сообщения/записи (код) -blockByte BLOB — сырые байты блока (nullable) -to_login TEXT — адресат логин (nullable) -toBchName TEXT — адресат блокчейн (nullable) -toBlockGlobalNumber INTEGER — целевой глобальный номер (nullable) -toBlockHashe TEXT — целевой хэш (nullable) \ No newline at end of file diff --git a/DOC/Описание БД.md b/DOC/Описание БД.md new file mode 100644 index 0000000..3801bb8 --- /dev/null +++ b/DOC/Описание БД.md @@ -0,0 +1,107 @@ +1) Перечень таблиц и кратко о каждой + +solana_users — справочник пользователей: логин + ключ устройства + (опционально) Solana-ключ. База для FK почти во всех таблицах. +active_sessions — активные сессии авторизации/работы клиента: пароли сессии/хранилища, времена, push-данные, IP/инфо клиента. +users_params — “последние значения параметров” пользователя. Для каждого (login,param) хранится актуальная версия по time_ms (старые обновления игнорируются). +ip_geo_cache — кеш геолокации по IP, чтобы не дергать внешние сервисы постоянно. +blockchain_state — агрегатное состояние блокчейна по blockchainName: лимиты/размер, последний глобальный блок и последние блоки по линиям 0..7. +blocks — локальное хранилище блоков/сообщений: привязка к пользователю и блокчейну, номера/хэши, тип/подтип, тело блока (BLOB), и опциональная “ссылка на другой блок” через поля to*. (PK сейчас намеренно убран.) + +2) Таблицы подробно: параметры по строкам + +solana_users + +login — TEXT PK — уникальный логин пользователя. +deviceKey — TEXT NOT NULL — публичный ключ устройства (обычно Base64(32) или HEX(64)). +solanaKey — TEXT NULL — публичный ключ Solana-аккаунта (если используется). + +active_sessions + +sessionId — TEXT PK — идентификатор сессии (строка; по смыслу base64(32)). +login — TEXT NOT NULL, FK → solana_users(login) — владелец сессии. +sessionPwd — TEXT NOT NULL — пароль/секрет сессии (как хранится — строкой). +storagePwd — TEXT NOT NULL — пароль/секрет для storage (как хранится — строкой). +sessionCreatedAtMs — INTEGER NOT NULL — время создания сессии (Unix ms). +lastAuthirificatedAtMs — INTEGER NOT NULL — время последней авторизации/refresh (Unix ms). +pushEndpoint — TEXT NULL — endpoint для WebPush. +pushP256dhKey — TEXT NULL — p256dh ключ для WebPush. +pushAuthKey — TEXT NULL — auth ключ для WebPush. +clientIp — TEXT NULL — IP клиента на auth/refresh. +clientInfoFromClient — TEXT NULL — строка, присланная клиентом (PWA). +clientInfoFromRequest — TEXT NULL — строка, собранная сервером из запроса. +userLanguage — TEXT NULL — язык пользователя (например ru-RU). + +users_params + +login — TEXT NOT NULL, FK → solana_users(login) — владелец параметра. +param — TEXT NOT NULL — имя параметра (ключ). +time_ms — INTEGER NOT NULL — версия/время параметра (Unix ms), используется для “только если новее”. +value — TEXT NOT NULL — значение параметра. +device_key — TEXT NULL — каким ключом подписано (если используешь), строковый формат. +signature — TEXT NULL — подпись (если используешь), строковый формат. + +Ограничение: UNIQUE(login, param) — один актуальный параметр на пару. + +ip_geo_cache + +ip — TEXT PK — IP-адрес (строкой). +geo — TEXT NULL — гео-строка (Country/City или как договоритесь). +updated_at_ms — INTEGER NOT NULL — когда кеш обновлялся (Unix ms). + +blockchain_state + +blockchainName — TEXT PK — имя/ID блокчейна (уникальное). +login — TEXT NOT NULL, FK → solana_users(login) — владелец блокчейна. +blockchainKey — TEXT NOT NULL — публичный ключ блокчейна (по смыслу Base64(32)). +size_limit — INTEGER NOT NULL — лимит размера (по смыслу bytes; в Java это long). +file_size_bytes — INTEGER NOT NULL — текущий размер файла блокчейна в байтах. +last_global_number — INTEGER NOT NULL — последний глобальный номер блока (genesis = -1). +last_global_hash — TEXT NOT NULL — хэш последнего глобального блока (или пустая строка). +updated_at_ms — INTEGER NOT NULL — время обновления состояния (Unix ms). + +Линии 0..7 (для каждой линии две колонки): +line0_last_number — INTEGER NOT NULL — последний номер в линии 0. +line0_last_hash — TEXT NOT NULL — последний хэш в линии 0. +line1_last_number — INTEGER NOT NULL — последний номер в линии 1. +line1_last_hash — TEXT NOT NULL — последний хэш в линии 1. +line2_last_number — INTEGER NOT NULL — последний номер в линии 2. +line2_last_hash — TEXT NOT NULL — последний хэш в линии 2. +line3_last_number — INTEGER NOT NULL — последний номер в линии 3. +line3_last_hash — TEXT NOT NULL — последний хэш в линии 3. +line4_last_number — INTEGER NOT NULL — последний номер в линии 4. +line4_last_hash — TEXT NOT NULL — последний хэш в линии 4. +line5_last_number — INTEGER NOT NULL — последний номер в линии 5. +line5_last_hash — TEXT NOT NULL — последний хэш в линии 5. +line6_last_number — INTEGER NOT NULL — последний номер в линии 6. +line6_last_hash — TEXT NOT NULL — последний хэш в линии 6. +line7_last_number — INTEGER NOT NULL — последний номер в линии 7. +line7_last_hash — TEXT NOT NULL — последний хэш в линии 7. + +blocks + +login — TEXT NOT NULL, FK → solana_users(login) — чей блок (логин). +bchName — TEXT NOT NULL, FK → blockchain_state(blockchainName) — к какому блокчейну относится блок. +blockGlobalNumber — INTEGER NOT NULL — глобальный номер блока. +blockGlobalPreHashe — TEXT NOT NULL — хэш предыдущего глобального блока. +blockLineIndex — INTEGER NOT NULL — индекс линии (0..7), по смыслу int16. +blockLineNumber — INTEGER NOT NULL — номер блока в линии. +blockLinePreHashe — TEXT NOT NULL — хэш предыдущего блока в линии. +msgType — INTEGER NOT NULL — общий тип сообщения/блока (по смыслу uint16). +msgSubType — INTEGER NOT NULL — подтип внутри msgType (по смыслу uint16). +blockByte — BLOB NULL — сырой байтовый блок/тело сообщения. + +Ссылка на другой блок (nullable, для ответов/репостов/связей и т.п.): +to_login — TEXT NULL — логин “на кого/кому/с кем” (смысловая цель). +toBchName — TEXT NULL — целевой блокчейн. +toBlockGlobalNumber — INTEGER NULL — целевой глобальный номер. +toBlockHashe — TEXT NULL — хэш целевого блока. + +Индексы (кратко, чтобы было понятно зачем) +idx_solana_users_login(login) — быстрый поиск по логину. +idx_active_sessions_login(login) — быстро получить сессии пользователя. +idx_users_params_login(login) — быстро получить параметры пользователя. +idx_ip_geo_cache_updated_at(updated_at_ms) — чистка старых записей. +idx_blockchain_state_login(login) — блокчейны пользователя. +idx_blockchain_state_updated_at(updated_at_ms) — выборки/обслуживание по “свежести”. +idx_blocks_chain_global(login,bchName,blockGlobalNumber) — выборки блоков по цепочке. +idx_blocks_to_target(to_login,toBchName,toBlockGlobalNumber) — быстрые выборки “по ссылке”. \ No newline at end of file diff --git a/DOC/Описание протокола.md b/DOC/Описание протокола.md new file mode 100644 index 0000000..41c0000 --- /dev/null +++ b/DOC/Описание протокола.md @@ -0,0 +1,286 @@ +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 +loginKey +deviceKey +bchLimit + +Ответ (успех): +op +requestId +status - 200 + +Ответ (ошибка): +op +requestId +status +code +message \ No newline at end of file diff --git a/shine-server-db/src/main/java/shine/db/dao/SolanaUsersDAO.java b/shine-server-db/src/main/java/shine/db/dao/SolanaUsersDAO.java index 7cfd9a6..aa3ec10 100644 --- a/shine-server-db/src/main/java/shine/db/dao/SolanaUsersDAO.java +++ b/shine-server-db/src/main/java/shine/db/dao/SolanaUsersDAO.java @@ -10,16 +10,26 @@ import java.util.List; /** * SolanaUsersDAO — локальная таблица пользователей из Solana. * - * Колонки: - * - login TEXT (PK) - * - bchName TEXT - * - loginKey TEXT - * - deviceKey TEXT - * - bchLimit INTEGER (может быть NULL) + * Таблица: solana_users * - * Правило: - * - методы с Connection НЕ закрывают соединение - * - методы без Connection сами открывают и закрывают соединение + * Колонки: + * - login TEXT PRIMARY KEY + * Уникальный логин пользователя (case-insensitive используется на уровне запросов). + * + * - deviceKey TEXT NOT NULL + * Публичный ключ устройства пользователя. + * Хранится в Base64(32 bytes) или HEX(64 chars). + * + * - solanaKey TEXT NULLABLE + * Публичный ключ Solana-аккаунта пользователя (если есть). + * + * Назначение таблицы: + * - локальное сопоставление login → deviceKey / solanaKey + * - используется для аутентификации, валидации подписей и связки с блокчейном + * + * Правило работы с соединениями: + * - методы с Connection НЕ закрывают соединение + * - методы без Connection сами открывают и закрывают соединение */ public final class SolanaUsersDAO { diff --git a/shine-server-db/src/main/java/shine/db/entities/SolanaUserEntry.java b/shine-server-db/src/main/java/shine/db/entities/SolanaUserEntry.java index 92b0285..8ffb44c 100644 --- a/shine-server-db/src/main/java/shine/db/entities/SolanaUserEntry.java +++ b/shine-server-db/src/main/java/shine/db/entities/SolanaUserEntry.java @@ -3,15 +3,35 @@ package shine.db.entities; import java.util.Base64; /** - * Локальная копия пользователя из Solana. + * SolanaUserEntry — локальная запись пользователя из Solana. * - * Теперь: + * Таблица: solana_users + * + * Поля: * - login — PRIMARY KEY (TEXT) - * - bchName — имя/идентификатор персонального блокчейна (TEXT) - * - loginKey — публичный ключ логина - * - deviceKey — публичный ключ устройства - * - bchLimit — лимит (может быть null) + * Уникальный логин пользователя. + * + * - deviceKey — TEXT NOT NULL + * Публичный ключ устройства. + * Поддерживаемые форматы: + * • Base64 (32 байта) + * • HEX (64 hex-символа) + * + * - solanaKey — TEXT NULLABLE + * Публичный ключ Solana-аккаунта пользователя (если используется). + * + * Назначение: + * - хранение минимальной локальной информации о пользователе + * - используется для: + * • проверки подписи запросов + * • привязки пользователя к блокчейну + * • сопоставления login ↔ ключи + * + * ВАЖНО: + * - deviceKey обязателен всегда + * - solanaKey может отсутствовать (null) */ + public class SolanaUserEntry { private String login; // TEXT PK diff --git a/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/Описание протокола.md b/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/Описание протокола.md index cd38e2e..41c0000 100644 --- a/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/Описание протокола.md +++ b/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/Описание протокола.md @@ -1,52 +1,286 @@ -Протокол использует единый формат JSON-сообщений: клиент всегда отправляет запросы с полями op, requestId и payload, сервер отвечает тем же op и requestId, добавляя status (200 для успеха, любое другое значение — ошибка) и либо payload, либо error. +JSON WebSocket протокол сервера: список существующих запросов (op) -События от сервера приходят без requestId и status, содержат только op и payload и не являются ответами на запросы. +Общий формат любого запроса (client → server): +op - имя операции (строка) +requestId - идентификатор запроса для связывания с ответом (строка) +payload - объект с параметрами конкретной операции (object) -# Примеры JSON для SearchUsers (минимальная шпаргалка) +Общий формат любого ответа (server → client): +op - имя операции (строка, совпадает с запросом) +requestId - идентификатор запроса (строка, совпадает с запросом) +status - статус результата (200 = успех, другое = ошибка) +payload - объект с полями ответа (object; при ошибке содержит code/message) -## 🔵 Запрос (client → server) +Группа: Авторизация и сессии -```json -{ - "op": "SearchUsers", - "requestId": "req-1", - "payload": { - "query": "ai" - } -} +Эта группа управляет входом пользователя, созданием/обновлением сессий и безопасным завершением активных подключений. -🟢 Успешный ответ (server → client) +----- AuthChallenge +Одноразовый шаг 1: по логину выдаёт nonce (authNonce), который затем подписывается на шаге 2. -{ - "op": "SearchUsers", - "requestId": "req-1", - "status": 200, - "payload": { - "users": [ - { "login": "aidar" }, - { "login": "anya" } - ] - } -} +Запрос: +op - "AuthChallenge" +requestId - id запроса +login - логин пользователя, для которого начинается авторизация -🔴 Ошибочный ответ (server → client) +Ответ (успех): +op - "AuthChallenge" +requestId - id запроса +status - 200 если успех +authNonce - одноразовый nonce, Base64Url(32 bytes) без padding -{ - "op": "SearchUsers", - "requestId": "req-1", - "status": 403, - "error": { - "code": "SESSION_EXPIRED", - "message": "Сессия истекла" - } -} +Ответ (ошибка): +op - "AuthChallenge" +requestId - id запроса +status - код ошибки +code - строковый код ошибки +message - человекочитаемое описание ошибки -🟣 Событие (server → client, не ответ) +----- CreateAuthSession +Шаг 2: проверяет подпись владения ключом, создаёт новую active_session и возвращает sessionId/sessionPwd. -{ - "op": "NewBlockEvent", - "payload": { - "blockchainId": 42, - "blockNumber": 101 - } -} \ No newline at end of file +Запрос: +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 +loginKey +deviceKey +bchLimit + +Ответ (успех): +op +requestId +status - 200 + +Ответ (ошибка): +op +requestId +status +code +message \ No newline at end of file