Сделал что бы при создании пользователя передавались три ключа пользователя. И имя блокчейна сделал через "-"
This commit is contained in:
AidarKC 2026-01-08 15:02:01 +03:00
parent 1ea5390771
commit 7a167b470a
7 changed files with 116 additions and 24 deletions

View File

@ -1,21 +1,71 @@
package utils.blockchain; package utils.blockchain;
import java.util.Objects;
public final class BlockchainNameUtil { public final class BlockchainNameUtil {
/** Сколько символов отрезаем с конца blockchainName, чтобы получить login. */ /**
/** Теперь новое правило везде использовать только 3 символа номера блокчена в конце его имени */ * Теперь новое правило:
public static final int BLOCKCHAIN_NAME_LOGIN_SUFFIX_LEN = 3; * blockchainName = login + "-"+ 3 цифры
* Пример: "Dima-001" -> "Dima"
*
* Сколько символов отрезаем с конца blockchainName, чтобы получить login: "-001" = 4
*/
public static final int BLOCKCHAIN_NAME_LOGIN_SUFFIX_LEN = 4;
private BlockchainNameUtil() {} private BlockchainNameUtil() {}
/** /**
* Извлечь login из blockchainName: отрезаем последние 3 символа. * Извлечь login из blockchainName: отрезаем последние 4 символа ("-NNN").
* Пример: "Dima001" -> "Dima" * Пример: "Dima-001" -> "Dima"
*/ */
public static String loginFromBlockchainName(String blockchainName) { public static String loginFromBlockchainName(String blockchainName) {
if (blockchainName == null) return null; if (blockchainName == null) return null;
String s = blockchainName.trim(); String s = blockchainName.trim();
if (s.length() <= BLOCKCHAIN_NAME_LOGIN_SUFFIX_LEN) return null; if (!hasDashAnd3DigitsSuffix(s)) return null;
return s.substring(0, s.length() - BLOCKCHAIN_NAME_LOGIN_SUFFIX_LEN); return s.substring(0, s.length() - BLOCKCHAIN_NAME_LOGIN_SUFFIX_LEN);
} }
/**
* Проверка правила:
* - blockchainName должен оканчиваться на "-"+3 цифры
* - blockchainName без суффикса "-NNN" должен равняться login
*
* ВАЖНО:
* - сравнение строгое (case-sensitive)
* - null/blank считаем невалидным
*/
public static boolean isBlockchainNameMatchesLogin(String blockchainName, String login) {
if (blockchainName == null || login == null) return false;
String bn = blockchainName.trim();
String lg = login.trim();
if (bn.isEmpty() || lg.isEmpty()) return false;
if (!hasDashAnd3DigitsSuffix(bn)) return false;
String extracted = bn.substring(0, bn.length() - BLOCKCHAIN_NAME_LOGIN_SUFFIX_LEN);
return Objects.equals(extracted, lg);
}
private static boolean hasDashAnd3DigitsSuffix(String s) {
if (s == null) return false;
int len = s.length();
if (len <= BLOCKCHAIN_NAME_LOGIN_SUFFIX_LEN) return false;
int dashPos = len - 4;
if (s.charAt(dashPos) != '-') return false;
char c1 = s.charAt(len - 3);
char c2 = s.charAt(len - 2);
char c3 = s.charAt(len - 1);
return isDigit(c1) && isDigit(c2) && isDigit(c3);
}
private static boolean isDigit(char c) {
return c >= '0' && c <= '9';
}
} }

View File

@ -5,9 +5,9 @@ import org.slf4j.LoggerFactory;
import server.logic.ws_protocol.JSON.ConnectionContext; import server.logic.ws_protocol.JSON.ConnectionContext;
import server.logic.ws_protocol.JSON.entyties.Net_Request; import server.logic.ws_protocol.JSON.entyties.Net_Request;
import server.logic.ws_protocol.JSON.entyties.Net_Response; 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.handlers.tempToTest.entyties.Net_AddUser_Request;
import server.logic.ws_protocol.JSON.handlers.tempToTest.entyties.Net_AddUser_Response; import server.logic.ws_protocol.JSON.handlers.tempToTest.entyties.Net_AddUser_Response;
import server.logic.ws_protocol.JSON.handlers.JsonMessageHandler;
import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory; import server.logic.ws_protocol.JSON.utils.NetExceptionResponseFactory;
import server.logic.ws_protocol.WireCodes; import server.logic.ws_protocol.WireCodes;
import shine.db.SqliteDbController; import shine.db.SqliteDbController;
@ -15,6 +15,7 @@ import shine.db.dao.BlockchainStateDAO;
import shine.db.dao.SolanaUsersDAO; import shine.db.dao.SolanaUsersDAO;
import shine.db.entities.BlockchainStateEntry; import shine.db.entities.BlockchainStateEntry;
import shine.db.entities.SolanaUserEntry; import shine.db.entities.SolanaUserEntry;
import utils.blockchain.BlockchainNameUtil;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
@ -34,13 +35,24 @@ public class Net_AddUser_Handler implements JsonMessageHandler {
if (req.getLogin() == null || req.getLogin().isBlank() if (req.getLogin() == null || req.getLogin().isBlank()
|| req.getBlockchainName() == null || req.getBlockchainName().isBlank() || req.getBlockchainName() == null || req.getBlockchainName().isBlank()
|| req.getSolanaKey() == null || req.getSolanaKey().isBlank() || req.getSolanaKey() == null || req.getSolanaKey().isBlank()
|| req.getBlockchainKey() == null || req.getBlockchainKey().isBlank()
|| req.getDeviceKey() == null || req.getDeviceKey().isBlank()) { || req.getDeviceKey() == null || req.getDeviceKey().isBlank()) {
return NetExceptionResponseFactory.error( return NetExceptionResponseFactory.error(
req, req,
WireCodes.Status.BAD_REQUEST, WireCodes.Status.BAD_REQUEST,
"BAD_FIELDS", "BAD_FIELDS",
"Некорректные поля: login/blockchainName/solanaKey/deviceKey" "Некорректные поля: login/blockchainName/solanaKey/blockchainKey/deviceKey"
);
}
// blockchainName должен быть вида: <login>-NNN
if (!BlockchainNameUtil.isBlockchainNameMatchesLogin(req.getBlockchainName(), req.getLogin())) {
return NetExceptionResponseFactory.error(
req,
WireCodes.Status.BAD_REQUEST,
"BAD_BLOCKCHAIN_NAME",
"blockchainName должен быть вида <login>-NNN (пример: anya-001)"
); );
} }
@ -49,13 +61,13 @@ public class Net_AddUser_Handler implements JsonMessageHandler {
: req.getBchLimit(); : req.getBchLimit();
try { try {
byte[] blockchainKey32 = Base64.getDecoder().decode(req.getSolanaKey()); byte[] blockchainKey32 = Base64.getDecoder().decode(req.getBlockchainKey());
if (blockchainKey32.length != 32) { if (blockchainKey32.length != 32) {
return NetExceptionResponseFactory.error( return NetExceptionResponseFactory.error(
req, req,
WireCodes.Status.BAD_REQUEST, WireCodes.Status.BAD_REQUEST,
"BAD_BLOCKCHAIN_KEY", "BAD_BLOCKCHAIN_KEY",
"solanaKey должен быть Base64(32 bytes)" "blockchainKey должен быть Base64(32 bytes)"
); );
} }
@ -87,20 +99,20 @@ public class Net_AddUser_Handler implements JsonMessageHandler {
); );
} }
// 3. Создаём пользователя // 3. Создаём пользователя (solanaKey + deviceKey)
SolanaUserEntry user = new SolanaUserEntry( SolanaUserEntry user = new SolanaUserEntry(
req.getLogin(), req.getLogin(),
req.getDeviceKey(), req.getSolanaKey(),
req.getDeviceKey() req.getDeviceKey()
); );
usersDAO.insert(c, user); usersDAO.insert(c, user);
// 4. Создаём INITIAL blockchain_state // 4. Создаём INITIAL blockchain_state (blockchainKey)
BlockchainStateEntry st = new BlockchainStateEntry(); BlockchainStateEntry st = new BlockchainStateEntry();
st.setBlockchainName(req.getBlockchainName()); st.setBlockchainName(req.getBlockchainName());
st.setLogin(req.getLogin()); st.setLogin(req.getLogin());
st.setBlockchainKey(req.getSolanaKey()); // Base64(32) st.setBlockchainKey(req.getBlockchainKey()); // Base64(32)
st.setLastGlobalNumber(-1); st.setLastGlobalNumber(-1);
st.setLastGlobalHash(new byte[32]); st.setLastGlobalHash(new byte[32]);
st.setFileSizeBytes(0); st.setFileSizeBytes(0);

View File

@ -14,6 +14,7 @@ import server.logic.ws_protocol.JSON.entyties.Net_Request;
* "login": "anya", * "login": "anya",
* "blockchainName": "anya0001", * "blockchainName": "anya0001",
* "solanaKey": "base64-ed25519-public-key-login", * "solanaKey": "base64-ed25519-public-key-login",
* "blockchainKey": "base64-ed25519-public-key-blockchain",
* "deviceKey": "base64-ed25519-public-key-device", * "deviceKey": "base64-ed25519-public-key-device",
* "bchLimit": 1000000 * "bchLimit": 1000000
* } * }
@ -25,8 +26,16 @@ public class Net_AddUser_Request extends Net_Request {
private String login; private String login;
private String blockchainName; private String blockchainName;
/** Ключ пользователя Solana (публичный ключ логина) */
private String solanaKey; private String solanaKey;
/** Ключ блокчейна (публичный ключ блокчейна) */
private String blockchainKey;
/** Ключ устройства (публичный ключ устройства) */
private String deviceKey; private String deviceKey;
private Integer bchLimit; private Integer bchLimit;
public String getLogin() { return login; } public String getLogin() { return login; }
@ -38,6 +47,9 @@ public class Net_AddUser_Request extends Net_Request {
public String getSolanaKey() { return solanaKey; } public String getSolanaKey() { return solanaKey; }
public void setSolanaKey(String solanaKey) { this.solanaKey = solanaKey; } public void setSolanaKey(String solanaKey) { this.solanaKey = solanaKey; }
public String getBlockchainKey() { return blockchainKey; }
public void setBlockchainKey(String blockchainKey) { this.blockchainKey = blockchainKey; }
public String getDeviceKey() { return deviceKey; } public String getDeviceKey() { return deviceKey; }
public void setDeviceKey(String deviceKey) { this.deviceKey = deviceKey; } public void setDeviceKey(String deviceKey) { this.deviceKey = deviceKey; }

View File

@ -10,7 +10,7 @@ import java.util.concurrent.ConcurrentHashMap;
* TestConfig конфиг IT тестов: * TestConfig конфиг IT тестов:
* - 3 пользователя (TestUser1/2/3) * - 3 пользователя (TestUser1/2/3)
* - ключи по login через map (device/solana/blockchain) * - ключи по login через map (device/solana/blockchain)
* - blockchainName = login + "001" * - blockchainName = login + "-" + "001"
* *
* Важно: * Важно:
* - privateKey = Ed25519Util.generatePrivateKeyFromString(login) (sha256, 32 bytes) * - privateKey = Ed25519Util.generatePrivateKeyFromString(login) (sha256, 32 bytes)
@ -45,7 +45,7 @@ public final class TestConfig {
public static String getBlockchainName(String login) { public static String getBlockchainName(String login) {
if (login == null) throw new IllegalArgumentException("login is null"); if (login == null) throw new IllegalArgumentException("login is null");
return login + BCH_SUFFIX_3(); return login + "-" + BCH_SUFFIX_3();
} }
// ============ key maps ============ // ============ key maps ============
@ -92,6 +92,7 @@ public final class TestConfig {
// ============ base64 helpers ============ // ============ base64 helpers ============
public static String devicePublicKeyB64(String login) { return Base64.getEncoder().encodeToString(getDevicePublicKey(login)); } public static String devicePublicKeyB64(String login) { return Base64.getEncoder().encodeToString(getDevicePublicKey(login)); }
public static String solanaPublicKeyB64(String login) { return Base64.getEncoder().encodeToString(getSolanaPublicKey(login)); }
public static String blockchainPublicKeyB64(String login) { return Base64.getEncoder().encodeToString(getBlockchainPublicKey(login)); } public static String blockchainPublicKeyB64(String login) { return Base64.getEncoder().encodeToString(getBlockchainPublicKey(login)); }
// ============ backward-compatible helpers for "user1" ============ // ============ backward-compatible helpers for "user1" ============
@ -99,10 +100,15 @@ public final class TestConfig {
public static String BCH_NAME2() { return getBlockchainName(LOGIN2()); } public static String BCH_NAME2() { return getBlockchainName(LOGIN2()); }
public static String BCH_NAME3() { return getBlockchainName(LOGIN3()); } public static String BCH_NAME3() { return getBlockchainName(LOGIN3()); }
/** solanaKey для AddUser: по твоему решению = blockchain pubkey. */ /** solanaKey для AddUser: публичный ключ Solana-пользователя */
public static String LOGIN_PUBKEY_B64() { return blockchainPublicKeyB64(LOGIN()); } public static String SOLANA_PUBKEY_B64() { return solanaPublicKeyB64(LOGIN()); }
public static String LOGIN2_PUBKEY_B64() { return blockchainPublicKeyB64(LOGIN2()); } public static String SOLANA2_PUBKEY_B64() { return solanaPublicKeyB64(LOGIN2()); }
public static String LOGIN3_PUBKEY_B64() { return blockchainPublicKeyB64(LOGIN3()); } 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()); }
public static String DEVICE_PUBKEY_B64() { return devicePublicKeyB64(LOGIN()); } public static String DEVICE_PUBKEY_B64() { return devicePublicKeyB64(LOGIN()); }
public static String DEVICE2_PUBKEY_B64() { return devicePublicKeyB64(LOGIN2()); } public static String DEVICE2_PUBKEY_B64() { return devicePublicKeyB64(LOGIN2()); }

View File

@ -16,8 +16,11 @@ public final class JsonBuilders {
public static String addUser(String login) { public static String addUser(String login) {
String requestId = TestIds.next("adduser"); String requestId = TestIds.next("adduser");
String blockchainName = TestConfig.getBlockchainName(login); String blockchainName = TestConfig.getBlockchainName(login);
String solanaKeyB64 = TestConfig.blockchainPublicKeyB64(login); // solanaKey = blockchain pub
String solanaKeyB64 = TestConfig.solanaPublicKeyB64(login);
String blockchainKeyB64 = TestConfig.blockchainPublicKeyB64(login);
String deviceKeyB64 = TestConfig.devicePublicKeyB64(login); String deviceKeyB64 = TestConfig.devicePublicKeyB64(login);
return """ return """
{ {
"op": "AddUser", "op": "AddUser",
@ -26,11 +29,20 @@ public final class JsonBuilders {
"login": "%s", "login": "%s",
"blockchainName": "%s", "blockchainName": "%s",
"solanaKey": "%s", "solanaKey": "%s",
"blockchainKey": "%s",
"deviceKey": "%s", "deviceKey": "%s",
"bchLimit": %d "bchLimit": %d
} }
} }
""".formatted(requestId, login, blockchainName, solanaKeyB64, deviceKeyB64, TestConfig.TEST_BCH_LIMIT); """.formatted(
requestId,
login,
blockchainName,
solanaKeyB64,
blockchainKeyB64,
deviceKeyB64,
TestConfig.TEST_BCH_LIMIT
);
} }
// ---------------- AuthChallenge ---------------- // ---------------- AuthChallenge ----------------