05 01 25
Документы: Описание БД и всех запросов актуализировал!
This commit is contained in:
parent
a6a5089379
commit
94777c58c6
@ -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)
|
|
||||||
107
DOC/Описание БД.md
Normal file
107
DOC/Описание БД.md
Normal file
@ -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) — быстрые выборки “по ссылке”.
|
||||||
286
DOC/Описание протокола.md
Normal file
286
DOC/Описание протокола.md
Normal file
@ -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
|
||||||
@ -10,16 +10,26 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* SolanaUsersDAO — локальная таблица пользователей из Solana.
|
* SolanaUsersDAO — локальная таблица пользователей из Solana.
|
||||||
*
|
*
|
||||||
* Колонки:
|
* Таблица: solana_users
|
||||||
* - login TEXT (PK)
|
|
||||||
* - bchName TEXT
|
|
||||||
* - loginKey TEXT
|
|
||||||
* - deviceKey TEXT
|
|
||||||
* - bchLimit INTEGER (может быть NULL)
|
|
||||||
*
|
*
|
||||||
* Правило:
|
* Колонки:
|
||||||
* - методы с Connection НЕ закрывают соединение
|
* - login TEXT PRIMARY KEY
|
||||||
* - методы без Connection сами открывают и закрывают соединение
|
* Уникальный логин пользователя (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 {
|
public final class SolanaUsersDAO {
|
||||||
|
|
||||||
|
|||||||
@ -3,15 +3,35 @@ package shine.db.entities;
|
|||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Локальная копия пользователя из Solana.
|
* SolanaUserEntry — локальная запись пользователя из Solana.
|
||||||
*
|
*
|
||||||
* Теперь:
|
* Таблица: solana_users
|
||||||
|
*
|
||||||
|
* Поля:
|
||||||
* - login — PRIMARY KEY (TEXT)
|
* - login — PRIMARY KEY (TEXT)
|
||||||
* - bchName — имя/идентификатор персонального блокчейна (TEXT)
|
* Уникальный логин пользователя.
|
||||||
* - loginKey — публичный ключ логина
|
*
|
||||||
* - deviceKey — публичный ключ устройства
|
* - deviceKey — TEXT NOT NULL
|
||||||
* - bchLimit — лимит (может быть null)
|
* Публичный ключ устройства.
|
||||||
|
* Поддерживаемые форматы:
|
||||||
|
* • Base64 (32 байта)
|
||||||
|
* • HEX (64 hex-символа)
|
||||||
|
*
|
||||||
|
* - solanaKey — TEXT NULLABLE
|
||||||
|
* Публичный ключ Solana-аккаунта пользователя (если используется).
|
||||||
|
*
|
||||||
|
* Назначение:
|
||||||
|
* - хранение минимальной локальной информации о пользователе
|
||||||
|
* - используется для:
|
||||||
|
* • проверки подписи запросов
|
||||||
|
* • привязки пользователя к блокчейну
|
||||||
|
* • сопоставления login ↔ ключи
|
||||||
|
*
|
||||||
|
* ВАЖНО:
|
||||||
|
* - deviceKey обязателен всегда
|
||||||
|
* - solanaKey может отсутствовать (null)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class SolanaUserEntry {
|
public class SolanaUserEntry {
|
||||||
|
|
||||||
private String login; // TEXT PK
|
private String login; // TEXT PK
|
||||||
|
|||||||
@ -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",
|
op - "AuthChallenge"
|
||||||
"requestId": "req-1",
|
requestId - id запроса
|
||||||
"status": 200,
|
login - логин пользователя, для которого начинается авторизация
|
||||||
"payload": {
|
|
||||||
"users": [
|
|
||||||
{ "login": "aidar" },
|
|
||||||
{ "login": "anya" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
🔴 Ошибочный ответ (server → client)
|
Ответ (успех):
|
||||||
|
op - "AuthChallenge"
|
||||||
|
requestId - id запроса
|
||||||
|
status - 200 если успех
|
||||||
|
authNonce - одноразовый nonce, Base64Url(32 bytes) без padding
|
||||||
|
|
||||||
{
|
Ответ (ошибка):
|
||||||
"op": "SearchUsers",
|
op - "AuthChallenge"
|
||||||
"requestId": "req-1",
|
requestId - id запроса
|
||||||
"status": 403,
|
status - код ошибки
|
||||||
"error": {
|
code - строковый код ошибки
|
||||||
"code": "SESSION_EXPIRED",
|
message - человекочитаемое описание ошибки
|
||||||
"message": "Сессия истекла"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
🟣 Событие (server → client, не ответ)
|
----- CreateAuthSession
|
||||||
|
Шаг 2: проверяет подпись владения ключом, создаёт новую active_session и возвращает sessionId/sessionPwd.
|
||||||
|
|
||||||
{
|
Запрос:
|
||||||
"op": "NewBlockEvent",
|
op - "CreateAuthSession"
|
||||||
"payload": {
|
requestId - id запроса
|
||||||
"blockchainId": 42,
|
storagePwd - ключ/пароль хранилища клиента, base64(32 bytes)
|
||||||
"blockNumber": 101
|
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
|
||||||
Loading…
Reference in New Issue
Block a user