From 23748504e65fd9542a147a6d4fcfc89dd01883413cc7bb238f756784104c5add Mon Sep 17 00:00:00 2001 From: AidarKC Date: Mon, 27 Jul 2026 19:06:08 +0400 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B2=D0=B5=D1=80:=20=D1=83?= =?UTF-8?q?=D0=B4=D0=B0=D0=BB=D0=B8=D1=82=D1=8C=20manual=20import=20=D0=B8?= =?UTF-8?q?=20AddUser=20=D1=81=D0=BB=D0=BE=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/shine/db/dao/SolanaUsersDAO.java | 39 +- .../main/java/shine/db/dao/UserCreateDAO.java | 128 ------ .../java/shine/db/sql/SolanaUsersSql.java | 15 - .../src/main/resources/postgres/schema_v1.sql | 34 -- .../ws_protocol/JSON/JsonHandlerRegistry.java | 5 - .../auth/Net_AuthChallenge_Handler.java | 20 +- .../auth/SolanaUserPdaImportService.java | 34 +- .../auth/entyties/AUTH_SESSION_NEW.md | 44 +-- .../tempToTest/Net_AddUser_Handler.java | 26 -- .../tempToTest/Net_GetUser_Handler.java | 4 - .../entyties/Net_AddUser_Request.java | 58 --- .../entyties/Net_AddUser_Response.java | 21 - .../JSON/messages/SignedMessagesCore.java | 6 +- .../sync/PeriodicBlockchainSyncService.java | 74 +--- .../java/test/it/cases/IT_01_AddUser.java | 365 ------------------ .../java/test/it/cases/IT_02_Sessions.java | 3 +- .../test/it/cases/IT_03_AddBlock_NoAuth.java | 3 +- .../it/cases/IT_04_UserParams_NoAuth.java | 5 +- .../java/test/it/cases/IT_07_EspPairing.java | 11 +- .../it/cases/SeedDataPopulationHelper.java | 48 +-- .../it/cases/Seed_TestDataPopulation.java | 5 +- .../java/test/it/runner/IT_RunAllMain.java | 4 - .../test/java/test/it/suite/IT_00_Suite.java | 2 - .../test/java/test/it/utils/TestConfig.java | 4 +- .../java/test/it/utils/json/JsonBuilders.java | 34 -- VERSION.properties | 2 +- 26 files changed, 26 insertions(+), 968 deletions(-) delete mode 100644 SHiNE-server/shine-server-db/src/main/java/shine/db/dao/UserCreateDAO.java delete mode 100644 SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_AddUser_Handler.java delete mode 100644 SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_AddUser_Request.java delete mode 100644 SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_AddUser_Response.java delete mode 100644 SHiNE-server/src/test/java/test/it/cases/IT_01_AddUser.java diff --git a/SHiNE-server/shine-server-db/src/main/java/shine/db/dao/SolanaUsersDAO.java b/SHiNE-server/shine-server-db/src/main/java/shine/db/dao/SolanaUsersDAO.java index ef0c07f1..5a4e4026 100644 --- a/SHiNE-server/shine-server-db/src/main/java/shine/db/dao/SolanaUsersDAO.java +++ b/SHiNE-server/shine-server-db/src/main/java/shine/db/dao/SolanaUsersDAO.java @@ -10,9 +10,10 @@ import java.util.ArrayList; import java.util.List; /** - * SolanaUsersDAO — локальная таблица пользователей из Solana. + * SolanaUsersDAO — совместимый runtime-доступ к текущему срезу пользователей. * - * Таблица: solana_users + * Источник: + * - solana_user_pda_current * * Колонки: * - login TEXT PRIMARY KEY @@ -41,40 +42,6 @@ public final class SolanaUsersDAO { return instance; } - // -------------------- INSERT -------------------- - - /** Вставка с внешним соединением. Соединение НЕ закрывает. */ - public void insert(Connection c, SolanaUserEntry user) throws SQLException { - String sql = """ - INSERT INTO solana_users_manual ( - login, blockchain_name, solana_key, blockchain_key, client_key, updated_at_ms - ) VALUES (?, ?, ?, ?, ?, ?) - ON CONFLICT (login) DO UPDATE SET - blockchain_name = EXCLUDED.blockchain_name, - solana_key = EXCLUDED.solana_key, - blockchain_key = EXCLUDED.blockchain_key, - client_key = EXCLUDED.client_key, - updated_at_ms = EXCLUDED.updated_at_ms - """; - - try (PreparedStatement ps = c.prepareStatement(sql)) { - ps.setString(1, user.getLogin()); - ps.setString(2, user.getBlockchainName()); - ps.setString(3, user.getSolanaKey()); - ps.setString(4, user.getBlockchainKey()); - ps.setString(5, user.getClientKey()); - ps.setLong(6, System.currentTimeMillis()); - ps.executeUpdate(); - } - } - - /** Вставка без внешнего соединения. Сам открывает/закрывает. */ - public void insert(SolanaUserEntry user) throws SQLException { - try (Connection c = db.getConnection()) { - insert(c, user); - } - } - // -------------------- EXISTS -------------------- /** Проверка существования по login (case-insensitive) с внешним соединением. Соединение НЕ закрывает. */ diff --git a/SHiNE-server/shine-server-db/src/main/java/shine/db/dao/UserCreateDAO.java b/SHiNE-server/shine-server-db/src/main/java/shine/db/dao/UserCreateDAO.java deleted file mode 100644 index 6c71d37e..00000000 --- a/SHiNE-server/shine-server-db/src/main/java/shine/db/dao/UserCreateDAO.java +++ /dev/null @@ -1,128 +0,0 @@ -package shine.db.dao; - -import shine.db.DbController; -import shine.db.entities.SolanaUserEntry; - -import java.sql.*; - -/** - * UserCreateDAO — атомарное добавление пользователя: - * - solana_users (login, blockchain_name, solana_key, blockchain_key, client_key) - * - blockchain_state (blockchain_name, login, blockchain_key, size_limit, ... last_block_number=-1 ...) - * - * ВАЖНО: - * - только INSERT (без перезаписи существующих записей) - * - если login или blockchainName заняты — возвращаем false (пользователь уже есть/занято) - */ -public final class UserCreateDAO { - - private static volatile UserCreateDAO instance; - private final DbController db = DbController.getInstance(); - private final SolanaUsersDAO usersDao = SolanaUsersDAO.getInstance(); - - private UserCreateDAO() {} - - public static UserCreateDAO getInstance() { - if (instance == null) { - synchronized (UserCreateDAO.class) { - if (instance == null) instance = new UserCreateDAO(); - } - } - return instance; - } - - /** - * @return true если добавили; false если занято (login уже есть или blockchainName уже существует). - */ - public boolean insertUserWithBlockchain( - String login, - String blockchainName, - String solanaKey, - String blockchainKey, - String clientKey, - long sizeLimit, - long nowMs - ) throws SQLException { - - try (Connection c = db.getConnection()) { - boolean oldAuto = c.getAutoCommit(); - c.setAutoCommit(false); - - try { - // 1) solana_users - SolanaUserEntry u = new SolanaUserEntry(); - u.setLogin(login); - u.setBlockchainName(blockchainName); - u.setSolanaKey(solanaKey); - u.setBlockchainKey(blockchainKey); - u.setClientKey(clientKey); - - usersDao.insert(c, u); // если login занят (NOCASE) или blockchainName (unique) -> constraint - - // 2) blockchain_state — строго INSERT, без UPSERT (иначе можно перезаписать существующую цепочку) - insertBlockchainStateStrict( - c, - blockchainName, - login, - blockchainKey, - sizeLimit, - nowMs - ); - - c.commit(); - return true; - - } catch (SQLException e) { - c.rollback(); - - String msg = e.getMessage() == null ? "" : e.getMessage().toLowerCase(); - if (msg.contains("constraint")) { - return false; - } - throw e; - - } finally { - c.setAutoCommit(oldAuto); - } - } - } - - private static void insertBlockchainStateStrict( - Connection c, - String blockchainName, - String login, - String blockchainKey, - long sizeLimit, - long nowMs - ) throws SQLException { - - String sql = """ - INSERT INTO blockchain_state ( - blockchain_name, - login, - blockchain_key, - size_limit, - file_size_bytes, - last_block_number, - last_block_hash, - updated_at_ms - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) - """; - - try (PreparedStatement ps = c.prepareStatement(sql)) { - int i = 1; - ps.setString(i++, blockchainName); - ps.setString(i++, login); - ps.setString(i++, blockchainKey); - - ps.setLong(i++, sizeLimit); - ps.setLong(i++, 0L); - - ps.setInt(i++, -1); - ps.setNull(i++, Types.BINARY); // старт: блоков ещё нет - ps.setLong(i++, nowMs); - - ps.executeUpdate(); // если blockchainName занят -> constraint (PK) - } - } -} diff --git a/SHiNE-server/shine-server-db/src/main/java/shine/db/sql/SolanaUsersSql.java b/SHiNE-server/shine-server-db/src/main/java/shine/db/sql/SolanaUsersSql.java index 3baadaa9..968cf0b2 100644 --- a/SHiNE-server/shine-server-db/src/main/java/shine/db/sql/SolanaUsersSql.java +++ b/SHiNE-server/shine-server-db/src/main/java/shine/db/sql/SolanaUsersSql.java @@ -17,21 +17,6 @@ public final class SolanaUsersSql { current_users.blockchain_key AS blockchain_key, current_users.client_key AS client_key FROM solana_user_pda_current current_users - - UNION ALL - - SELECT - manual.login AS login, - manual.blockchain_name AS blockchain_name, - manual.solana_key AS solana_key, - manual.blockchain_key AS blockchain_key, - manual.client_key AS client_key - FROM solana_users_manual manual - WHERE NOT EXISTS ( - SELECT 1 - FROM solana_user_pda_current current_users - WHERE LOWER(current_users.login) = LOWER(manual.login) - ) ) %s """.formatted(alias); } diff --git a/SHiNE-server/shine-server-db/src/main/resources/postgres/schema_v1.sql b/SHiNE-server/shine-server-db/src/main/resources/postgres/schema_v1.sql index 69da9863..7a01264c 100644 --- a/SHiNE-server/shine-server-db/src/main/resources/postgres/schema_v1.sql +++ b/SHiNE-server/shine-server-db/src/main/resources/postgres/schema_v1.sql @@ -111,40 +111,6 @@ CREATE TABLE IF NOT EXISTS solana_user_pda_current ( CREATE INDEX IF NOT EXISTS idx_user_pda_current_slot ON solana_user_pda_current(slot); -CREATE TABLE IF NOT EXISTS solana_users_manual ( - login TEXT PRIMARY KEY, - blockchain_name TEXT NOT NULL UNIQUE, - solana_key TEXT NOT NULL, - blockchain_key TEXT NOT NULL, - client_key TEXT NOT NULL, - updated_at_ms BIGINT NOT NULL -); - -CREATE INDEX IF NOT EXISTS idx_solana_users_manual_login - ON solana_users_manual(login); - -CREATE OR REPLACE VIEW solana_users AS -SELECT - current_users.login AS login, - current_users.blockchain_name AS blockchain_name, - current_users.client_key AS solana_key, - current_users.blockchain_key AS blockchain_key, - current_users.client_key AS client_key -FROM solana_user_pda_current current_users -UNION ALL -SELECT - manual.login, - manual.blockchain_name, - manual.solana_key, - manual.blockchain_key, - manual.client_key -FROM solana_users_manual manual -WHERE NOT EXISTS ( - SELECT 1 - FROM solana_user_pda_current current_users - WHERE LOWER(current_users.login) = LOWER(manual.login) -); - CREATE TABLE IF NOT EXISTS solana_user_pda_history ( id BIGSERIAL PRIMARY KEY, tx_signature TEXT NOT NULL, diff --git a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/JsonHandlerRegistry.java b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/JsonHandlerRegistry.java index 9d2121aa..5a7a7cca 100644 --- a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/JsonHandlerRegistry.java +++ b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/JsonHandlerRegistry.java @@ -43,9 +43,6 @@ import server.logic.ws_protocol.JSON.handlers.blockchain.Net_GetBlockchainBlock_ import server.logic.ws_protocol.JSON.handlers.blockchain.entyties.Net_AddBlock_Request; import server.logic.ws_protocol.JSON.handlers.blockchain.entyties.Net_GetBlockchainBlock_Request; -import server.logic.ws_protocol.JSON.handlers.tempToTest.Net_AddUser_Handler; -import server.logic.ws_protocol.JSON.handlers.tempToTest.entyties.Net_AddUser_Request; - import server.logic.ws_protocol.JSON.handlers.tempToTest.Net_GetUser_Handler; import server.logic.ws_protocol.JSON.handlers.tempToTest.Net_TestGetFreeAvatarQuota_Handler; import server.logic.ws_protocol.JSON.handlers.tempToTest.Net_TestUploadFreeAvatar_Handler; @@ -142,7 +139,6 @@ public final class JsonHandlerRegistry { } private static final Map HANDLERS = Map.ofEntries( - Map.entry("AddUser", new Net_AddUser_Handler()), Map.entry("GetUser", new Net_GetUser_Handler()), Map.entry("SearchUsers", new Net_SearchUsers_Handler()), Map.entry("TestGetFreeAvatarQuota", new Net_TestGetFreeAvatarQuota_Handler()), @@ -223,7 +219,6 @@ public final class JsonHandlerRegistry { ); private static final Map> REQUEST_TYPES = Map.ofEntries( - Map.entry("AddUser", Net_AddUser_Request.class), Map.entry("GetUser", Net_GetUser_Request.class), Map.entry("SearchUsers", Net_SearchUsers_Request.class), Map.entry("TestGetFreeAvatarQuota", Net_TestGetFreeAvatarQuota_Request.class), diff --git a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/Net_AuthChallenge_Handler.java b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/Net_AuthChallenge_Handler.java index 3b956b8f..8481ad9b 100644 --- a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/Net_AuthChallenge_Handler.java +++ b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/Net_AuthChallenge_Handler.java @@ -26,7 +26,7 @@ import java.security.SecureRandom; * * Что делает: * 1) Проверяет login. - * 2) Находит пользователя (solana_users). + * 2) Находит пользователя в текущем PDA snapshot. * 3) Пишет solanaUser в ctx, ставит AUTH_STATUS_AUTH_IN_PROGRESS. * 4) Генерирует authNonce (base64url(32)) и сохраняет в ctx.authNonce. */ @@ -61,25 +61,9 @@ public class Net_AuthChallenge_Handler implements JsonMessageHandler { } SolanaUserEntry solanaUserEntry = SolanaUsersDAO.getInstance().getByLogin(login); - if (solanaUserEntry == null) { - try { - solanaUserEntry = SolanaUserPdaImportService.findOrImportByLogin(login); - if (solanaUserEntry != null) { - log.info("AuthChallenge: пользователь {} импортирован из Solana PDA", solanaUserEntry.getLogin()); - } - } catch (Exception e) { - log.error("AuthChallenge: ошибка lazy-import пользователя {} из Solana", login, e); - return NetExceptionResponseFactory.error( - req, - WireCodes.Status.SERVER_DATA_ERROR, - "SOLANA_IMPORT_FAILED", - "Ошибка проверки пользователя в Solana" - ); - } - } if (solanaUserEntry == null) { return NetExceptionResponseFactory.error( - req, + req, WireCodes.Status.UNVERIFIED, "UNKNOWN_USER", "Пользователь с таким логином не найден" diff --git a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/SolanaUserPdaImportService.java b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/SolanaUserPdaImportService.java index 60065c90..4f58614a 100644 --- a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/SolanaUserPdaImportService.java +++ b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/SolanaUserPdaImportService.java @@ -4,9 +4,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import shine.db.dao.SolanaUsersDAO; -import shine.db.dao.UserCreateDAO; -import shine.db.entities.SolanaUserEntry; import utils.config.SolanaProgramsConfig; import java.net.URI; @@ -22,8 +19,7 @@ import java.util.Locale; import java.util.Map; /** - * Lazy-import пользователя из Solana PDA в локальную БД сервера. - * Используется при входе, если в solana_users нет записи по login. + * Чтение пользовательских и серверных PDA из Solana. */ public final class SolanaUserPdaImportService { @@ -34,34 +30,6 @@ public final class SolanaUserPdaImportService { private SolanaUserPdaImportService() {} - public static SolanaUserEntry findOrImportByLogin(String loginRaw) throws Exception { - String login = normalizeLogin(loginRaw); - if (login == null) return null; - - SolanaUsersDAO usersDao = SolanaUsersDAO.getInstance(); - SolanaUserEntry existing = usersDao.getByLogin(login); - if (existing != null) return existing; - - ParsedSolanaUser parsed = fetchFromSolana(login); - if (parsed == null) return null; - - long now = System.currentTimeMillis(); - long sizeLimit = parsed.paidLimitBytes > 0 ? parsed.paidLimitBytes : 100_000L; - boolean inserted = UserCreateDAO.getInstance().insertUserWithBlockchain( - parsed.login, - parsed.blockchainName, - parsed.clientKeyB64, // в текущей модели solanaKey = clientKey - parsed.blockchainKeyB64, - parsed.clientKeyB64, - sizeLimit, - now - ); - if (!inserted) { - return usersDao.getByLogin(login); - } - return usersDao.getByLogin(login); - } - public static SessionTypeCheckResult checkSessionTypeAgainstPda(String loginRaw, String sessionKeyApi, int requestedSessionType) throws Exception { String login = normalizeLogin(loginRaw); if (login == null) return SessionTypeCheckResult.noRecord(); diff --git a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/entyties/AUTH_SESSION_NEW.md b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/entyties/AUTH_SESSION_NEW.md index 9e6ab857..de8c9143 100644 --- a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/entyties/AUTH_SESSION_NEW.md +++ b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/auth/entyties/AUTH_SESSION_NEW.md @@ -33,46 +33,10 @@ } } -1. Добавление пользователя (AddUser) +1. Пользователь уже существует в актуальном PDA snapshot -Назначение: создать локальную запись пользователя с двумя ключами — solanaKey и clientKey. - -📤 Запрос клиента -{ -"op": "AddUser", -"requestId": "req-1", -"payload": { -"login": "anya4", -"loginId": 100212, -"bchId": 4222, -"solanaKey": "BASE64_LOGIN_KEY", -"clientKey": "BASE64_DEVICE_KEY", -"bchLimit": 1000000 -} -} - -🖥 Действия сервера - -Проверяет корректность данных. - -Вставляет запись в таблицу: - -CREATE TABLE solana_users ( -login TEXT NOT NULL, -loginId INTEGER PRIMARY KEY, -bchId INTEGER NOT NULL, -solanaKey TEXT, -clientKey TEXT, -bchLimit INTEGER -); - -📥 Ответ -{ -"op": "AddUser", -"requestId": "req-1", -"status": 200, -"payload": { "ok": true } -} +Назначение: перед началом auth-flow сервер уже должен видеть пользователя +в актуальном `solana_user_pda_current`. 2. Шаг 1 — запрос временного пароля сессии AuthChallenge @@ -173,4 +137,4 @@ pushAuthKey TEXT } 📘 Итоговая схема создания сессии -AddUser → AuthChallenge → CreateAuthSession → Session Created +PDA snapshot ready → AuthChallenge → CreateAuthSession → Session Created diff --git a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_AddUser_Handler.java b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_AddUser_Handler.java deleted file mode 100644 index d2756b0b..00000000 --- a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_AddUser_Handler.java +++ /dev/null @@ -1,26 +0,0 @@ -package server.logic.ws_protocol.JSON.handlers.tempToTest; - -import server.logic.ws_protocol.JSON.ConnectionContext; -import server.logic.ws_protocol.JSON.entyties.Net_Request; -import server.logic.ws_protocol.JSON.entyties.Net_Response; -import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler; -import server.logic.ws_protocol.JSON.handlers.tempToTest.entyties.Net_AddUser_Request; -import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory; - -/** - * AddUser отключен: регистрация работает через Solana. - */ -public class Net_AddUser_Handler implements JsonMessageHandler { - - @Override - public Net_Response handle(Net_Request baseRequest, ConnectionContext ctx) { - Net_AddUser_Request req = (Net_AddUser_Request) baseRequest; - return NetExceptionResponseFactory.error( - req, - 410, - "ADD_USER_DISABLED", - "Серверная регистрация AddUser отключена. Используйте регистрацию через Solana." - ); - } -} - diff --git a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_GetUser_Handler.java b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_GetUser_Handler.java index 728b8d3f..9e282951 100644 --- a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_GetUser_Handler.java +++ b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_GetUser_Handler.java @@ -5,7 +5,6 @@ import org.slf4j.LoggerFactory; import server.logic.ws_protocol.JSON.ConnectionContext; import server.logic.ws_protocol.JSON.entyties.Net_Request; import server.logic.ws_protocol.JSON.entyties.Net_Response; -import server.logic.ws_protocol.JSON.handlers.auth.SolanaUserPdaImportService; import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler; import server.logic.ws_protocol.JSON.handlers.tempToTest.entyties.Net_GetUser_Request; import server.logic.ws_protocol.JSON.handlers.tempToTest.entyties.Net_GetUser_Response; @@ -43,9 +42,6 @@ public class Net_GetUser_Handler implements JsonMessageHandler { try { SolanaUserEntry u = usersDAO.getByLogin(req.getLogin()); - if (u == null) { - u = SolanaUserPdaImportService.findOrImportByLogin(req.getLogin()); - } Net_GetUser_Response resp = new Net_GetUser_Response(); resp.setOp(req.getOp()); diff --git a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_AddUser_Request.java b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_AddUser_Request.java deleted file mode 100644 index 28b6a6b7..00000000 --- a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_AddUser_Request.java +++ /dev/null @@ -1,58 +0,0 @@ -package server.logic.ws_protocol.JSON.handlers.tempToTest.entyties; - -import server.logic.ws_protocol.JSON.entyties.Net_Request; - -/** - * Запрос AddUser — временная/тестовая регистрация локального пользователя. - * - * Клиент отправляет: - * - * { - * "op": "AddUser", - * "requestId": "test-add-1", - * "payload": { - * "login": "anya", - * "blockchainName": "anya-001", - * "solanaKey": "base64-ed25519-public-key-login", - * "blockchainKey": "base64-ed25519-public-key-blockchain", - * "clientKey": "base64-ed25519-public-key-device", - * "bchLimit": 1000000 - * } - * } - * - * Все поля лежат внутри payload. - */ -public class Net_AddUser_Request extends Net_Request { - - private String login; - private String blockchainName; - - /** Ключ пользователя Solana (публичный ключ логина) */ - private String solanaKey; - - /** Ключ блокчейна (публичный ключ блокчейна) */ - private String blockchainKey; - - /** Ключ устройства (публичный ключ устройства) */ - private String clientKey; - - private Integer bchLimit; - - public String getLogin() { return login; } - public void setLogin(String login) { this.login = login; } - - public String getBlockchainName() { return blockchainName; } - public void setBlockchainName(String blockchainName) { this.blockchainName = blockchainName; } - - public String getSolanaKey() { return solanaKey; } - public void setSolanaKey(String solanaKey) { this.solanaKey = solanaKey; } - - public String getBlockchainKey() { return blockchainKey; } - public void setBlockchainKey(String blockchainKey) { this.blockchainKey = blockchainKey; } - - public String getClientKey() { return clientKey; } - public void setClientKey(String clientKey) { this.clientKey = clientKey; } - - public Integer getBchLimit() { return bchLimit; } - public void setBchLimit(Integer bchLimit) { this.bchLimit = bchLimit; } -} \ No newline at end of file diff --git a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_AddUser_Response.java b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_AddUser_Response.java deleted file mode 100644 index 465cdcb6..00000000 --- a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_AddUser_Response.java +++ /dev/null @@ -1,21 +0,0 @@ -// file: server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_AddUser_Response.java -package server.logic.ws_protocol.JSON.handlers.tempToTest.entyties; - -import server.logic.ws_protocol.JSON.entyties.Net_Response; - -/** - * Успешный ответ на AddUser. - * - * Сейчас дополнительных полей нет — достаточно status=200. - * - * Пример: - * { - * "op": "AddUser", - * "requestId": "test-add-1", - * "status": 200, - * "payload": { } - * } - */ -public class Net_AddUser_Response extends Net_Response { - // При необходимости сюда можно добавить, например, флаг created/updated и т.п. -} \ No newline at end of file diff --git a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/messages/SignedMessagesCore.java b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/messages/SignedMessagesCore.java index f51c2eb7..7f5ffa3a 100644 --- a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/messages/SignedMessagesCore.java +++ b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/messages/SignedMessagesCore.java @@ -1,6 +1,5 @@ package server.logic.ws_protocol.JSON.messages; -import server.logic.ws_protocol.JSON.handlers.auth.SolanaUserPdaImportService; import shine.db.dao.SolanaUsersDAO; import shine.db.entities.SignedMessageV2Entry; import shine.db.entities.SolanaUserEntry; @@ -62,10 +61,7 @@ final class SignedMessagesCore { } private static SolanaUserEntry resolveUser(String login) throws Exception { - SolanaUsersDAO usersDao = SolanaUsersDAO.getInstance(); - SolanaUserEntry user = usersDao.getByLogin(login); - if (user != null) return user; - return SolanaUserPdaImportService.findOrImportByLogin(login); + return SolanaUsersDAO.getInstance().getByLogin(login); } static void validatePair(SignedMessageBlock incoming, SignedMessageBlock outgoing) { diff --git a/SHiNE-server/src/main/java/server/sync/PeriodicBlockchainSyncService.java b/SHiNE-server/src/main/java/server/sync/PeriodicBlockchainSyncService.java index f88f49bd..0b3deebe 100644 --- a/SHiNE-server/src/main/java/server/sync/PeriodicBlockchainSyncService.java +++ b/SHiNE-server/src/main/java/server/sync/PeriodicBlockchainSyncService.java @@ -4,15 +4,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import server.logic.ws_protocol.JSON.entyties.Net_Exception_Response; import server.logic.ws_protocol.JSON.entyties.Net_Response; -import server.logic.ws_protocol.JSON.handlers.auth.SolanaUserPdaImportService; import server.logic.ws_protocol.JSON.handlers.blockchain.Net_AddBlock_Handler; import server.logic.ws_protocol.JSON.handlers.blockchain.Net_AddBlock_Handler_utils.BlockchainLocks; import server.logic.ws_protocol.JSON.handlers.blockchain.entyties.Net_AddBlock_Request; import shine.db.dao.BlockchainResyncCleanupDAO; import shine.db.dao.BlockchainStateDAO; import shine.db.dao.SyncServersDAO; -import shine.db.dao.UserCreateDAO; -import shine.db.dao.SolanaUsersDAO; import shine.db.dao.SolanaUserPdaCurrentDAO; import shine.db.entities.BlockchainStateEntry; import shine.db.entities.SolanaUserPdaCurrentEntry; @@ -20,7 +17,6 @@ import shine.db.entities.SyncServerEntry; import server.sync.BlockchainResyncGuard; import utils.files.FileStoreUtil; import utils.blockchain.BlockchainNameUtil; -import utils.config.AppConfig; import java.util.concurrent.locks.ReentrantLock; import java.util.List; @@ -55,12 +51,9 @@ public final class PeriodicBlockchainSyncService { private static final Net_AddBlock_Handler ADD_BLOCK_HANDLER = new Net_AddBlock_Handler(); private static final BlockchainStateDAO STATE_DAO = BlockchainStateDAO.getInstance(); private static final SyncServersDAO SYNC_SERVERS_DAO = SyncServersDAO.getInstance(); - private static final UserCreateDAO USER_CREATE_DAO = UserCreateDAO.getInstance(); private static final BlockchainResyncCleanupDAO RESYNC_CLEANUP_DAO = BlockchainResyncCleanupDAO.getInstance(); private static final FileStoreUtil FILE_STORE = FileStoreUtil.getInstance(); - private static final SolanaUsersDAO SOLANA_USERS_DAO = SolanaUsersDAO.getInstance(); private static final SolanaUserPdaCurrentDAO SOLANA_USER_PDA_CURRENT_DAO = SolanaUserPdaCurrentDAO.getInstance(); - private static final String CONFIG_IMPORT_PROFILE_FROM_PARTNER = "sync.importUserProfileFromPartner.enabled"; private PeriodicBlockchainSyncService() {} @@ -370,11 +363,7 @@ public final class PeriodicBlockchainSyncService { if (login == null || login.isBlank()) { return false; } - if (AppConfig.getInstance().getBoolean(CONFIG_IMPORT_PROFILE_FROM_PARTNER, false)) { - return importUserProfileFromPartner(partner, login); - } - SolanaUserPdaImportService.findOrImportByLogin(login); - return STATE_DAO.getByBlockchainName(blockchainName) != null; + return false; } catch (Exception e) { log.warn("Periodic blockchain sync: failed to ensure local chain exists for blockchainName={} reason={}", blockchainName, String.valueOf(e)); @@ -416,67 +405,6 @@ public final class PeriodicBlockchainSyncService { return keyBytes != null && keyBytes.length == 32; } - private static boolean importUserProfileFromPartner(SyncServerEntry partner, String login) throws Exception { - if (partner == null || partner.getServerAddress() == null || partner.getServerAddress().isBlank()) { - return false; - } - - RemoteBlockchainSyncClient.RemoteSyncUserProfile profile = - REMOTE.getSyncUserProfile(partner.getServerAddress(), login); - if (profile == null) { - log.warn("Periodic blockchain sync: partner has no sync profile for login={} partner={}", - login, normalize(partner.getLogin())); - return false; - } - - long now = System.currentTimeMillis(); - long sizeLimit = profile.blockchainSizeLimitBytes() > 0 ? profile.blockchainSizeLimitBytes() : 100_000L; - BlockchainStateEntry state = buildStateFromProfile(profile, sizeLimit, now); - - if (SOLANA_USERS_DAO.existsByLogin(profile.login())) { - STATE_DAO.insertIfMissing(state); - return STATE_DAO.getByBlockchainName(profile.blockchainName()) != null; - } - - boolean inserted = USER_CREATE_DAO.insertUserWithBlockchain( - profile.login(), - profile.blockchainName(), - profile.solanaKey(), - profile.blockchainKey(), - profile.clientKey(), - sizeLimit, - now - ); - - if (inserted) { - return STATE_DAO.getByBlockchainName(profile.blockchainName()) != null; - } - - // Если пользователь уже успел существовать локально, но chain_state отсутствует, - // добиваем только state и не пытаемся пересоздать identity. - if (SOLANA_USERS_DAO.existsByLogin(profile.login())) { - STATE_DAO.insertIfMissing(state); - return STATE_DAO.getByBlockchainName(profile.blockchainName()) != null; - } - - return false; - } - - private static BlockchainStateEntry buildStateFromProfile(RemoteBlockchainSyncClient.RemoteSyncUserProfile profile, - long sizeLimit, - long nowMs) { - BlockchainStateEntry state = new BlockchainStateEntry(); - state.setBlockchainName(profile.blockchainName()); - state.setLogin(profile.login()); - state.setBlockchainKey(profile.blockchainKey()); - state.setSizeLimit(sizeLimit); - state.setFileSizeBytes(0L); - state.setLastBlockNumber(-1); - state.setLastBlockHash(null); - state.setUpdatedAtMs(nowMs); - return state; - } - private static String normalize(String value) { if (value == null) return null; String s = value.trim().toLowerCase(Locale.ROOT); diff --git a/SHiNE-server/src/test/java/test/it/cases/IT_01_AddUser.java b/SHiNE-server/src/test/java/test/it/cases/IT_01_AddUser.java deleted file mode 100644 index cd132733..00000000 --- a/SHiNE-server/src/test/java/test/it/cases/IT_01_AddUser.java +++ /dev/null @@ -1,365 +0,0 @@ -package test.it.cases; - -import test.it.utils.TestConfig; -import test.it.utils.TestIds; -import test.it.utils.json.JsonBuilders; -import test.it.utils.json.JsonParsers; -import test.it.utils.log.TestResult; -import test.it.utils.ws.WsSession; - -import java.time.Duration; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.fail; - -/** - * IT_01_AddUser - * Создаёт 3 пользователей: TestUser1/2/3 (200 OK или 409 USER_ALREADY_EXISTS). - * - * Обновление: - * - теперь AddUser может вернуть 409 не только USER_ALREADY_EXISTS, - * но и BLOCKCHAIN_ALREADY_EXISTS / BLOCKCHAIN_STATE_ALREADY_EXISTS. - * - дополнительно проверяем GetUser (status=200 всегда). - * - добавлен SearchUsers: поиск по префиксу (первые 3 символа). - */ -public class IT_01_AddUser { - - public static void main(String[] args) { - String summary = run(); - System.out.println(summary); - } - - public static String run() { - TestResult r = new TestResult("IT_01_AddUser"); - - Duration t = Duration.ofSeconds(5); - - try (WsSession ws = WsSession.open()) { - - checkPingAndServerInfo(r, ws, t); - - r.ok("AddUser USER1: " + TestConfig.LOGIN()); - String resp1 = ws.call("AddUser#USER1", JsonBuilders.addUser(TestConfig.LOGIN()), t); - checkAddUser200or409(r, resp1); - checkGetUserMustExist(r, ws, TestConfig.LOGIN(), t); - - r.ok("AddUser USER2: " + TestConfig.LOGIN2()); - String resp2 = ws.call("AddUser#USER2", JsonBuilders.addUser(TestConfig.LOGIN2()), t); - checkAddUser200or409(r, resp2); - checkGetUserMustExist(r, ws, TestConfig.LOGIN2(), t); - - r.ok("AddUser USER3: " + TestConfig.LOGIN3()); - String resp3 = ws.call("AddUser#USER3", JsonBuilders.addUser(TestConfig.LOGIN3()), t); - checkAddUser200or409(r, resp3); - checkGetUserMustExist(r, ws, TestConfig.LOGIN3(), t); - - // Доп: проверяем case-insensitive поиск в GetUser - String mixed = mixCase(TestConfig.LOGIN()); - r.ok("GetUser case-insensitive: запрос=" + mixed + " (должен найти " + TestConfig.LOGIN() + ")"); - checkGetUserMustExist(r, ws, mixed, t); - - // Доп: проверяем "не существует" (но status=200) - String missing = "NoSuchUser_987654321"; - r.ok("GetUser missing: " + missing); - checkGetUserMustNotExist(r, ws, missing, t); - - // SearchUsers: один раз ищем по первым трём символам логина USER1 - String prefix3 = first3(TestConfig.LOGIN()); - String prefix3Mixed = mixCase(prefix3); - r.ok("SearchUsers: prefix(3)='" + prefix3Mixed + "' (должен вернуть список и содержать " + TestConfig.LOGIN() + ")"); - checkSearchUsersMustContain(r, ws, prefix3Mixed, TestConfig.LOGIN(), t); - - checkNegativeRequests(r, ws, t); - - } catch (Throwable e) { - r.fail("IT_01_AddUser упал: " + e.getMessage()); - } - - return r.summaryLine(); - } - - private static void checkPingAndServerInfo(TestResult r, WsSession ws, Duration t) { - String pingResp = ws.call("Ping", JsonBuilders.ping(System.currentTimeMillis()), t); - if (JsonParsers.status(pingResp) != 200 || !Boolean.TRUE.equals(JsonParsers.ok(pingResp))) { - r.fail("Ping: ожидали status=200 и ok=true, resp=" + pingResp); - fail("Ping unexpected response"); - } - - Long serverTs = JsonParsers.pingTs(pingResp); - if (serverTs == null || serverTs <= 0) { - r.fail("Ping: сервер не вернул ts, resp=" + pingResp); - fail("Ping missing ts"); - } - r.ok("Ping: ok, serverTs=" + serverTs); - - String infoResp = ws.call("GetServerInfo", JsonBuilders.getServerInfo(), t); - if (JsonParsers.status(infoResp) != 200 || !Boolean.TRUE.equals(JsonParsers.ok(infoResp))) { - r.fail("GetServerInfo: ожидали status=200 и ok=true, resp=" + infoResp); - fail("GetServerInfo unexpected response"); - } - if (!JsonParsers.payloadIsObject(infoResp)) { - r.fail("GetServerInfo: payload должен быть объектом, resp=" + infoResp); - fail("GetServerInfo payload is not object"); - } - - r.ok("GetServerInfo: ok, url='" + safe(JsonParsers.payloadText(infoResp, "url")) - + "', version='" + safe(JsonParsers.payloadText(infoResp, "version")) - + "', physicalRegion='" + safe(JsonParsers.payloadText(infoResp, "physicalRegion")) - + "', description='" + safe(JsonParsers.payloadText(infoResp, "description")) - + "', origin='" + safe(JsonParsers.payloadText(infoResp, "origin")) - + "', extraInfo='" + safe(JsonParsers.payloadText(infoResp, "extraInfo")) + "'"); - } - - private static void checkAddUser200or409(TestResult r, String resp) { - int st = JsonParsers.status(resp); - if (st == 200) { - r.ok("AddUser: status=200 (создан)"); - return; - } - if (st == 409) { - String code = JsonParsers.errorCode(resp); - - // раньше был только USER_ALREADY_EXISTS, теперь добавились ещё варианты - if ("USER_ALREADY_EXISTS".equals(code)) { - r.ok("AddUser: status=409 USER_ALREADY_EXISTS (уже был)"); - return; - } - if ("BLOCKCHAIN_ALREADY_EXISTS".equals(code)) { - r.ok("AddUser: status=409 BLOCKCHAIN_ALREADY_EXISTS (blockchainName уже занят)"); - return; - } - if ("BLOCKCHAIN_STATE_ALREADY_EXISTS".equals(code)) { - r.ok("AddUser: status=409 BLOCKCHAIN_STATE_ALREADY_EXISTS (blockchain_state уже есть)"); - return; - } - - r.fail("AddUser: status=409 но code=" + code + ", resp=" + resp); - fail("AddUser unexpected 409 code=" + code); - } - r.fail("AddUser: неожиданный status=" + st + ", resp=" + resp); - fail("AddUser unexpected status=" + st); - } - - private static void checkGetUserMustExist(TestResult r, WsSession ws, String loginQuery, Duration t) { - String resp = ws.call("GetUser#" + loginQuery, JsonBuilders.getUser(loginQuery), t); - - int st = JsonParsers.status(resp); - if (st != 200) { - r.fail("GetUser: ожидали status=200, получили " + st + ", resp=" + resp); - fail("GetUser unexpected status=" + st); - } - - Boolean exists = JsonParsers.exists(resp); - if (exists == null || !exists) { - r.fail("GetUser: ожидали exists=true, resp=" + resp); - fail("GetUser expected exists=true"); - } - - // Проверяем, что сервер возвращает данные - String login = JsonParsers.userLogin(resp); - String blockchainName = JsonParsers.userBlockchainName(resp); - String solanaKey = JsonParsers.userSolanaKey(resp); - String blockchainKey = JsonParsers.userBlockchainKey(resp); - String clientKey = JsonParsers.userClientKey(resp); - - if (isBlank(login) || isBlank(blockchainName) || isBlank(solanaKey) || isBlank(blockchainKey) || isBlank(clientKey)) { - r.fail("GetUser: exists=true, но поля пустые/неполные, resp=" + resp); - fail("GetUser returned incomplete user data"); - } - - // ВАЖНО: - // Поиск делается без учета регистра, но login/blockchainName должны вернуться как в БД. - // Для тех логинов, которые мы создаем в тесте, это ровно TestConfig.LOGIN*(). - // Поэтому если запрос был смешанный регистр — сравниваем не с loginQuery, а с "каноничным" логином из конфига. - String canonical = canonicalLogin(loginQuery); - if (canonical != null) { - if (!login.equals(canonical)) { - r.fail("GetUser: login должен вернуться как в БД. expected=" + canonical + ", got=" + login + ", resp=" + resp); - fail("GetUser wrong login case"); - } - - String expectedBch = TestConfig.getBlockchainName(canonical); - if (!blockchainName.equals(expectedBch)) { - r.fail("GetUser: blockchainName должен вернуться как в БД. expected=" + expectedBch + ", got=" + blockchainName + ", resp=" + resp); - fail("GetUser wrong blockchainName"); - } - - // ключи должны совпадать с теми, что AddUser использует при регистрации - String expSol = TestConfig.solanaPublicKeyB64(canonical); - String expBchKey = TestConfig.blockchainPublicKeyB64(canonical); - String expDev = TestConfig.clientPublicKeyB64(canonical); - - if (!solanaKey.equals(expSol)) { - r.fail("GetUser: solanaKey mismatch, resp=" + resp); - fail("GetUser solanaKey mismatch"); - } - if (!blockchainKey.equals(expBchKey)) { - r.fail("GetUser: blockchainKey mismatch, resp=" + resp); - fail("GetUser blockchainKey mismatch"); - } - if (!clientKey.equals(expDev)) { - r.fail("GetUser: clientKey mismatch, resp=" + resp); - fail("GetUser clientKey mismatch"); - } - } - - r.ok("GetUser: exists=true, login=" + login + ", blockchainName=" + blockchainName); - } - - private static void checkGetUserMustNotExist(TestResult r, WsSession ws, String loginQuery, Duration t) { - String resp = ws.call("GetUser#" + loginQuery, JsonBuilders.getUser(loginQuery), t); - - int st = JsonParsers.status(resp); - if (st != 200) { - r.fail("GetUser(not exist): ожидали status=200, получили " + st + ", resp=" + resp); - fail("GetUser(not exist) unexpected status=" + st); - } - - Boolean exists = JsonParsers.exists(resp); - if (exists == null) { - r.fail("GetUser(not exist): payload.exists отсутствует, resp=" + resp); - fail("GetUser(not exist) missing exists"); - } - if (exists) { - r.fail("GetUser(not exist): ожидали exists=false, resp=" + resp); - fail("GetUser(not exist) expected exists=false"); - } - - r.ok("GetUser: exists=false (ok)"); - } - - private static void checkSearchUsersMustContain(TestResult r, WsSession ws, String prefix, String expectedLogin, Duration t) { - String resp = ws.call("SearchUsers#" + prefix, JsonBuilders.searchUsers(prefix), t); - - int st = JsonParsers.status(resp); - if (st != 200) { - r.fail("SearchUsers: ожидали status=200, получили " + st + ", resp=" + resp); - fail("SearchUsers unexpected status=" + st); - } - - List logins = JsonParsers.searchLogins(resp); - if (logins == null || logins.isEmpty()) { - r.fail("SearchUsers: ожидали непустой список, resp=" + resp); - fail("SearchUsers expected non-empty list"); - } - - // ВАЖНО: ожидаемый логин должен быть в ответе в регистре БД (каноничный expectedLogin) - boolean found = false; - for (String s : logins) { - if (expectedLogin.equals(s)) { - found = true; - break; - } - } - if (!found) { - r.fail("SearchUsers: ожидаемый логин не найден. expected=" + expectedLogin + ", got=" + logins + ", resp=" + resp); - fail("SearchUsers expected login not found"); - } - - r.ok("SearchUsers: ok, prefix=" + prefix + ", results=" + logins.size() + ", contains=" + expectedLogin); - } - - private static void checkNegativeRequests(TestResult r, WsSession ws, Duration t) { - String badAddUserReqId = TestIds.next("bad-adduser"); - String badAddUser = """ - { - "op": "AddUser", - "requestId": "%s", - "payload": { - "login": "", - "blockchainName": "%s", - "solanaKey": "%s", - "blockchainKey": "%s", - "clientKey": "%s", - "bchLimit": %d - } - } - """.formatted( - badAddUserReqId, - TestConfig.BCH_NAME(), - TestConfig.SOLANA_PUBKEY_B64(), - TestConfig.BLOCKCHAIN_PUBKEY_B64(), - TestConfig.DEVICE_PUBKEY_B64(), - TestConfig.TEST_BCH_LIMIT - ); - String badAddUserResp = ws.call("AddUser#NEGATIVE", badAddUser, t); - assertErrorFormat(badAddUserResp, "AddUser", badAddUserReqId, "BAD_FIELDS"); - r.ok("Negative AddUser: error format OK"); - - String badGetUserReqId = TestIds.next("bad-getuser"); - String badGetUser = """ - { - "op": "GetUser", - "requestId": "%s", - "payload": { - "login": "" - } - } - """.formatted(badGetUserReqId); - String badGetUserResp = ws.call("GetUser#NEGATIVE", badGetUser, t); - assertErrorFormat(badGetUserResp, "GetUser", badGetUserReqId, "BAD_FIELDS"); - r.ok("Negative GetUser: error format OK"); - - String badSearchReqId = TestIds.next("bad-searchusers"); - String badSearch = """ - { - "op": "SearchUsers", - "requestId": "%s", - "payload": { - "prefix": "" - } - } - """.formatted(badSearchReqId); - String badSearchResp = ws.call("SearchUsers#NEGATIVE", badSearch, t); - assertErrorFormat(badSearchResp, "SearchUsers", badSearchReqId, "BAD_FIELDS"); - r.ok("Negative SearchUsers: error format OK"); - } - - private static void assertErrorFormat(String resp, String op, String requestId, String code) { - int status = JsonParsers.status(resp); - if (status >= 200 && status < 300) fail("Expected non-2xx status: " + resp); - if (!Boolean.FALSE.equals(JsonParsers.ok(resp))) fail("Expected ok=false: " + resp); - if (!op.equals(JsonParsers.op(resp))) fail("Unexpected op: " + resp); - if (!requestId.equals(JsonParsers.requestId(resp))) fail("Unexpected requestId: " + resp); - if (!code.equals(JsonParsers.errorCode(resp))) fail("Unexpected error code: " + resp); - if (!JsonParsers.payloadIsObject(resp)) fail("payload must be object: " + resp); - if (JsonParsers.payloadSize(resp) != 0) fail("error payload must be empty object: " + resp); - if (isBlank(JsonParsers.message(resp))) fail("error message must be present: " + resp); - } - - private static String canonicalLogin(String anyCaseLogin) { - if (anyCaseLogin == null) return null; - String x = anyCaseLogin.trim(); - if (x.isEmpty()) return null; - - // Привязка только к нашим тестовым логинам, чтобы не гадать. - if (x.equalsIgnoreCase(TestConfig.LOGIN())) return TestConfig.LOGIN(); - if (x.equalsIgnoreCase(TestConfig.LOGIN2())) return TestConfig.LOGIN2(); - if (x.equalsIgnoreCase(TestConfig.LOGIN3())) return TestConfig.LOGIN3(); - - return null; - } - - private static String mixCase(String s) { - if (s == null) return null; - String x = s.trim(); - if (x.length() < 2) return x; - // простой "микс" без рандома, чтобы тест был детерминированный - return Character.toUpperCase(x.charAt(0)) + x.substring(1).toLowerCase(); - } - - private static String first3(String s) { - if (s == null) return ""; - String x = s.trim(); - if (x.length() <= 3) return x; - return x.substring(0, 3); - } - - private static boolean isBlank(String s) { - return s == null || s.trim().isEmpty(); - } - - private static String safe(String s) { - return s == null ? "" : s; - } -} diff --git a/SHiNE-server/src/test/java/test/it/cases/IT_02_Sessions.java b/SHiNE-server/src/test/java/test/it/cases/IT_02_Sessions.java index adde6f78..35a261e3 100644 --- a/SHiNE-server/src/test/java/test/it/cases/IT_02_Sessions.java +++ b/SHiNE-server/src/test/java/test/it/cases/IT_02_Sessions.java @@ -32,8 +32,7 @@ public class IT_02_Sessions { private static final String LOGIN = TestConfig.LOGIN(); public static void main(String[] args) { - TestLog.info("Standalone: этот тест требует заранее созданных пользователей -> сначала запускаю IT_01_AddUser"); - System.out.println(IT_01_AddUser.run()); + TestLog.info("Standalone: этот тест требует заранее существующего пользователя в актуальном PDA snapshot"); String summary = run(); System.out.println(summary); } diff --git a/SHiNE-server/src/test/java/test/it/cases/IT_03_AddBlock_NoAuth.java b/SHiNE-server/src/test/java/test/it/cases/IT_03_AddBlock_NoAuth.java index d40f4b6f..b767688c 100644 --- a/SHiNE-server/src/test/java/test/it/cases/IT_03_AddBlock_NoAuth.java +++ b/SHiNE-server/src/test/java/test/it/cases/IT_03_AddBlock_NoAuth.java @@ -34,8 +34,7 @@ import static org.junit.jupiter.api.Assertions.*; public class IT_03_AddBlock_NoAuth { public static void main(String[] args) { - TestLog.info("Standalone: этот тест требует заранее созданных пользователей -> запускаю IT_01_AddUser"); - System.out.println(IT_01_AddUser.run()); + TestLog.info("Standalone: этот тест требует заранее существующих пользователей в актуальном PDA snapshot"); String summary = run(); System.out.println(summary); } diff --git a/SHiNE-server/src/test/java/test/it/cases/IT_04_UserParams_NoAuth.java b/SHiNE-server/src/test/java/test/it/cases/IT_04_UserParams_NoAuth.java index 3f050f82..74bcd7a6 100644 --- a/SHiNE-server/src/test/java/test/it/cases/IT_04_UserParams_NoAuth.java +++ b/SHiNE-server/src/test/java/test/it/cases/IT_04_UserParams_NoAuth.java @@ -28,8 +28,7 @@ public class IT_04_UserParams_NoAuth { private static final ObjectMapper M = new ObjectMapper(); public static void main(String[] args) { - TestLog.info("Standalone: этот тест требует заранее созданных пользователей -> сначала запускаю IT_01_AddUser"); - System.out.println(IT_01_AddUser.run()); + TestLog.info("Standalone: этот тест требует заранее существующего пользователя в актуальном PDA snapshot"); String summary = run(); System.out.println(summary); } @@ -283,4 +282,4 @@ public class IT_04_UserParams_NoAuth { return null; } } -} \ No newline at end of file +} diff --git a/SHiNE-server/src/test/java/test/it/cases/IT_07_EspPairing.java b/SHiNE-server/src/test/java/test/it/cases/IT_07_EspPairing.java index dcaaff39..0ac2f49f 100644 --- a/SHiNE-server/src/test/java/test/it/cases/IT_07_EspPairing.java +++ b/SHiNE-server/src/test/java/test/it/cases/IT_07_EspPairing.java @@ -8,7 +8,6 @@ import test.it.utils.log.TestResult; import test.it.utils.ws.WsSession; import utils.crypto.Ed25519Util; import shine.db.dao.SolanaUsersDAO; -import shine.db.entities.SolanaUserEntry; import utils.crypto.HashSHA256Util; import java.time.Duration; @@ -22,7 +21,7 @@ public class IT_07_EspPairing { private static final String LOGIN = TestConfig.LOGIN(); public static void main(String[] args) { - TestLog.info("Standalone: при необходимости локально создаю тестового пользователя напрямую в БД"); + TestLog.info("Standalone: этот тест требует заранее существующего пользователя в актуальном PDA snapshot"); String summary = run(); System.out.println(summary); } @@ -211,13 +210,7 @@ public class IT_07_EspPairing { if (SolanaUsersDAO.getInstance().existsByLogin(LOGIN)) { return; } - SolanaUserEntry entry = new SolanaUserEntry(); - entry.setLogin(LOGIN); - entry.setBlockchainName(TestConfig.getBlockchainName(LOGIN)); - entry.setSolanaKey(TestConfig.solanaPublicKeyB64(LOGIN)); - entry.setBlockchainKey(TestConfig.blockchainPublicKeyB64(LOGIN)); - entry.setClientKey(TestConfig.clientPublicKeyB64(LOGIN)); - SolanaUsersDAO.getInstance().insert(entry); + throw new IllegalStateException("Тестовый пользователь отсутствует в актуальном PDA snapshot: " + LOGIN); } private static String derivePairingHash(String login, String password) { diff --git a/SHiNE-server/src/test/java/test/it/cases/SeedDataPopulationHelper.java b/SHiNE-server/src/test/java/test/it/cases/SeedDataPopulationHelper.java index 9b6bcd0a..b08e3cb9 100644 --- a/SHiNE-server/src/test/java/test/it/cases/SeedDataPopulationHelper.java +++ b/SHiNE-server/src/test/java/test/it/cases/SeedDataPopulationHelper.java @@ -7,8 +7,6 @@ import blockchain.body.TextBody; import blockchain.body.UserParamBody; import test.it.blockchain.AddBlockSender; import test.it.blockchain.ChainState; -import test.it.utils.TestIds; -import test.it.utils.json.JsonParsers; import test.it.utils.log.TestResult; import test.it.utils.ws.WsSession; import utils.crypto.Ed25519Util; @@ -25,7 +23,8 @@ import java.util.Objects; /** * Вспомогательные функции для массового заполнения тестовой соц-сети через API. - * Вся запись состояния делается только через AddUser / AddBlock. + * Пользователи должны уже существовать в актуальном PDA snapshot сервера. + * Вся запись блокчейн-состояния делается через AddBlock. */ public final class SeedDataPopulationHelper { @@ -52,7 +51,6 @@ public final class SeedDataPopulationHelper { } public void createUsersAndHeaders(List users) { - for (UserSpec user : users) createUserViaApi(user.login); for (UserSpec user : users) initHeader(user.login); } @@ -159,48 +157,6 @@ public final class SeedDataPopulationHelper { ), timeout); } - private void createUserViaApi(String login) { - String requestId = TestIds.next("seed_adduser"); - String req = """ - { - "op": "AddUser", - "requestId": "%s", - "payload": { - "login": "%s", - "blockchainName": "%s", - "solanaKey": "%s", - "blockchainKey": "%s", - "clientKey": "%s", - "bchLimit": 50000000 - } - } - """.formatted( - requestId, - login, - bch(login), - keys.solanaPublicB64, - keys.blockchainPublicB64, - keys.clientPublicB64 - ); - - String resp = ws.call("AddUser#" + login, req, timeout); - int status = JsonParsers.status(resp); - if (status == 200) { - result.ok("AddUser " + login + ": created"); - return; - } - if (status == 409) { - String code = JsonParsers.errorCode(resp); - if ("USER_ALREADY_EXISTS".equals(code) - || "BLOCKCHAIN_ALREADY_EXISTS".equals(code) - || "BLOCKCHAIN_STATE_ALREADY_EXISTS".equals(code)) { - result.ok("AddUser " + login + ": already exists (" + code + ")"); - return; - } - } - throw new IllegalStateException("AddUser failed for " + login + ": status=" + status + ", resp=" + resp); - } - private void initHeader(String login) { ChainState state = new ChainState(); AddBlockSender sender = new AddBlockSender(ws, state, login, bch(login), keys.blockchainPrivate32); diff --git a/SHiNE-server/src/test/java/test/it/cases/Seed_TestDataPopulation.java b/SHiNE-server/src/test/java/test/it/cases/Seed_TestDataPopulation.java index 97d5d11c..40569b8e 100644 --- a/SHiNE-server/src/test/java/test/it/cases/Seed_TestDataPopulation.java +++ b/SHiNE-server/src/test/java/test/it/cases/Seed_TestDataPopulation.java @@ -12,7 +12,8 @@ import static org.junit.jupiter.api.Assertions.fail; * Seed_TestDataPopulation * * Заполняет тестовую соц-сеть через API: - * - пользователи + HEADER через AddUser/AddBlock; + * - пользователи должны уже существовать в актуальном PDA snapshot; + * - HEADER и остальные блоки пишутся через AddBlock; * - параметры профиля (имя, фамилия, пол, адрес, web, phone, official, shine) через AddBlock USER_PARAM; * - связи (close friend/contact/follow/parent/child/sibling) через AddBlock CONNECTION; * - посты через AddBlock TEXT_POST. @@ -34,7 +35,7 @@ public class Seed_TestDataPopulation { SeedDataPopulationHelper seed = new SeedDataPopulationHelper(ws, result, timeout, PASSWORD); // ----------------------------------------------------------------- - // 1) Пользователи и профили + // 1) Заголовки и профили // ----------------------------------------------------------------- List users = buildUsers(); seed.createUsersAndHeaders(users); diff --git a/SHiNE-server/src/test/java/test/it/runner/IT_RunAllMain.java b/SHiNE-server/src/test/java/test/it/runner/IT_RunAllMain.java index 9c1c9ce8..ae9eca17 100644 --- a/SHiNE-server/src/test/java/test/it/runner/IT_RunAllMain.java +++ b/SHiNE-server/src/test/java/test/it/runner/IT_RunAllMain.java @@ -1,6 +1,5 @@ package test.it.runner; -import test.it.cases.IT_01_AddUser; import test.it.cases.IT_00_TechnicalRequests; import test.it.cases.IT_02_Sessions; import test.it.cases.IT_03_AddBlock_NoAuth; @@ -44,9 +43,6 @@ public class IT_RunAllMain { String s0 = IT_00_TechnicalRequests.run(); summaries.add(s0); if (s0.contains("FAIL:")) { failed++; if (STOP_ON_FIRST_FAIL) return finishEarly(summaries, failed); } - String s1 = IT_01_AddUser.run(); summaries.add(s1); - if (s1.contains("FAIL:")) { failed++; if (STOP_ON_FIRST_FAIL) return finishEarly(summaries, failed); } - String s2 = IT_02_Sessions.run(); summaries.add(s2); if (s2.contains("FAIL:")) { failed++; if (STOP_ON_FIRST_FAIL) return finishEarly(summaries, failed); } diff --git a/SHiNE-server/src/test/java/test/it/suite/IT_00_Suite.java b/SHiNE-server/src/test/java/test/it/suite/IT_00_Suite.java index a7c7516f..b0f29901 100644 --- a/SHiNE-server/src/test/java/test/it/suite/IT_00_Suite.java +++ b/SHiNE-server/src/test/java/test/it/suite/IT_00_Suite.java @@ -2,7 +2,6 @@ package test.it.suite; import org.junit.platform.suite.api.SelectClasses; import org.junit.platform.suite.api.Suite; -import test.it.cases.IT_01_AddUser; import test.it.cases.IT_02_Sessions; import test.it.cases.IT_03_AddBlock_NoAuth; import test.it.cases.Seed_TestDataPopulation; @@ -15,7 +14,6 @@ import test.it.cases.Seed_TestDataPopulation; */ @Suite @SelectClasses({ - IT_01_AddUser.class, IT_02_Sessions.class, IT_03_AddBlock_NoAuth.class, Seed_TestDataPopulation.class diff --git a/SHiNE-server/src/test/java/test/it/utils/TestConfig.java b/SHiNE-server/src/test/java/test/it/utils/TestConfig.java index 5554a2c2..f62395e8 100644 --- a/SHiNE-server/src/test/java/test/it/utils/TestConfig.java +++ b/SHiNE-server/src/test/java/test/it/utils/TestConfig.java @@ -126,12 +126,12 @@ public final class TestConfig { public static String BCH_NAME2() { return getBlockchainName(LOGIN2()); } public static String BCH_NAME3() { return getBlockchainName(LOGIN3()); } - /** solanaKey для AddUser: публичный ключ Solana-пользователя */ + /** публичный ключ Solana-пользователя */ public static String SOLANA_PUBKEY_B64() { return solanaPublicKeyB64(LOGIN()); } public static String SOLANA2_PUBKEY_B64() { return solanaPublicKeyB64(LOGIN2()); } public static String SOLANA3_PUBKEY_B64() { return solanaPublicKeyB64(LOGIN3()); } - /** blockchainKey для AddUser: публичный ключ блокчейна */ + /** публичный ключ блокчейна */ public static String BLOCKCHAIN_PUBKEY_B64() { return blockchainPublicKeyB64(LOGIN()); } public static String BLOCKCHAIN2_PUBKEY_B64() { return blockchainPublicKeyB64(LOGIN2()); } public static String BLOCKCHAIN3_PUBKEY_B64() { return blockchainPublicKeyB64(LOGIN3()); } diff --git a/SHiNE-server/src/test/java/test/it/utils/json/JsonBuilders.java b/SHiNE-server/src/test/java/test/it/utils/json/JsonBuilders.java index 07683c2d..20ce116b 100644 --- a/SHiNE-server/src/test/java/test/it/utils/json/JsonBuilders.java +++ b/SHiNE-server/src/test/java/test/it/utils/json/JsonBuilders.java @@ -11,40 +11,6 @@ import java.util.Base64; public final class JsonBuilders { private JsonBuilders() {} - // ---------------- AddUser ---------------- - - public static String addUser(String login) { - String requestId = TestIds.next("adduser"); - String blockchainName = TestConfig.getBlockchainName(login); - - String solanaKeyB64 = TestConfig.solanaPublicKeyB64(login); - String blockchainKeyB64 = TestConfig.blockchainPublicKeyB64(login); - String clientKeyB64 = TestConfig.clientPublicKeyB64(login); - - return """ - { - "op": "AddUser", - "requestId": "%s", - "payload": { - "login": "%s", - "blockchainName": "%s", - "solanaKey": "%s", - "blockchainKey": "%s", - "clientKey": "%s", - "bchLimit": %d - } - } - """.formatted( - requestId, - login, - blockchainName, - solanaKeyB64, - blockchainKeyB64, - clientKeyB64, - TestConfig.TEST_BCH_LIMIT - ); - } - // ---------------- GetUser ---------------- public static String getUser(String login) { diff --git a/VERSION.properties b/VERSION.properties index 72a433e7..9bac0fee 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ client.version=1.2.354 -server.version=1.2.333 +server.version=1.2.334