SHA256
Wallet-session pairing и browser plugin wallet, оплаты пока не работают
This commit is contained in:
+36
@@ -4,6 +4,7 @@ import org.eclipse.jetty.websocket.api.Session;
|
||||
import server.logic.ws_protocol.JSON.ActiveConnectionsRegistry;
|
||||
import server.logic.ws_protocol.JSON.ConnectionContext;
|
||||
import shine.db.entities.ActiveSessionEntry;
|
||||
import utils.crypto.HashSHA256Util;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
@@ -29,6 +30,8 @@ final class EspPairingSupport {
|
||||
static final String STATE_REJECTED = "rejected";
|
||||
static final String STATE_CANCELED = "canceled";
|
||||
static final String STATE_EXPIRED = "expired";
|
||||
static final String PASSWORD_HASH_PREFIX = "sha256$";
|
||||
static final String PASSWORD_HASH_VERSION = "shine-pairing";
|
||||
|
||||
private static final SecureRandom RANDOM = new SecureRandom();
|
||||
private static final char[] BASE58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
|
||||
@@ -77,6 +80,30 @@ final class EspPairingSupport {
|
||||
return value;
|
||||
}
|
||||
|
||||
static String normalizePasswordHash(String raw) {
|
||||
String value = normalizeOpaqueHash(raw);
|
||||
if (value == null) return null;
|
||||
if (!value.regionMatches(true, 0, PASSWORD_HASH_PREFIX, 0, PASSWORD_HASH_PREFIX.length())) {
|
||||
return null;
|
||||
}
|
||||
String hex = value.substring(PASSWORD_HASH_PREFIX.length()).trim().toLowerCase(Locale.ROOT);
|
||||
if (hex.length() != 64) return null;
|
||||
for (int i = 0; i < hex.length(); i++) {
|
||||
char ch = hex.charAt(i);
|
||||
boolean ok = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f');
|
||||
if (!ok) return null;
|
||||
}
|
||||
return PASSWORD_HASH_PREFIX + hex;
|
||||
}
|
||||
|
||||
static String derivePasswordHash(String loginRaw, String passwordRaw) {
|
||||
String login = loginRaw == null ? "" : loginRaw.trim().toLowerCase(Locale.ROOT);
|
||||
String password = passwordRaw == null ? "" : passwordRaw;
|
||||
String preimage = PASSWORD_HASH_VERSION + "|" + login + "|" + password;
|
||||
byte[] digest = HashSHA256Util.sha256(preimage.getBytes(StandardCharsets.UTF_8));
|
||||
return PASSWORD_HASH_PREFIX + toHexLower(digest);
|
||||
}
|
||||
|
||||
static String normalizeEncryptedPayload(String raw) {
|
||||
if (raw == null) return null;
|
||||
String value = raw.trim();
|
||||
@@ -149,5 +176,14 @@ final class EspPairingSupport {
|
||||
return remainder;
|
||||
}
|
||||
|
||||
private static String toHexLower(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder(bytes.length * 2);
|
||||
for (byte b : bytes) {
|
||||
sb.append(Character.forDigit((b >>> 4) & 0x0F, 16));
|
||||
sb.append(Character.forDigit(b & 0x0F, 16));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
record PairingFingerprint(String shortCode, String fingerprintB58) {}
|
||||
}
|
||||
|
||||
+5
-1
@@ -54,7 +54,11 @@ public class Net_StartEspPairing_Handler implements JsonMessageHandler {
|
||||
if (!EspPairingSupport.isSupportedPayloadType(payloadType)) {
|
||||
return NetExceptionResponseFactory.error(req, WireCodes.Status.BAD_REQUEST, "BAD_PAYLOAD_TYPE", "payloadType должен быть 1, 2 или 3");
|
||||
}
|
||||
String passwordHash = EspPairingSupport.normalizeOpaqueHash(req.getPasswordHash());
|
||||
String rawPasswordHash = EspPairingSupport.normalizeOpaqueHash(req.getPasswordHash());
|
||||
String passwordHash = EspPairingSupport.normalizePasswordHash(rawPasswordHash);
|
||||
if (rawPasswordHash != null && passwordHash == null) {
|
||||
return NetExceptionResponseFactory.error(req, WireCodes.Status.BAD_REQUEST, "BAD_PASSWORD_HASH_FORMAT", "passwordHash должен быть пустым или иметь формат sha256$<64 hex>");
|
||||
}
|
||||
|
||||
SolanaUserEntry user = SolanaUsersDAO.getInstance().getByLogin(login);
|
||||
if (user == null) {
|
||||
|
||||
+10
-1
@@ -27,7 +27,16 @@ public class Net_UpsertEspPairingSettings_Handler implements JsonMessageHandler
|
||||
}
|
||||
|
||||
boolean enabled = req.getEnabled() != null && req.getEnabled();
|
||||
String passwordHash = EspPairingSupport.normalizeOpaqueHash(req.getPasswordHash());
|
||||
String rawPasswordHash = EspPairingSupport.normalizeOpaqueHash(req.getPasswordHash());
|
||||
String passwordHash = EspPairingSupport.normalizePasswordHash(rawPasswordHash);
|
||||
if (rawPasswordHash != null && passwordHash == null) {
|
||||
return NetExceptionResponseFactory.error(
|
||||
req,
|
||||
WireCodes.Status.BAD_REQUEST,
|
||||
"BAD_PASSWORD_HASH_FORMAT",
|
||||
"passwordHash должен быть пустым или иметь формат sha256$<64 hex>"
|
||||
);
|
||||
}
|
||||
int ttlSeconds = EspPairingSupport.normalizeTtlSeconds(req.getTtlSeconds());
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
@@ -9,9 +9,11 @@ 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;
|
||||
import java.util.Base64;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@@ -38,7 +40,7 @@ public class IT_07_EspPairing {
|
||||
|
||||
sessionLogin2Steps(clientWs, clientSession, 1, "Web", t, r);
|
||||
|
||||
String passwordHash = "argon2id$v=19$m=65536,t=2,p=1$test$esp_pairing_hash";
|
||||
String passwordHash = derivePairingHash(LOGIN, "test-pairing-password");
|
||||
String upsertResp = clientWs.call(
|
||||
"UpsertEspPairingSettings",
|
||||
JsonBuilders.upsertEspPairingSettings(true, passwordHash, 180),
|
||||
@@ -218,6 +220,17 @@ public class IT_07_EspPairing {
|
||||
SolanaUsersDAO.getInstance().insert(entry);
|
||||
}
|
||||
|
||||
private static String derivePairingHash(String login, String password) {
|
||||
String preimage = "shine-pairing|" + login.trim().toLowerCase() + "|" + password;
|
||||
byte[] digest = HashSHA256Util.sha256(preimage.getBytes(StandardCharsets.UTF_8));
|
||||
StringBuilder sb = new StringBuilder(64);
|
||||
for (byte b : digest) {
|
||||
sb.append(Character.forDigit((b >>> 4) & 0x0F, 16));
|
||||
sb.append(Character.forDigit(b & 0x0F, 16));
|
||||
}
|
||||
return "sha256$" + sb;
|
||||
}
|
||||
|
||||
private record Session(String sessionId, String sessionKey, byte[] sessionPrivKey, String storagePwd) {}
|
||||
private record SessionMaterial(String sessionKey, byte[] sessionPrivKey) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user