23 01 25
Ура прошли все тесты новой версии авторификации!! Осталось что то доделать поправить с лишними закрытиями сервака
This commit is contained in:
parent
4430615117
commit
43b0efb4d3
@ -35,7 +35,7 @@ import java.util.Base64;
|
|||||||
* - Сервер сохраняет sessionPubKeyB64 в active_sessions.session_key.
|
* - Сервер сохраняет sessionPubKeyB64 в active_sessions.session_key.
|
||||||
*
|
*
|
||||||
* Подпись deviceKey (Ed25519) проверяется над строкой (UTF-8):
|
* Подпись deviceKey (Ed25519) проверяется над строкой (UTF-8):
|
||||||
* AUTH_CREATE_SESSION:{login}:{timeMs}:{authNonce}:{sessionPubKeyB64}:{storagePwd}
|
* AUTH_CREATE_SESSION:{login}:{timeMs}:{authNonce}
|
||||||
*
|
*
|
||||||
* На выходе:
|
* На выходе:
|
||||||
* - создаётся запись active_sessions
|
* - создаётся запись active_sessions
|
||||||
@ -106,7 +106,7 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Проверим, что ключ декодируется в 32 байта
|
// Проверим, что sessionPubKeyB64 декодируется в 32 байта
|
||||||
byte[] sessionPubKey32;
|
byte[] sessionPubKey32;
|
||||||
try {
|
try {
|
||||||
sessionPubKey32 = decodeBase64Any(sessionPubKeyB64);
|
sessionPubKey32 = decodeBase64Any(sessionPubKeyB64);
|
||||||
@ -183,8 +183,6 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
|||||||
login,
|
login,
|
||||||
authNonce,
|
authNonce,
|
||||||
timeMs,
|
timeMs,
|
||||||
sessionPubKeyB64,
|
|
||||||
storagePwd,
|
|
||||||
signatureB64
|
signatureB64
|
||||||
);
|
);
|
||||||
} catch (IllegalArgumentException ex) {
|
} catch (IllegalArgumentException ex) {
|
||||||
@ -288,15 +286,14 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
|||||||
String login,
|
String login,
|
||||||
String authNonce,
|
String authNonce,
|
||||||
long timeMs,
|
long timeMs,
|
||||||
String sessionPubKeyB64,
|
|
||||||
String storagePwd,
|
|
||||||
String signatureB64
|
String signatureB64
|
||||||
) throws IllegalArgumentException {
|
) throws IllegalArgumentException {
|
||||||
|
|
||||||
|
// deviceKey (pub, 32)
|
||||||
byte[] publicKey32 = Ed25519Util.keyFromBase64(user.getDeviceKey());
|
byte[] publicKey32 = Ed25519Util.keyFromBase64(user.getDeviceKey());
|
||||||
byte[] signature64 = decodeBase64Any(signatureB64);
|
byte[] signature64 = decodeBase64Any(signatureB64);
|
||||||
|
|
||||||
String preimageStr = "AUTH_CREATE_SESSION:" + login + ":" + timeMs + ":" + authNonce + ":" + sessionPubKeyB64 + ":" + storagePwd;
|
String preimageStr = "AUTH_CREATE_SESSION:" + login + ":" + timeMs + ":" + authNonce;
|
||||||
byte[] preimage = preimageStr.getBytes(StandardCharsets.UTF_8);
|
byte[] preimage = preimageStr.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
return Ed25519Util.verify(preimage, signature64, publicKey32);
|
return Ed25519Util.verify(preimage, signature64, publicKey32);
|
||||||
@ -309,11 +306,15 @@ public class Net_CreateAuthSession__Handler implements JsonMessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] decodeBase64Any(String s) throws IllegalArgumentException {
|
private static byte[] decodeBase64Any(String s) throws IllegalArgumentException {
|
||||||
|
if (s == null) throw new IllegalArgumentException("base64 is null");
|
||||||
|
String x = s.trim();
|
||||||
|
if (x.isEmpty()) throw new IllegalArgumentException("base64 is empty");
|
||||||
|
|
||||||
// сначала url-safe, потом обычный
|
// сначала url-safe, потом обычный
|
||||||
try {
|
try {
|
||||||
return Base64.getUrlDecoder().decode(s);
|
return Base64.getUrlDecoder().decode(x);
|
||||||
} catch (IllegalArgumentException ignore) {
|
} catch (IllegalArgumentException ignore) {
|
||||||
return Base64.getDecoder().decode(s);
|
return Base64.getDecoder().decode(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
6
src/main/java/server/ws/TODO SERVER CODE UPDATE.txt
Normal file
6
src/main/java/server/ws/TODO SERVER CODE UPDATE.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
ура всё прошло.
|
||||||
|
|
||||||
|
Другой надеюсь крайний на сегодня вопрос .
|
||||||
|
|
||||||
|
|
||||||
|
Сформулируй Подробное туду с тем что переделать сервак что бы он не обрывал соединение сразу из за любой ошибки (а видимо только в каких то случах гд енадо ... но в каких :)
|
||||||
@ -15,8 +15,17 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class IT_RunAllMain {
|
public class IT_RunAllMain {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Настройка поведения прогона:
|
||||||
|
* - true : остановить запуск сразу после первого упавшего теста
|
||||||
|
* - false : прогнать все тесты до конца, даже если некоторые упали
|
||||||
|
*/
|
||||||
|
private static final boolean STOP_ON_FIRST_FAIL = true;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
int failed = runAll();
|
int failed = runAll();
|
||||||
|
// при желании можно вернуть код выхода ОС:
|
||||||
|
// System.exit(failed == 0 ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int runAll() {
|
public static int runAll() {
|
||||||
@ -24,13 +33,30 @@ public class IT_RunAllMain {
|
|||||||
List<String> summaries = new ArrayList<>();
|
List<String> summaries = new ArrayList<>();
|
||||||
int failed = 0;
|
int failed = 0;
|
||||||
|
|
||||||
TestLog.title("IT RUN: запуск всех тестов подряд");
|
TestLog.title("IT RUN: запуск всех тестов подряд"
|
||||||
|
+ (STOP_ON_FIRST_FAIL ? " (STOP_ON_FIRST_FAIL=ON)" : " (STOP_ON_FIRST_FAIL=OFF)"));
|
||||||
|
|
||||||
String s1 = IT_01_AddUser.run(); summaries.add(s1); if (s1.contains("FAIL:")) failed++;
|
String s1 = IT_01_AddUser.run(); summaries.add(s1);
|
||||||
String s2 = IT_02_Sessions.run(); summaries.add(s2); if (s2.contains("FAIL:")) failed++;
|
if (s1.contains("FAIL:")) { failed++; if (STOP_ON_FIRST_FAIL) return finishEarly(summaries, failed); }
|
||||||
String s3 = IT_03_AddBlock_NoAuth.run(); summaries.add(s3); if (s3.contains("FAIL:")) failed++;
|
|
||||||
String s4 = IT_04_UserParams_NoAuth.run(); summaries.add(s4); if (s4.contains("FAIL:")) failed++;
|
|
||||||
|
|
||||||
|
String s2 = IT_02_Sessions.run(); summaries.add(s2);
|
||||||
|
if (s2.contains("FAIL:")) { failed++; if (STOP_ON_FIRST_FAIL) return finishEarly(summaries, failed); }
|
||||||
|
|
||||||
|
String s3 = IT_03_AddBlock_NoAuth.run(); summaries.add(s3);
|
||||||
|
if (s3.contains("FAIL:")) { failed++; if (STOP_ON_FIRST_FAIL) return finishEarly(summaries, failed); }
|
||||||
|
|
||||||
|
String s4 = IT_04_UserParams_NoAuth.run(); summaries.add(s4);
|
||||||
|
if (s4.contains("FAIL:")) { failed++; if (STOP_ON_FIRST_FAIL) return finishEarly(summaries, failed); }
|
||||||
|
|
||||||
|
return finish(summaries, failed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int finishEarly(List<String> summaries, int failed) {
|
||||||
|
TestLog.boom("⛔ Остановка прогона: найден FAIL, STOP_ON_FIRST_FAIL=ON");
|
||||||
|
return finish(summaries, failed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int finish(List<String> summaries, int failed) {
|
||||||
TestLog.title("IT RUN RESULT (per test)");
|
TestLog.title("IT RUN RESULT (per test)");
|
||||||
for (String s : summaries) System.out.println(s);
|
for (String s : summaries) System.out.println(s);
|
||||||
|
|
||||||
|
|||||||
@ -9,13 +9,14 @@ 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/session)
|
||||||
* - blockchainName = login + "-" + "001"
|
* - blockchainName = login + "-" + "001"
|
||||||
*
|
*
|
||||||
* Важно:
|
* Важно:
|
||||||
* - privateKey = Ed25519Util.generatePrivateKeyFromString(login) (sha256, 32 bytes)
|
* - privateKey = Ed25519Util.generatePrivateKeyFromString(seed) (sha256(seed) => 32 bytes)
|
||||||
* - publicKey = Ed25519Util.derivePublicKey(privateKey)
|
* - publicKey = Ed25519Util.derivePublicKey(privateKey)
|
||||||
* - пока device/solana/blockchain ключи одинаковые (один seed на login)
|
* - device/solana/blockchain ключи пока одинаковые (seed = login)
|
||||||
|
* - session ключ отдельный (seed = "session:" + login) — чтобы SessionLogin был честнее.
|
||||||
*/
|
*/
|
||||||
public final class TestConfig {
|
public final class TestConfig {
|
||||||
|
|
||||||
@ -58,6 +59,10 @@ public final class TestConfig {
|
|||||||
private static final Map<String, byte[]> bchPriv = new ConcurrentHashMap<>();
|
private static final Map<String, byte[]> bchPriv = new ConcurrentHashMap<>();
|
||||||
private static final Map<String, byte[]> bchPub = new ConcurrentHashMap<>();
|
private static final Map<String, byte[]> bchPub = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// NEW: session keys (для SessionLogin v2)
|
||||||
|
private static final Map<String, byte[]> sessionPriv = new ConcurrentHashMap<>();
|
||||||
|
private static final Map<String, byte[]> sessionPub = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
initUserKeys(LOGIN());
|
initUserKeys(LOGIN());
|
||||||
initUserKeys(LOGIN2());
|
initUserKeys(LOGIN2());
|
||||||
@ -65,6 +70,7 @@ public final class TestConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void initUserKeys(String login) {
|
private static void initUserKeys(String login) {
|
||||||
|
// seed = login
|
||||||
byte[] priv = Ed25519Util.generatePrivateKeyFromString(login); // sha256(login) => 32 bytes
|
byte[] priv = Ed25519Util.generatePrivateKeyFromString(login); // sha256(login) => 32 bytes
|
||||||
byte[] pub = Ed25519Util.derivePublicKey(priv);
|
byte[] pub = Ed25519Util.derivePublicKey(priv);
|
||||||
|
|
||||||
@ -77,6 +83,13 @@ public final class TestConfig {
|
|||||||
|
|
||||||
bchPriv.put(login, priv);
|
bchPriv.put(login, priv);
|
||||||
bchPub.put(login, pub);
|
bchPub.put(login, pub);
|
||||||
|
|
||||||
|
// session seed = "session:" + login (отдельно!)
|
||||||
|
byte[] sPriv = Ed25519Util.generatePrivateKeyFromString("session:" + login);
|
||||||
|
byte[] sPub = Ed25519Util.derivePublicKey(sPriv);
|
||||||
|
|
||||||
|
sessionPriv.put(login, sPriv);
|
||||||
|
sessionPub.put(login, sPub);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============ requested getters (with your names) ============
|
// ============ requested getters (with your names) ============
|
||||||
@ -90,11 +103,18 @@ public final class TestConfig {
|
|||||||
public static byte[] getBlockchainPrivatKey(String login) { return cloneOrThrow(bchPriv.get(login), "bchPriv", login); }
|
public static byte[] getBlockchainPrivatKey(String login) { return cloneOrThrow(bchPriv.get(login), "bchPriv", login); }
|
||||||
public static byte[] getBlockchainPublicKey(String login) { return cloneOrThrow(bchPub.get(login), "bchPub", login); }
|
public static byte[] getBlockchainPublicKey(String login) { return cloneOrThrow(bchPub.get(login), "bchPub", login); }
|
||||||
|
|
||||||
|
// NEW: session getters
|
||||||
|
public static byte[] getSessionPrivatKey(String login) { return cloneOrThrow(sessionPriv.get(login), "sessionPriv", login); }
|
||||||
|
public static byte[] getSessionPublicKey(String login) { return cloneOrThrow(sessionPub.get(login), "sessionPub", login); }
|
||||||
|
|
||||||
// ============ 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 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)); }
|
||||||
|
|
||||||
|
// NEW: session pub b64 helper
|
||||||
|
public static String sessionPublicKeyB64(String login) { return Base64.getEncoder().encodeToString(getSessionPublicKey(login)); }
|
||||||
|
|
||||||
// ============ backward-compatible helpers for "user1" ============
|
// ============ backward-compatible helpers for "user1" ============
|
||||||
public static String BCH_NAME() { return getBlockchainName(LOGIN()); }
|
public static String BCH_NAME() { return getBlockchainName(LOGIN()); }
|
||||||
public static String BCH_NAME2() { return getBlockchainName(LOGIN2()); }
|
public static String BCH_NAME2() { return getBlockchainName(LOGIN2()); }
|
||||||
@ -114,6 +134,11 @@ public final class TestConfig {
|
|||||||
public static String DEVICE2_PUBKEY_B64() { return devicePublicKeyB64(LOGIN2()); }
|
public static String DEVICE2_PUBKEY_B64() { return devicePublicKeyB64(LOGIN2()); }
|
||||||
public static String DEVICE3_PUBKEY_B64() { return devicePublicKeyB64(LOGIN3()); }
|
public static String DEVICE3_PUBKEY_B64() { return devicePublicKeyB64(LOGIN3()); }
|
||||||
|
|
||||||
|
// NEW: session pub b64 compat
|
||||||
|
public static String SESSION_PUBKEY_B64() { return sessionPublicKeyB64(LOGIN()); }
|
||||||
|
public static String SESSION2_PUBKEY_B64() { return sessionPublicKeyB64(LOGIN2()); }
|
||||||
|
public static String SESSION3_PUBKEY_B64() { return sessionPublicKeyB64(LOGIN3()); }
|
||||||
|
|
||||||
// ============ misc ============
|
// ============ misc ============
|
||||||
public static String fakeStoragePwd() {
|
public static String fakeStoragePwd() {
|
||||||
return "pwd-" + System.nanoTime();
|
return "pwd-" + System.nanoTime();
|
||||||
|
|||||||
@ -59,13 +59,20 @@ public final class JsonBuilders {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---------------- CreateAuthSession (v2) ----------------
|
// ---------------- CreateAuthSession (v2) ----------------
|
||||||
// v2: sessionKey генерируется на клиенте, на сервер отправляем только sessionPubKey (base64).
|
// v2: sessionKey генерируется/хранится на клиенте, на сервер отправляем sessionPubKeyB64 (base64).
|
||||||
// подпись шага CreateAuthSession всё ещё делается deviceKey: "AUTHORIFICATED:" + timeMs + authNonce
|
//
|
||||||
|
// ВАЖНО (новое правило):
|
||||||
|
// Подпись CreateAuthSession делается ТОЛЬКО deviceKey над строкой:
|
||||||
|
// preimage = "AUTH_CREATE_SESSION:" + login + ":" + timeMs + ":" + authNonce
|
||||||
|
//
|
||||||
|
// storagePwd и sessionPubKeyB64 НЕ входят в preimage.
|
||||||
|
|
||||||
public static String createAuthSessionV2(String login, String authNonce, String storagePwd, String sessionPubKeyB64) {
|
public static String createAuthSessionV2(String login, String authNonce, String storagePwd, String sessionPubKeyB64) {
|
||||||
long timeMs = System.currentTimeMillis();
|
long timeMs = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// подпись делаем devicePrivKey
|
||||||
byte[] devicePriv = TestConfig.getDevicePrivatKey(login);
|
byte[] devicePriv = TestConfig.getDevicePrivatKey(login);
|
||||||
String sigB64 = signAuthorificated(authNonce, timeMs, devicePriv);
|
String sigB64 = signAuthCreateSession(login, timeMs, authNonce, devicePriv);
|
||||||
|
|
||||||
String requestId = TestIds.next("create");
|
String requestId = TestIds.next("create");
|
||||||
return """
|
return """
|
||||||
@ -106,6 +113,8 @@ public final class JsonBuilders {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---------------- SessionLogin (v2) ----------------
|
// ---------------- SessionLogin (v2) ----------------
|
||||||
|
// Подпись SessionLogin по-прежнему делается sessionPrivKey:
|
||||||
|
// preimage = "SESSION_LOGIN:" + sessionId + ":" + timeMs + ":" + nonce
|
||||||
|
|
||||||
public static String sessionLogin(String sessionId, String nonce, byte[] sessionPrivKey) {
|
public static String sessionLogin(String sessionId, String nonce, byte[] sessionPrivKey) {
|
||||||
long timeMs = System.currentTimeMillis();
|
long timeMs = System.currentTimeMillis();
|
||||||
@ -136,8 +145,6 @@ public final class JsonBuilders {
|
|||||||
"op": "ListSessions",
|
"op": "ListSessions",
|
||||||
"requestId": "%s",
|
"requestId": "%s",
|
||||||
"payload": {
|
"payload": {
|
||||||
"timeMs": %d,
|
|
||||||
"signatureB64": "%s"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""".formatted(requestId, timeMs, signatureB64);
|
""".formatted(requestId, timeMs, signatureB64);
|
||||||
@ -153,9 +160,7 @@ public final class JsonBuilders {
|
|||||||
"op": "CloseActiveSession",
|
"op": "CloseActiveSession",
|
||||||
"requestId": "%s",
|
"requestId": "%s",
|
||||||
"payload": {
|
"payload": {
|
||||||
"sessionId": "%s",
|
"sessionId": "%s"
|
||||||
"timeMs": %d,
|
|
||||||
"signatureB64": "%s"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""".formatted(requestId, sessionId, timeMs, signatureB64);
|
""".formatted(requestId, sessionId, timeMs, signatureB64);
|
||||||
@ -175,12 +180,12 @@ public final class JsonBuilders {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Подпись для режима AUTH_IN_PROGRESS:
|
* Подпись CreateAuthSession(v2):
|
||||||
* preimage = "AUTHORIFICATED:" + timeMs + authNonce
|
* preimage = "AUTH_CREATE_SESSION:" + login + ":" + timeMs + ":" + authNonce
|
||||||
* подписываем devicePrivKey.
|
* подписываем devicePrivKey.
|
||||||
*/
|
*/
|
||||||
public static String signAuthorificated(String authNonce, long timeMs, byte[] devicePrivKey) {
|
public static String signAuthCreateSession(String login, long timeMs, String authNonce, byte[] devicePrivKey) {
|
||||||
String preimageStr = "AUTHORIFICATED:" + timeMs + authNonce;
|
String preimageStr = "AUTH_CREATE_SESSION:" + login + ":" + timeMs + ":" + authNonce;
|
||||||
byte[] preimage = preimageStr.getBytes(StandardCharsets.UTF_8);
|
byte[] preimage = preimageStr.getBytes(StandardCharsets.UTF_8);
|
||||||
byte[] sig = Ed25519Util.sign(preimage, devicePrivKey);
|
byte[] sig = Ed25519Util.sign(preimage, devicePrivKey);
|
||||||
return Base64.getEncoder().encodeToString(sig);
|
return Base64.getEncoder().encodeToString(sig);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user