19 12 25
Переделал и запросы и тесты (но ещё не тетил)
This commit is contained in:
parent
7f92dc5f51
commit
c140e3aae4
File diff suppressed because it is too large
Load Diff
@ -40,6 +40,7 @@ public final class BlockchainStateDAO {
|
|||||||
file_size_bytes,
|
file_size_bytes,
|
||||||
last_global_number,
|
last_global_number,
|
||||||
last_global_hash,
|
last_global_hash,
|
||||||
|
updated_at_ms,
|
||||||
line0_last_number, line0_last_hash,
|
line0_last_number, line0_last_hash,
|
||||||
line1_last_number, line1_last_hash,
|
line1_last_number, line1_last_hash,
|
||||||
line2_last_number, line2_last_hash,
|
line2_last_number, line2_last_hash,
|
||||||
@ -47,8 +48,7 @@ public final class BlockchainStateDAO {
|
|||||||
line4_last_number, line4_last_hash,
|
line4_last_number, line4_last_hash,
|
||||||
line5_last_number, line5_last_hash,
|
line5_last_number, line5_last_hash,
|
||||||
line6_last_number, line6_last_hash,
|
line6_last_number, line6_last_hash,
|
||||||
line7_last_number, line7_last_hash,
|
line7_last_number, line7_last_hash
|
||||||
updated_at_ms
|
|
||||||
FROM blockchain_state
|
FROM blockchain_state
|
||||||
WHERE blockchainName = ?
|
WHERE blockchainName = ?
|
||||||
""";
|
""";
|
||||||
@ -81,6 +81,7 @@ public final class BlockchainStateDAO {
|
|||||||
file_size_bytes,
|
file_size_bytes,
|
||||||
last_global_number,
|
last_global_number,
|
||||||
last_global_hash,
|
last_global_hash,
|
||||||
|
updated_at_ms,
|
||||||
line0_last_number, line0_last_hash,
|
line0_last_number, line0_last_hash,
|
||||||
line1_last_number, line1_last_hash,
|
line1_last_number, line1_last_hash,
|
||||||
line2_last_number, line2_last_hash,
|
line2_last_number, line2_last_hash,
|
||||||
@ -88,10 +89,9 @@ public final class BlockchainStateDAO {
|
|||||||
line4_last_number, line4_last_hash,
|
line4_last_number, line4_last_hash,
|
||||||
line5_last_number, line5_last_hash,
|
line5_last_number, line5_last_hash,
|
||||||
line6_last_number, line6_last_hash,
|
line6_last_number, line6_last_hash,
|
||||||
line7_last_number, line7_last_hash,
|
line7_last_number, line7_last_hash
|
||||||
updated_at_ms
|
|
||||||
) VALUES (
|
) VALUES (
|
||||||
?,?,?,?,?,?,?,?,
|
?,?,?,?,?,?,?,?,?,
|
||||||
?,?,
|
?,?,
|
||||||
?,?,
|
?,?,
|
||||||
?,?,
|
?,?,
|
||||||
@ -100,7 +100,7 @@ public final class BlockchainStateDAO {
|
|||||||
?,?,
|
?,?,
|
||||||
?,?,
|
?,?,
|
||||||
?,?,
|
?,?,
|
||||||
?
|
?,?
|
||||||
)
|
)
|
||||||
ON CONFLICT(blockchainName)
|
ON CONFLICT(blockchainName)
|
||||||
DO UPDATE SET
|
DO UPDATE SET
|
||||||
@ -111,6 +111,7 @@ public final class BlockchainStateDAO {
|
|||||||
file_size_bytes = excluded.file_size_bytes,
|
file_size_bytes = excluded.file_size_bytes,
|
||||||
last_global_number = excluded.last_global_number,
|
last_global_number = excluded.last_global_number,
|
||||||
last_global_hash = excluded.last_global_hash,
|
last_global_hash = excluded.last_global_hash,
|
||||||
|
updated_at_ms = excluded.updated_at_ms,
|
||||||
line0_last_number = excluded.line0_last_number,
|
line0_last_number = excluded.line0_last_number,
|
||||||
line0_last_hash = excluded.line0_last_hash,
|
line0_last_hash = excluded.line0_last_hash,
|
||||||
line1_last_number = excluded.line1_last_number,
|
line1_last_number = excluded.line1_last_number,
|
||||||
@ -126,12 +127,12 @@ public final class BlockchainStateDAO {
|
|||||||
line6_last_number = excluded.line6_last_number,
|
line6_last_number = excluded.line6_last_number,
|
||||||
line6_last_hash = excluded.line6_last_hash,
|
line6_last_hash = excluded.line6_last_hash,
|
||||||
line7_last_number = excluded.line7_last_number,
|
line7_last_number = excluded.line7_last_number,
|
||||||
line7_last_hash = excluded.line7_last_hash,
|
line7_last_hash = excluded.line7_last_hash
|
||||||
updated_at_ms = excluded.updated_at_ms
|
|
||||||
""";
|
""";
|
||||||
|
|
||||||
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
|
||||||
ps.setString(i++, e.getBlockchainName());
|
ps.setString(i++, e.getBlockchainName());
|
||||||
ps.setString(i++, nn(e.getLogin()));
|
ps.setString(i++, nn(e.getLogin()));
|
||||||
ps.setString(i++, nn(e.getPublicKeyBase64()));
|
ps.setString(i++, nn(e.getPublicKeyBase64()));
|
||||||
@ -140,19 +141,20 @@ public final class BlockchainStateDAO {
|
|||||||
ps.setLong(i++, e.getFileSizeBytes());
|
ps.setLong(i++, e.getFileSizeBytes());
|
||||||
ps.setInt(i++, e.getLastGlobalNumber());
|
ps.setInt(i++, e.getLastGlobalNumber());
|
||||||
ps.setString(i++, nn(e.getLastGlobalHash()));
|
ps.setString(i++, nn(e.getLastGlobalHash()));
|
||||||
|
ps.setLong(i++, e.getUpdatedAtMs());
|
||||||
|
|
||||||
for (int line = 0; line < 8; line++) {
|
for (int line = 0; line < 8; line++) {
|
||||||
ps.setInt(i++, e.getLastLineNumber(line));
|
ps.setInt(i++, e.getLastLineNumber(line));
|
||||||
ps.setString(i++, nn(e.getLastLineHash(line)));
|
ps.setString(i++, nn(e.getLastLineHash(line)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ps.setLong(i++, e.getUpdatedAtMs());
|
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BlockchainStateEntry mapRow(ResultSet rs) throws SQLException {
|
private BlockchainStateEntry mapRow(ResultSet rs) throws SQLException {
|
||||||
BlockchainStateEntry e = new BlockchainStateEntry();
|
BlockchainStateEntry e = new BlockchainStateEntry();
|
||||||
|
|
||||||
e.setBlockchainName(rs.getString("blockchainName"));
|
e.setBlockchainName(rs.getString("blockchainName"));
|
||||||
e.setLogin(rs.getString("login"));
|
e.setLogin(rs.getString("login"));
|
||||||
e.setPublicKeyBase64(rs.getString("public_key_base64"));
|
e.setPublicKeyBase64(rs.getString("public_key_base64"));
|
||||||
@ -164,12 +166,13 @@ public final class BlockchainStateDAO {
|
|||||||
e.setLastGlobalNumber(rs.getInt("last_global_number"));
|
e.setLastGlobalNumber(rs.getInt("last_global_number"));
|
||||||
e.setLastGlobalHash(rs.getString("last_global_hash"));
|
e.setLastGlobalHash(rs.getString("last_global_hash"));
|
||||||
|
|
||||||
|
e.setUpdatedAtMs(rs.getLong("updated_at_ms"));
|
||||||
|
|
||||||
for (int line = 0; line < 8; line++) {
|
for (int line = 0; line < 8; line++) {
|
||||||
e.setLastLineNumber(line, rs.getInt("line" + line + "_last_number"));
|
e.setLastLineNumber(line, rs.getInt("line" + line + "_last_number"));
|
||||||
e.setLastLineHash(line, rs.getString("line" + line + "_last_hash"));
|
e.setLastLineHash(line, rs.getString("line" + line + "_last_hash"));
|
||||||
}
|
}
|
||||||
|
|
||||||
e.setUpdatedAtMs(rs.getLong("updated_at_ms"));
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||||||
*
|
*
|
||||||
* Позволяет:
|
* Позволяет:
|
||||||
* - получить ConnectionContext по sessionId;
|
* - получить ConnectionContext по sessionId;
|
||||||
* - получить все активные подключения пользователя по loginId;
|
* - получить все активные подключения пользователя по login;
|
||||||
* - удалить подключение при закрытии WebSocket.
|
* - удалить подключение при закрытии WebSocket.
|
||||||
*
|
*
|
||||||
* найти все подключения пользователя:
|
* найти все подключения пользователя:
|
||||||
@ -34,27 +34,27 @@ public final class ActiveConnectionsRegistry {
|
|||||||
// sessionId (String) -> ConnectionContext
|
// sessionId (String) -> ConnectionContext
|
||||||
private final ConcurrentHashMap<String, ConnectionContext> bySessionId = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, ConnectionContext> bySessionId = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
// loginId -> множество ConnectionContext для этого пользователя
|
// login (String) -> множество ConnectionContext для этого пользователя
|
||||||
private final ConcurrentHashMap<Long, Set<ConnectionContext>> byLoginId = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, Set<ConnectionContext>> byLogin = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Зарегистрировать авторизованное подключение.
|
* Зарегистрировать авторизованное подключение.
|
||||||
* Ожидается, что в ctx уже выставлены loginId и sessionId.
|
* Ожидается, что в ctx уже выставлены login и sessionId.
|
||||||
*/
|
*/
|
||||||
public void register(ConnectionContext ctx) {
|
public void register(ConnectionContext ctx) {
|
||||||
if (ctx == null) return;
|
if (ctx == null) return;
|
||||||
|
|
||||||
String sessionId = ctx.getSessionId();
|
String sessionId = ctx.getSessionId();
|
||||||
Long loginId = ctx.getLoginId();
|
String login = ctx.getLogin();
|
||||||
|
|
||||||
if (sessionId == null || loginId == null) {
|
if (sessionId == null || login == null || login.isBlank()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bySessionId.put(sessionId, ctx);
|
bySessionId.put(sessionId, ctx);
|
||||||
|
|
||||||
byLoginId
|
byLogin
|
||||||
.computeIfAbsent(loginId, id -> new CopyOnWriteArraySet<>())
|
.computeIfAbsent(login, id -> new CopyOnWriteArraySet<>())
|
||||||
.add(ctx);
|
.add(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,18 +65,18 @@ public final class ActiveConnectionsRegistry {
|
|||||||
if (ctx == null) return;
|
if (ctx == null) return;
|
||||||
|
|
||||||
String sessionId = ctx.getSessionId();
|
String sessionId = ctx.getSessionId();
|
||||||
Long loginId = ctx.getLoginId();
|
String login = ctx.getLogin();
|
||||||
|
|
||||||
if (sessionId != null) {
|
if (sessionId != null) {
|
||||||
bySessionId.remove(sessionId);
|
bySessionId.remove(sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loginId != null) {
|
if (login != null) {
|
||||||
Set<ConnectionContext> set = byLoginId.get(loginId);
|
Set<ConnectionContext> set = byLogin.get(login);
|
||||||
if (set != null) {
|
if (set != null) {
|
||||||
set.remove(ctx);
|
set.remove(ctx);
|
||||||
if (set.isEmpty()) {
|
if (set.isEmpty()) {
|
||||||
byLoginId.remove(loginId);
|
byLogin.remove(login);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,13 +90,13 @@ public final class ActiveConnectionsRegistry {
|
|||||||
|
|
||||||
ConnectionContext ctx = bySessionId.remove(sessionId);
|
ConnectionContext ctx = bySessionId.remove(sessionId);
|
||||||
if (ctx != null) {
|
if (ctx != null) {
|
||||||
Long loginId = ctx.getLoginId();
|
String login = ctx.getLogin();
|
||||||
if (loginId != null) {
|
if (login != null) {
|
||||||
Set<ConnectionContext> set = byLoginId.get(loginId);
|
Set<ConnectionContext> set = byLogin.get(login);
|
||||||
if (set != null) {
|
if (set != null) {
|
||||||
set.remove(ctx);
|
set.remove(ctx);
|
||||||
if (set.isEmpty()) {
|
if (set.isEmpty()) {
|
||||||
byLoginId.remove(loginId);
|
byLogin.remove(login);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,10 +112,11 @@ public final class ActiveConnectionsRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получить все активные подключения пользователя по loginId.
|
* Получить все активные подключения пользователя по login.
|
||||||
*/
|
*/
|
||||||
public Set<ConnectionContext> getByLoginId(long loginId) {
|
public Set<ConnectionContext> getByLogin(String login) {
|
||||||
Set<ConnectionContext> set = byLoginId.get(loginId);
|
if (login == null) return Set.of();
|
||||||
|
Set<ConnectionContext> set = byLogin.get(login);
|
||||||
if (set == null) {
|
if (set == null) {
|
||||||
return Set.of();
|
return Set.of();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -77,16 +77,12 @@ public class ConnectionContext {
|
|||||||
this.activeSessionEntry = activeSessionEntry;
|
this.activeSessionEntry = activeSessionEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Удобные геттеры для логина ---
|
// --- Удобный геттер для логина ---
|
||||||
|
|
||||||
public String getLogin() {
|
public String getLogin() {
|
||||||
return solanaUserEntry != null ? solanaUserEntry.getLogin() : null;
|
return solanaUserEntry != null ? solanaUserEntry.getLogin() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getLoginId() {
|
|
||||||
return solanaUserEntry != null ? solanaUserEntry.getLoginId() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- sessionId / sessionPwd ---
|
// --- sessionId / sessionPwd ---
|
||||||
|
|
||||||
public String getSessionId() {
|
public String getSessionId() {
|
||||||
@ -149,7 +145,6 @@ public class ConnectionContext {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "ConnectionContext{" +
|
return "ConnectionContext{" +
|
||||||
"login='" + getLogin() + '\'' +
|
"login='" + getLogin() + '\'' +
|
||||||
", loginId=" + getLoginId() +
|
|
||||||
", sessionId=" + sessionId +
|
", sessionId=" + sessionId +
|
||||||
", authenticationStatus=" + authenticationStatus +
|
", authenticationStatus=" + authenticationStatus +
|
||||||
'}';
|
'}';
|
||||||
|
|||||||
@ -4,17 +4,17 @@ import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
|||||||
|
|
||||||
public final class Net_AddBlock_Request extends Net_Request {
|
public final class Net_AddBlock_Request extends Net_Request {
|
||||||
|
|
||||||
private String login; // обязателен
|
private String login; // обязателен
|
||||||
private long blockchainId; // обязателен
|
private String blockchainName; // обязателен
|
||||||
private int globalNumber; // обязателен
|
private int globalNumber; // обязателен
|
||||||
private String prevGlobalHash; // HEX(64) или "" для нулевого
|
private String prevGlobalHash; // HEX(64) или "" для нулевого
|
||||||
private String blockBytesB64; // байты FULL-блока (raw+sig+hash) в Base64
|
private String blockBytesB64; // байты FULL-блока (raw+sig+hash) в Base64
|
||||||
|
|
||||||
public String getLogin() { return login; }
|
public String getLogin() { return login; }
|
||||||
public void setLogin(String login) { this.login = login; }
|
public void setLogin(String login) { this.login = login; }
|
||||||
|
|
||||||
public long getBlockchainId() { return blockchainId; }
|
public String getBlockchainName() { return blockchainName; }
|
||||||
public void setBlockchainId(long blockchainId) { this.blockchainId = blockchainId; }
|
public void setBlockchainName(String blockchainName) { this.blockchainName = blockchainName; }
|
||||||
|
|
||||||
public int getGlobalNumber() { return globalNumber; }
|
public int getGlobalNumber() { return globalNumber; }
|
||||||
public void setGlobalNumber(int globalNumber) { this.globalNumber = globalNumber; }
|
public void setGlobalNumber(int globalNumber) { this.globalNumber = globalNumber; }
|
||||||
|
|||||||
@ -12,8 +12,7 @@ import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
|||||||
* "requestId": "test-add-1",
|
* "requestId": "test-add-1",
|
||||||
* "payload": {
|
* "payload": {
|
||||||
* "login": "anya",
|
* "login": "anya",
|
||||||
* "loginId": 100211,
|
* "blockchainName": "anya0001",
|
||||||
* "bchId": 4222,
|
|
||||||
* "loginKey": "base64-ed25519-public-key-login",
|
* "loginKey": "base64-ed25519-public-key-login",
|
||||||
* "deviceKey": "base64-ed25519-public-key-device",
|
* "deviceKey": "base64-ed25519-public-key-device",
|
||||||
* "bchLimit": 1000000
|
* "bchLimit": 1000000
|
||||||
@ -25,57 +24,23 @@ import server.logic.ws_protocol.JSON.entyties.Net_Request;
|
|||||||
public class Net_AddUser_Request extends Net_Request {
|
public class Net_AddUser_Request extends Net_Request {
|
||||||
|
|
||||||
private String login;
|
private String login;
|
||||||
private long loginId;
|
private String blockchainName;
|
||||||
private long bchId;
|
|
||||||
private String loginKey;
|
private String loginKey;
|
||||||
private String deviceKey;
|
private String deviceKey;
|
||||||
private Integer bchLimit;
|
private Integer bchLimit;
|
||||||
|
|
||||||
public String getLogin() {
|
public String getLogin() { return login; }
|
||||||
return login;
|
public void setLogin(String login) { this.login = login; }
|
||||||
}
|
|
||||||
|
|
||||||
public void setLogin(String login) {
|
public String getBlockchainName() { return blockchainName; }
|
||||||
this.login = login;
|
public void setBlockchainName(String blockchainName) { this.blockchainName = blockchainName; }
|
||||||
}
|
|
||||||
|
|
||||||
public long getLoginId() {
|
public String getLoginKey() { return loginKey; }
|
||||||
return loginId;
|
public void setLoginKey(String loginKey) { this.loginKey = loginKey; }
|
||||||
}
|
|
||||||
|
|
||||||
public void setLoginId(long loginId) {
|
public String getDeviceKey() { return deviceKey; }
|
||||||
this.loginId = loginId;
|
public void setDeviceKey(String deviceKey) { this.deviceKey = deviceKey; }
|
||||||
}
|
|
||||||
|
|
||||||
public long getBchId() {
|
public Integer getBchLimit() { return bchLimit; }
|
||||||
return bchId;
|
public void setBchLimit(Integer bchLimit) { this.bchLimit = bchLimit; }
|
||||||
}
|
|
||||||
|
|
||||||
public void setBchId(long bchId) {
|
|
||||||
this.bchId = bchId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLoginKey() {
|
|
||||||
return loginKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLoginKey(String loginKey) {
|
|
||||||
this.loginKey = loginKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDeviceKey() {
|
|
||||||
return deviceKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDeviceKey(String deviceKey) {
|
|
||||||
this.deviceKey = deviceKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getBchLimit() {
|
|
||||||
return bchLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBchLimit(Integer bchLimit) {
|
|
||||||
this.bchLimit = bchLimit;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ public class Net_CloseActiveSession_Handler implements JsonMessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SolanaUserEntry user = ctx.getSolanaUser();
|
SolanaUserEntry user = ctx.getSolanaUser();
|
||||||
long currentLoginId = user.getLoginId();
|
String currentLogin = user.getLogin();
|
||||||
|
|
||||||
int authStatus = ctx.getAuthenticationStatus();
|
int authStatus = ctx.getAuthenticationStatus();
|
||||||
if (authStatus != ConnectionContext.AUTH_STATUS_USER
|
if (authStatus != ConnectionContext.AUTH_STATUS_USER
|
||||||
@ -180,7 +180,7 @@ public class Net_CloseActiveSession_Handler implements JsonMessageHandler {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetSession.getLoginId() != currentLoginId) {
|
if (currentLogin == null || !currentLogin.equals(targetSession.getLogin())) {
|
||||||
return NetExceptionResponseFactory.error(
|
return NetExceptionResponseFactory.error(
|
||||||
req,
|
req,
|
||||||
WireCodes.Status.UNVERIFIED,
|
WireCodes.Status.UNVERIFIED,
|
||||||
@ -236,10 +236,7 @@ public class Net_CloseActiveSession_Handler implements JsonMessageHandler {
|
|||||||
if (isCurrentSession && ctxToClose == currentCtx) {
|
if (isCurrentSession && ctxToClose == currentCtx) {
|
||||||
// Это текущее подключение: закрываем после отправки ответа.
|
// Это текущее подключение: закрываем после отправки ответа.
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try { Thread.sleep(50); } catch (InterruptedException ignored) {}
|
||||||
Thread.sleep(50); // небольшая пауза, чтобы ответ ушёл
|
|
||||||
} catch (InterruptedException ignored) {
|
|
||||||
}
|
|
||||||
WsConnectionUtils.closeConnection(
|
WsConnectionUtils.closeConnection(
|
||||||
ctxToClose,
|
ctxToClose,
|
||||||
4000,
|
4000,
|
||||||
|
|||||||
@ -25,52 +25,14 @@ import java.sql.SQLException;
|
|||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
/**
|
|
||||||
* Шаг 2 авторизации: проверка подписи и создание сессии.
|
|
||||||
*
|
|
||||||
* Клиент присылает в payload:
|
|
||||||
* - storagePwd (base64 от 32 байт)
|
|
||||||
* - timeMs (long, мс с 1970-01-01)
|
|
||||||
* - signatureB64 (подпись Ed25519 над строкой:
|
|
||||||
* "AUTHORIFICATED:" + timeMs + authNonce)
|
|
||||||
* - clientInfo (опционально, до 50 символов)
|
|
||||||
*
|
|
||||||
* authNonce клиент получил на шаге 1 (AuthChallenge) и сервер
|
|
||||||
* сохранил его в ctx.authNonce.
|
|
||||||
*
|
|
||||||
* При успехе:
|
|
||||||
* - создаётся запись ActiveSession в БД;
|
|
||||||
* - генерируется sessionId (base64 от 32 случайных байт);
|
|
||||||
* - генерируется sessionPwd (base64 от 32 случайных байт);
|
|
||||||
* - sessionCreatedAtMs и lastAuthirificatedAtMs = текущее время;
|
|
||||||
* - заполняются поля clientIp, clientInfoFromClient, clientInfoFromRequest, userLanguage;
|
|
||||||
* - возвращается sessionId и sessionPwd в ответе.
|
|
||||||
*
|
|
||||||
* При ошибке авторификации (битые данные, подпись, время и т.п.) —
|
|
||||||
* соединение закрывается через WsConnectionUtils.
|
|
||||||
*/
|
|
||||||
public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(Net_CreateAuthSession__Handler.class);
|
private static final Logger log = LoggerFactory.getLogger(Net_CreateAuthSession__Handler.class);
|
||||||
|
|
||||||
private static final SecureRandom RANDOM = new SecureRandom();
|
private static final SecureRandom RANDOM = new SecureRandom();
|
||||||
|
|
||||||
/** Допустимое расхождение времени клиента и сервера (мс). */
|
|
||||||
public static final long ALLOWED_SKEW_MS = 30_000L;
|
public static final long ALLOWED_SKEW_MS = 30_000L;
|
||||||
|
|
||||||
/**
|
|
||||||
* Общая проверка подписи Ed25519 над строкой:
|
|
||||||
* "AUTHORIFICATED:" + timeMs + authNonce.
|
|
||||||
*
|
|
||||||
* Используется и в CreateAuthSession, и в CloseActiveSession (для статуса AUTH_IN_PROGRESS).
|
|
||||||
*
|
|
||||||
* @param user пользователь (используется deviceKey)
|
|
||||||
* @param authNonce одноразовый nonce из шага 1
|
|
||||||
* @param timeMs время на стороне клиента
|
|
||||||
* @param signatureB64 подпись в base64
|
|
||||||
* @return true — подпись корректна; false — подпись не проходит верификацию
|
|
||||||
* @throws IllegalArgumentException при некорректном base64 ключа/подписи
|
|
||||||
*/
|
|
||||||
public static boolean verifyAuthorificatedSignature(
|
public static boolean verifyAuthorificatedSignature(
|
||||||
SolanaUserEntry user,
|
SolanaUserEntry user,
|
||||||
String authNonce,
|
String authNonce,
|
||||||
@ -92,7 +54,6 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
|||||||
public Net_Response handle(Net_Request baseReq, ConnectionContext ctx) throws Exception {
|
public Net_Response handle(Net_Request baseReq, ConnectionContext ctx) throws Exception {
|
||||||
Net_CreateAuthSession_Request req = (Net_CreateAuthSession_Request) baseReq;
|
Net_CreateAuthSession_Request req = (Net_CreateAuthSession_Request) baseReq;
|
||||||
|
|
||||||
// --- базовые проверки контекста шага 1 ---
|
|
||||||
if (ctx == null
|
if (ctx == null
|
||||||
|| ctx.getSolanaUser() == null
|
|| ctx.getSolanaUser() == null
|
||||||
|| ctx.getAuthNonce() == null
|
|| ctx.getAuthNonce() == null
|
||||||
@ -109,15 +70,15 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SolanaUserEntry user = ctx.getSolanaUser();
|
SolanaUserEntry user = ctx.getSolanaUser();
|
||||||
Long loginId = user.getLoginId();
|
String login = user.getLogin();
|
||||||
if (loginId == null) {
|
if (login == null || login.isBlank()) {
|
||||||
Net_Response err = NetExceptionResponseFactory.error(
|
Net_Response err = NetExceptionResponseFactory.error(
|
||||||
req,
|
req,
|
||||||
WireCodes.Status.SERVER_DATA_ERROR,
|
WireCodes.Status.SERVER_DATA_ERROR,
|
||||||
"NO_LOGIN_ID",
|
"NO_LOGIN",
|
||||||
"Для пользователя не задан loginId в БД"
|
"Для пользователя не задан login в БД"
|
||||||
);
|
);
|
||||||
WsConnectionUtils.closeConnection(ctx, 4001, "Auth failed: no loginId");
|
WsConnectionUtils.closeConnection(ctx, 4001, "Auth failed: no login");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,13 +121,11 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Короткая строка clientInfo от клиента (до 50 символов)
|
|
||||||
String clientInfoFromClient = req.getClientInfo();
|
String clientInfoFromClient = req.getClientInfo();
|
||||||
if (clientInfoFromClient != null && clientInfoFromClient.length() > 50) {
|
if (clientInfoFromClient != null && clientInfoFromClient.length() > 50) {
|
||||||
clientInfoFromClient = clientInfoFromClient.substring(0, 50);
|
clientInfoFromClient = clientInfoFromClient.substring(0, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- выбираем публичный ключ pubkey1 ---
|
|
||||||
String pubKeyB64 = user.getDeviceKey();
|
String pubKeyB64 = user.getDeviceKey();
|
||||||
if (pubKeyB64 == null || pubKeyB64.isBlank()) {
|
if (pubKeyB64 == null || pubKeyB64.isBlank()) {
|
||||||
Net_Response err = NetExceptionResponseFactory.error(
|
Net_Response err = NetExceptionResponseFactory.error(
|
||||||
@ -179,10 +138,8 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- authNonce (challenge) мы сохранили в ctx.authNonce на шаге 1 ---
|
|
||||||
String authNonce = ctx.getAuthNonce();
|
String authNonce = ctx.getAuthNonce();
|
||||||
|
|
||||||
// --- проверяем подпись через общий метод ---
|
|
||||||
boolean sigOk;
|
boolean sigOk;
|
||||||
try {
|
try {
|
||||||
sigOk = verifyAuthorificatedSignature(user, authNonce, timeMs, signatureB64);
|
sigOk = verifyAuthorificatedSignature(user, authNonce, timeMs, signatureB64);
|
||||||
@ -230,10 +187,7 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (clientIp == null) clientIp = "";
|
||||||
if (clientIp == null) {
|
|
||||||
clientIp = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- создаём запись ActiveSession и сохраняем в БД ---
|
// --- создаём запись ActiveSession и сохраняем в БД ---
|
||||||
ActiveSessionsDAO dao = ActiveSessionsDAO.getInstance();
|
ActiveSessionsDAO dao = ActiveSessionsDAO.getInstance();
|
||||||
@ -242,8 +196,8 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
|||||||
try {
|
try {
|
||||||
activeSessionEntry = new ActiveSessionEntry(
|
activeSessionEntry = new ActiveSessionEntry(
|
||||||
sessionId,
|
sessionId,
|
||||||
loginId,
|
login,
|
||||||
newSessionPwd, // настоящий секрет сессии
|
newSessionPwd,
|
||||||
storagePwd,
|
storagePwd,
|
||||||
now,
|
now,
|
||||||
now,
|
now,
|
||||||
@ -258,7 +212,7 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
|||||||
|
|
||||||
dao.insert(activeSessionEntry);
|
dao.insert(activeSessionEntry);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
log.error("Ошибка БД при создании новой сессии для loginId={}", loginId, e);
|
log.error("Ошибка БД при создании новой сессии для login={}", login, e);
|
||||||
Net_Response err = NetExceptionResponseFactory.error(
|
Net_Response err = NetExceptionResponseFactory.error(
|
||||||
req,
|
req,
|
||||||
WireCodes.Status.SERVER_DATA_ERROR,
|
WireCodes.Status.SERVER_DATA_ERROR,
|
||||||
|
|||||||
@ -51,7 +51,7 @@ public class Net_ListSessions_Handler implements JsonMessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SolanaUserEntry user = ctx.getSolanaUser();
|
SolanaUserEntry user = ctx.getSolanaUser();
|
||||||
long currentLoginId = user.getLoginId();
|
String currentLogin = user.getLogin();
|
||||||
|
|
||||||
int authStatus = ctx.getAuthenticationStatus();
|
int authStatus = ctx.getAuthenticationStatus();
|
||||||
if (authStatus != ConnectionContext.AUTH_STATUS_USER
|
if (authStatus != ConnectionContext.AUTH_STATUS_USER
|
||||||
@ -130,9 +130,9 @@ public class Net_ListSessions_Handler implements JsonMessageHandler {
|
|||||||
// 3) Тянем все активные сессии пользователя из БД
|
// 3) Тянем все активные сессии пользователя из БД
|
||||||
List<ActiveSessionEntry> sessions;
|
List<ActiveSessionEntry> sessions;
|
||||||
try {
|
try {
|
||||||
sessions = ActiveSessionsDAO.getInstance().getByLoginId(currentLoginId);
|
sessions = ActiveSessionsDAO.getInstance().getByLogin(currentLogin);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
log.error("Ошибка БД при получении списка сессий для loginId={}", currentLoginId, e);
|
log.error("Ошибка БД при получении списка сессий для login={}", currentLogin, e);
|
||||||
return NetExceptionResponseFactory.error(
|
return NetExceptionResponseFactory.error(
|
||||||
req,
|
req,
|
||||||
WireCodes.Status.SERVER_DATA_ERROR,
|
WireCodes.Status.SERVER_DATA_ERROR,
|
||||||
|
|||||||
@ -95,14 +95,15 @@ public class Net_RefreshSession_Handler implements JsonMessageHandler {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- вытаскиваем пользователя по loginId ---
|
// --- вытаскиваем пользователя по login из сессии ---
|
||||||
SolanaUserEntry solanaUserEntry = null;
|
SolanaUserEntry solanaUserEntry;
|
||||||
long loginId = session.getLoginId();
|
String login = session.getLogin();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SolanaUsersDAO usersDao = SolanaUsersDAO.getInstance();
|
SolanaUsersDAO usersDao = SolanaUsersDAO.getInstance();
|
||||||
solanaUserEntry = usersDao.getByLoginId(loginId);
|
solanaUserEntry = usersDao.getByLogin(login);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
log.error("Ошибка БД при поиске пользователя по loginId={} из сессии", loginId, e);
|
log.error("Ошибка БД при поиске пользователя по login={} из сессии", login, e);
|
||||||
return NetExceptionResponseFactory.error(
|
return NetExceptionResponseFactory.error(
|
||||||
req,
|
req,
|
||||||
WireCodes.Status.SERVER_DATA_ERROR,
|
WireCodes.Status.SERVER_DATA_ERROR,
|
||||||
|
|||||||
@ -4,11 +4,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
public final class BlockchainLocks {
|
public final class BlockchainLocks {
|
||||||
private static final ConcurrentHashMap<Long, ReentrantLock> MAP = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<String, ReentrantLock> MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private BlockchainLocks() {}
|
private BlockchainLocks() {}
|
||||||
|
|
||||||
public static ReentrantLock lockFor(long blockchainId) {
|
public static ReentrantLock lockFor(String blockchainName) {
|
||||||
return MAP.computeIfAbsent(blockchainId, id -> new ReentrantLock(true)); // fair=true
|
return MAP.computeIfAbsent(blockchainName, id -> new ReentrantLock(true)); // fair=true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -11,7 +11,6 @@ import shine.db.entities.SolanaUserEntry;
|
|||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Types;
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,9 +27,9 @@ public final class BlockchainStateService_new {
|
|||||||
|
|
||||||
/** Результат атомарного addBlock */
|
/** Результат атомарного addBlock */
|
||||||
public static final class AddBlockResult {
|
public static final class AddBlockResult {
|
||||||
public final int lineIndex; // 0..7 (пока ставим 0)
|
public final int lineIndex; // 0..7 (пока ставим 0)
|
||||||
public final int httpStatus; // WireCodes.Status.*
|
public final int httpStatus; // WireCodes.Status.*
|
||||||
public final String reasonCode; // null если ok
|
public final String reasonCode; // null если ok
|
||||||
public final BlockchainStateEntry stateAfter; // состояние после (может быть null)
|
public final BlockchainStateEntry stateAfter; // состояние после (может быть null)
|
||||||
|
|
||||||
public AddBlockResult(int lineIndex, int httpStatus, String reasonCode, BlockchainStateEntry stateAfter) {
|
public AddBlockResult(int lineIndex, int httpStatus, String reasonCode, BlockchainStateEntry stateAfter) {
|
||||||
@ -69,7 +68,7 @@ public final class BlockchainStateService_new {
|
|||||||
*/
|
*/
|
||||||
public AddBlockResult addBlockAtomically(
|
public AddBlockResult addBlockAtomically(
|
||||||
String login,
|
String login,
|
||||||
long blockchainId,
|
String blockchainName,
|
||||||
int globalNumber,
|
int globalNumber,
|
||||||
String prevGlobalHash,
|
String prevGlobalHash,
|
||||||
String blockBytesB64
|
String blockBytesB64
|
||||||
@ -91,11 +90,21 @@ public final class BlockchainStateService_new {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (login == null || login.isBlank()) {
|
||||||
|
return new AddBlockResult(lineIndex, WireCodes.Status.BAD_REQUEST, "empty_login", null);
|
||||||
|
}
|
||||||
|
if (blockchainName == null || blockchainName.isBlank()) {
|
||||||
|
return new AddBlockResult(lineIndex, WireCodes.Status.BAD_REQUEST, "empty_blockchain_name", null);
|
||||||
|
}
|
||||||
|
if (blockBytes == null || blockBytes.length == 0) {
|
||||||
|
return new AddBlockResult(lineIndex, WireCodes.Status.BAD_REQUEST, "empty_block_bytes", null);
|
||||||
|
}
|
||||||
|
|
||||||
try (Connection c = db.getConnection()) {
|
try (Connection c = db.getConnection()) {
|
||||||
boolean oldAutoCommit = c.getAutoCommit();
|
boolean oldAutoCommit = c.getAutoCommit();
|
||||||
c.setAutoCommit(false);
|
c.setAutoCommit(false);
|
||||||
try {
|
try {
|
||||||
// 1) получаем loginId по login
|
// 1) получаем пользователя по login (если надо валидировать существование)
|
||||||
SolanaUserEntry u = solanaUsersDAO.getByLogin(c, login);
|
SolanaUserEntry u = solanaUsersDAO.getByLogin(c, login);
|
||||||
if (u == null) {
|
if (u == null) {
|
||||||
c.rollback();
|
c.rollback();
|
||||||
@ -106,13 +115,12 @@ public final class BlockchainStateService_new {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
long loginId = u.getLoginId();
|
|
||||||
|
|
||||||
// 2) вставляем блок в blocks
|
// 2) вставляем блок в blocks
|
||||||
insertBlockRow(c, loginId, blockchainId, globalNumber, prevGlobalHash, blockBytes, lineIndex);
|
insertBlockRow(c, login, blockchainName, globalNumber, prevGlobalHash, blockBytes, lineIndex);
|
||||||
|
|
||||||
// 3) обновляем агрегатное состояние blockchain_state
|
// 3) обновляем агрегатное состояние blockchain_state (по blockchainName)
|
||||||
BlockchainStateEntry st = stateDAO.getByBlockchainId(c, blockchainId);
|
BlockchainStateEntry st = stateDAO.getByBlockchainName(c, blockchainName);
|
||||||
if (st == null) {
|
if (st == null) {
|
||||||
c.rollback();
|
c.rollback();
|
||||||
return new AddBlockResult(
|
return new AddBlockResult(
|
||||||
@ -124,7 +132,6 @@ public final class BlockchainStateService_new {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MVP: обновляем “последний глобальный номер”.
|
// MVP: обновляем “последний глобальный номер”.
|
||||||
// Хэш тут сейчас оставлен как заглушка — лучше поставить фактический хэш нового блока.
|
|
||||||
st.setLastGlobalNumber(globalNumber);
|
st.setLastGlobalNumber(globalNumber);
|
||||||
st.setLastGlobalHash(nn(prevGlobalHash)); // TODO: заменить на hash нового блока
|
st.setLastGlobalHash(nn(prevGlobalHash)); // TODO: заменить на hash нового блока
|
||||||
st.setUpdatedAtMs(System.currentTimeMillis());
|
st.setUpdatedAtMs(System.currentTimeMillis());
|
||||||
@ -158,8 +165,8 @@ public final class BlockchainStateService_new {
|
|||||||
|
|
||||||
private void insertBlockRow(
|
private void insertBlockRow(
|
||||||
Connection c,
|
Connection c,
|
||||||
long loginId,
|
String login,
|
||||||
long blockchainId,
|
String blockchainName,
|
||||||
int globalNumber,
|
int globalNumber,
|
||||||
String prevGlobalHash,
|
String prevGlobalHash,
|
||||||
byte[] blockBytes,
|
byte[] blockBytes,
|
||||||
@ -167,8 +174,9 @@ public final class BlockchainStateService_new {
|
|||||||
) throws SQLException {
|
) throws SQLException {
|
||||||
|
|
||||||
BlockEntry e = new BlockEntry();
|
BlockEntry e = new BlockEntry();
|
||||||
e.setLoginId(loginId);
|
|
||||||
e.setBlockchainId(blockchainId);
|
e.setLogin(login);
|
||||||
|
e.setBchName(blockchainName);
|
||||||
|
|
||||||
e.setBlockGlobalNumber(globalNumber);
|
e.setBlockGlobalNumber(globalNumber);
|
||||||
e.setBlockGlobalPreHashe(nn(prevGlobalHash));
|
e.setBlockGlobalPreHashe(nn(prevGlobalHash));
|
||||||
@ -182,10 +190,11 @@ public final class BlockchainStateService_new {
|
|||||||
|
|
||||||
e.setBlockByte(blockBytes);
|
e.setBlockByte(blockBytes);
|
||||||
|
|
||||||
e.setToLoginId(0);
|
// NEW: nullable ссылки (не забиваем фейковыми нулями)
|
||||||
e.setToBlockchainId(0);
|
e.setToLogin(null);
|
||||||
e.setToBlockGlobalNumber(0);
|
e.setToBchName(null);
|
||||||
e.setToBlockHashe("");
|
e.setToBlockGlobalNumber(null);
|
||||||
|
e.setToBlockHashe(null);
|
||||||
|
|
||||||
blocksDAO.upsert(c, e);
|
blocksDAO.upsert(c, e);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ public final class Net_AddBlock_new_Handler implements JsonMessageHandler {
|
|||||||
|
|
||||||
var r = BlockchainStateService_new.getInstance().addBlockAtomically(
|
var r = BlockchainStateService_new.getInstance().addBlockAtomically(
|
||||||
req.getLogin(),
|
req.getLogin(),
|
||||||
req.getBlockchainId(),
|
req.getBlockchainName(),
|
||||||
req.getGlobalNumber(),
|
req.getGlobalNumber(),
|
||||||
req.getPrevGlobalHash(),
|
req.getPrevGlobalHash(),
|
||||||
req.getBlockBytesB64()
|
req.getBlockBytesB64()
|
||||||
|
|||||||
@ -27,16 +27,15 @@ public class Net_AddUser_Handler implements JsonMessageHandler {
|
|||||||
Net_AddUser_Request req = (Net_AddUser_Request) baseRequest;
|
Net_AddUser_Request req = (Net_AddUser_Request) baseRequest;
|
||||||
|
|
||||||
if (req.getLogin() == null || req.getLogin().isBlank()
|
if (req.getLogin() == null || req.getLogin().isBlank()
|
||||||
|
|| req.getBlockchainName() == null || req.getBlockchainName().isBlank()
|
||||||
|| req.getLoginKey() == null || req.getLoginKey().isBlank()
|
|| req.getLoginKey() == null || req.getLoginKey().isBlank()
|
||||||
|| req.getDeviceKey() == null || req.getDeviceKey().isBlank()
|
|| req.getDeviceKey() == null || req.getDeviceKey().isBlank()) {
|
||||||
|| req.getLoginId() <= 0
|
|
||||||
|| req.getBchId() <= 0) {
|
|
||||||
|
|
||||||
return NetExceptionResponseFactory.error(
|
return NetExceptionResponseFactory.error(
|
||||||
req,
|
req,
|
||||||
WireCodes.Status.BAD_REQUEST,
|
WireCodes.Status.BAD_REQUEST,
|
||||||
"BAD_FIELDS",
|
"BAD_FIELDS",
|
||||||
"Некорректные поля: login/loginId/bchId/loginKey/deviceKey"
|
"Некорректные поля: login/blockchainName/loginKey/deviceKey"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,9 +46,8 @@ public class Net_AddUser_Handler implements JsonMessageHandler {
|
|||||||
SolanaUsersDAO dao = SolanaUsersDAO.getInstance();
|
SolanaUsersDAO dao = SolanaUsersDAO.getInstance();
|
||||||
|
|
||||||
SolanaUserEntry user = new SolanaUserEntry(
|
SolanaUserEntry user = new SolanaUserEntry(
|
||||||
req.getLoginId(),
|
|
||||||
req.getLogin(),
|
req.getLogin(),
|
||||||
req.getBchId(),
|
req.getBlockchainName(),
|
||||||
req.getLoginKey(),
|
req.getLoginKey(),
|
||||||
req.getDeviceKey(),
|
req.getDeviceKey(),
|
||||||
limit
|
limit
|
||||||
@ -62,8 +60,8 @@ public class Net_AddUser_Handler implements JsonMessageHandler {
|
|||||||
resp.setRequestId(req.getRequestId());
|
resp.setRequestId(req.getRequestId());
|
||||||
resp.setStatus(WireCodes.Status.OK);
|
resp.setStatus(WireCodes.Status.OK);
|
||||||
|
|
||||||
log.info("✅ AddUser ok: login={}, loginId={}, bchId={}, limit={}",
|
log.info("✅ AddUser ok: login={}, blockchainName={}, limit={}",
|
||||||
req.getLogin(), req.getLoginId(), req.getBchId(), limit);
|
req.getLogin(), req.getBlockchainName(), limit);
|
||||||
|
|
||||||
return resp;
|
return resp;
|
||||||
|
|
||||||
|
|||||||
@ -24,7 +24,8 @@ public class Test_AddBlock_new_NoAuth {
|
|||||||
private static final ObjectMapper JSON = new ObjectMapper();
|
private static final ObjectMapper JSON = new ObjectMapper();
|
||||||
|
|
||||||
private static final String TEST_LOGIN = "anya24";
|
private static final String TEST_LOGIN = "anya24";
|
||||||
private static final long TEST_BCH_ID = 4222L;
|
// По твоему правилу: blockchainName = login + 4 цифры
|
||||||
|
private static final String TEST_BCH_NAME = TEST_LOGIN + "0001";
|
||||||
|
|
||||||
private static final byte[] LOGIN_PRIV_KEY;
|
private static final byte[] LOGIN_PRIV_KEY;
|
||||||
private static final byte[] LOGIN_PUB_KEY;
|
private static final byte[] LOGIN_PUB_KEY;
|
||||||
@ -66,7 +67,7 @@ public class Test_AddBlock_new_NoAuth {
|
|||||||
|
|
||||||
String json = buildAddBlockJson(
|
String json = buildAddBlockJson(
|
||||||
"test-add-header",
|
"test-add-header",
|
||||||
TEST_BCH_ID,
|
TEST_BCH_NAME,
|
||||||
0,
|
0,
|
||||||
ZERO64, // prevGlobalHash для первого блока — нули
|
ZERO64, // prevGlobalHash для первого блока — нули
|
||||||
base64(headerFull)
|
base64(headerFull)
|
||||||
@ -124,7 +125,7 @@ public class Test_AddBlock_new_NoAuth {
|
|||||||
|
|
||||||
String json2 = buildAddBlockJson(
|
String json2 = buildAddBlockJson(
|
||||||
"test-add-text",
|
"test-add-text",
|
||||||
TEST_BCH_ID,
|
TEST_BCH_NAME,
|
||||||
1,
|
1,
|
||||||
lastGlobalHashHex, // prevGlobalHash = хэш header'а из ответа сервера
|
lastGlobalHashHex, // prevGlobalHash = хэш header'а из ответа сервера
|
||||||
base64(textFull)
|
base64(textFull)
|
||||||
@ -181,7 +182,7 @@ public class Test_AddBlock_new_NoAuth {
|
|||||||
byte[] prevLineHash32) {
|
byte[] prevLineHash32) {
|
||||||
|
|
||||||
HeaderBody body = new HeaderBody(
|
HeaderBody body = new HeaderBody(
|
||||||
TEST_BCH_ID,
|
TEST_BCH_NAME, // было TEST_BCH_ID (long), теперь имя блокчейна (String)
|
||||||
TEST_LOGIN,
|
TEST_LOGIN,
|
||||||
0, 0,
|
0, 0,
|
||||||
(short) 1,
|
(short) 1,
|
||||||
@ -259,17 +260,17 @@ public class Test_AddBlock_new_NoAuth {
|
|||||||
// =================================================================================
|
// =================================================================================
|
||||||
|
|
||||||
private static String buildAddBlockJson(String requestId,
|
private static String buildAddBlockJson(String requestId,
|
||||||
long blockchainId,
|
String blockchainName,
|
||||||
int globalNumber,
|
int globalNumber,
|
||||||
String prevGlobalHashHex,
|
String prevGlobalHashHex,
|
||||||
String blockBytesB64) {
|
String blockBytesB64) {
|
||||||
return """
|
return """
|
||||||
{
|
{
|
||||||
"op": "AddBlock",
|
"op": "AddBlock",
|
||||||
"requestId": "%s",
|
"requestId": "%s",
|
||||||
"payload": {
|
"payload": {
|
||||||
"login": "%s",
|
"login": "%s",
|
||||||
"blockchainId": %d,
|
"blockchainName": "%s",
|
||||||
"globalNumber": %d,
|
"globalNumber": %d,
|
||||||
"prevGlobalHash": "%s",
|
"prevGlobalHash": "%s",
|
||||||
"blockBytesB64": "%s"
|
"blockBytesB64": "%s"
|
||||||
|
|||||||
@ -57,8 +57,8 @@ public class Test_AddUser_and_Authorification {
|
|||||||
|
|
||||||
// Тестовые данные пользователя
|
// Тестовые данные пользователя
|
||||||
private static final String TEST_LOGIN = "anya24";
|
private static final String TEST_LOGIN = "anya24";
|
||||||
private static final long TEST_LOGIN_ID = 1030120L;
|
// По твоему правилу: blockchainName = login + 4 цифры
|
||||||
private static final long TEST_BCH_ID = 4222L;
|
private static final String TEST_BCH_NAME = TEST_LOGIN + "0001";
|
||||||
private static final int TEST_BCH_LIMIT = 1_000_000;
|
private static final int TEST_BCH_LIMIT = 1_000_000;
|
||||||
|
|
||||||
// Краткая строка clientInfo, которую клиент шлёт
|
// Краткая строка clientInfo, которую клиент шлёт
|
||||||
@ -399,13 +399,6 @@ public class Test_AddUser_and_Authorification {
|
|||||||
// SCENARIO 3 / 5 / 7: ListSessions
|
// SCENARIO 3 / 5 / 7: ListSessions
|
||||||
// ==========================================================
|
// ==========================================================
|
||||||
|
|
||||||
/**
|
|
||||||
* Общий сценарий: AuthChallenge → ListSessions в статусе AUTH_IN_PROGRESS.
|
|
||||||
*
|
|
||||||
* @param title заголовок для вывода
|
|
||||||
* @param expectSession1Present ожидать ли первую сессию в списке
|
|
||||||
* @param expectSession2Present ожидать ли вторую сессию в списке
|
|
||||||
*/
|
|
||||||
private static void scenario3_ListSessions_AuthInProgress(
|
private static void scenario3_ListSessions_AuthInProgress(
|
||||||
String title,
|
String title,
|
||||||
boolean expectSession1Present,
|
boolean expectSession1Present,
|
||||||
@ -476,8 +469,8 @@ public class Test_AddUser_and_Authorification {
|
|||||||
|
|
||||||
boolean ok =
|
boolean ok =
|
||||||
status == 200
|
status == 200
|
||||||
&& (expectSession1Present == has1)
|
&& (expectSession1Present == has1)
|
||||||
&& (expectSession2Present == has2);
|
&& (expectSession2Present == has2);
|
||||||
|
|
||||||
printTestResult(
|
printTestResult(
|
||||||
"S-List/ListSessions (ожидаемые сессии)",
|
"S-List/ListSessions (ожидаемые сессии)",
|
||||||
@ -767,8 +760,7 @@ public class Test_AddUser_and_Authorification {
|
|||||||
"requestId": "test-add-1",
|
"requestId": "test-add-1",
|
||||||
"payload": {
|
"payload": {
|
||||||
"login": "%s",
|
"login": "%s",
|
||||||
"loginId": %d,
|
"bchName": "%s",
|
||||||
"bchId": %d,
|
|
||||||
"loginKey": "%s",
|
"loginKey": "%s",
|
||||||
"deviceKey": "%s",
|
"deviceKey": "%s",
|
||||||
"bchLimit": %d
|
"bchLimit": %d
|
||||||
@ -776,8 +768,7 @@ public class Test_AddUser_and_Authorification {
|
|||||||
}
|
}
|
||||||
""".formatted(
|
""".formatted(
|
||||||
TEST_LOGIN,
|
TEST_LOGIN,
|
||||||
TEST_LOGIN_ID,
|
TEST_BCH_NAME,
|
||||||
TEST_BCH_ID,
|
|
||||||
LOGIN_PUBKEY_B64, // loginKey
|
LOGIN_PUBKEY_B64, // loginKey
|
||||||
DEVICE_PUBKEY_B64, // deviceKey
|
DEVICE_PUBKEY_B64, // deviceKey
|
||||||
TEST_BCH_LIMIT
|
TEST_BCH_LIMIT
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user