SHA256
09 12 25
Авторификация работает и тест авторификации проходит. (создание пользователя, два этапа создания сессии и рефреш сессии)
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
package shine.db;
|
||||
|
||||
|
||||
import utils.config.AppConfig;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
@@ -12,6 +11,15 @@ import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
/**
|
||||
* DatabaseInitializer — создание новой SQLite-БД по схеме SHiNE.
|
||||
*
|
||||
* Читает путь к файлу БД из application.properties (db.path),
|
||||
* при необходимости удаляет старый файл и создаёт таблицы:
|
||||
* - solana_users
|
||||
* - active_sessions
|
||||
* - users_params
|
||||
*/
|
||||
public class DatabaseInitializer {
|
||||
|
||||
public static void createNewDB(String[] args) {
|
||||
@@ -75,9 +83,9 @@ public class DatabaseInitializer {
|
||||
login TEXT NOT NULL,
|
||||
loginId INTEGER NOT NULL PRIMARY KEY,
|
||||
bchId INTEGER NOT NULL,
|
||||
pubkey0 TEXT,
|
||||
pubkey1 TEXT,
|
||||
bchLimit INTEGER -- может быть NULL
|
||||
loginKey TEXT, -- основной публичный ключ (логин)
|
||||
deviceKey TEXT, -- публичный ключ устройства
|
||||
bchLimit INTEGER -- может быть NULL
|
||||
);
|
||||
""");
|
||||
|
||||
@@ -87,22 +95,29 @@ public class DatabaseInitializer {
|
||||
""");
|
||||
|
||||
// 2. Таблица active_sessions
|
||||
// sessionId теперь TEXT (base64 от 32 байт), а не INTEGER.
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS active_sessions (
|
||||
sessionId INTEGER NOT NULL PRIMARY KEY,
|
||||
session_pwd TEXT NOT NULL,
|
||||
loginId INTEGER NOT NULL,
|
||||
time_ms INTEGER NOT NULL,
|
||||
pubkey_num INTEGER NOT NULL,
|
||||
push_endpoint TEXT,
|
||||
push_p256dh_key TEXT,
|
||||
push_auth_key TEXT,
|
||||
sessionId TEXT NOT NULL PRIMARY KEY,
|
||||
loginId INTEGER NOT NULL,
|
||||
sessionPwd TEXT NOT NULL,
|
||||
storagePwd TEXT NOT NULL,
|
||||
sessionCreatedAtMs INTEGER NOT NULL,
|
||||
lastAuthirificatedAtMs INTEGER NOT NULL,
|
||||
pushEndpoint TEXT,
|
||||
pushP256dhKey TEXT,
|
||||
pushAuthKey TEXT,
|
||||
FOREIGN KEY (loginId) REFERENCES solana_users(loginId)
|
||||
);
|
||||
""");
|
||||
|
||||
st.executeUpdate("""
|
||||
CREATE INDEX IF NOT EXISTS idx_active_sessions_loginId
|
||||
ON active_sessions (loginId);
|
||||
""");
|
||||
|
||||
// 3. Таблица users_params
|
||||
// Важно: пара (loginId, param) должна быть уникальна
|
||||
// Пара (loginId, param) должна быть уникальна.
|
||||
st.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS users_params (
|
||||
loginId INTEGER NOT NULL,
|
||||
|
||||
@@ -5,7 +5,11 @@ import shine.db.entities.ActiveSession;
|
||||
|
||||
import java.sql.*;
|
||||
|
||||
/** Здесь мы храним данные об активных сессиях пользователя (для wss соединений). */
|
||||
/**
|
||||
* DAO для таблицы active_sessions.
|
||||
*
|
||||
* Здесь мы храним данные об активных сессиях пользователя (для wss-соединений).
|
||||
*/
|
||||
public final class ActiveSessionsDAO {
|
||||
|
||||
private static volatile ActiveSessionsDAO instance;
|
||||
@@ -25,18 +29,21 @@ public final class ActiveSessionsDAO {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Вставка новой сессии.
|
||||
*/
|
||||
public void insert(ActiveSession session) throws SQLException {
|
||||
String sql = """
|
||||
INSERT INTO active_sessions (
|
||||
sessionId,
|
||||
loginId,
|
||||
session_pwd,
|
||||
storage_pwd,
|
||||
session_created_ms,
|
||||
last_auth_ms,
|
||||
push_endpoint,
|
||||
push_p256dh_key,
|
||||
push_auth_key
|
||||
sessionPwd,
|
||||
storagePwd,
|
||||
sessionCreatedAtMs,
|
||||
lastAuthirificatedAtMs,
|
||||
pushEndpoint,
|
||||
pushP256dhKey,
|
||||
pushAuthKey
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""";
|
||||
|
||||
@@ -50,22 +57,26 @@ public final class ActiveSessionsDAO {
|
||||
ps.setString(7, session.getPushEndpoint());
|
||||
ps.setString(8, session.getPushP256dhKey());
|
||||
ps.setString(9, session.getPushAuthKey());
|
||||
|
||||
ps.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить сессию по sessionId.
|
||||
*/
|
||||
public ActiveSession getBySessionId(String sessionId) throws SQLException {
|
||||
String sql = """
|
||||
SELECT
|
||||
sessionId,
|
||||
loginId,
|
||||
session_pwd,
|
||||
storage_pwd,
|
||||
session_created_ms,
|
||||
last_auth_ms,
|
||||
push_endpoint,
|
||||
push_p256dh_key,
|
||||
push_auth_key
|
||||
sessionPwd,
|
||||
storagePwd,
|
||||
sessionCreatedAtMs,
|
||||
lastAuthirificatedAtMs,
|
||||
pushEndpoint,
|
||||
pushP256dhKey,
|
||||
pushAuthKey
|
||||
FROM active_sessions
|
||||
WHERE sessionId = ?
|
||||
""";
|
||||
@@ -81,6 +92,23 @@ public final class ActiveSessionsDAO {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновить только lastAuthirificatedAtMs для конкретной сессии.
|
||||
*/
|
||||
public void updateLastAuthirificatedAtMs(String sessionId, long lastAuthMs) throws SQLException {
|
||||
String sql = """
|
||||
UPDATE active_sessions
|
||||
SET lastAuthirificatedAtMs = ?
|
||||
WHERE sessionId = ?
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setLong(1, lastAuthMs);
|
||||
ps.setString(2, sessionId);
|
||||
ps.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаление записи по sessionId.
|
||||
* Если записи нет — просто ничего не удалит (0 строк).
|
||||
@@ -94,42 +122,24 @@ public final class ActiveSessionsDAO {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновить поле last_auth_ms (lastAuthirificatedAtMs) для конкретной сессии.
|
||||
* Остальные поля записи не меняются.
|
||||
*/
|
||||
public void updateLastAuthirificatedAtMs(String sessionId, long newTimeMs) throws SQLException {
|
||||
String sql = """
|
||||
UPDATE active_sessions
|
||||
SET last_auth_ms = ?
|
||||
WHERE sessionId = ?
|
||||
""";
|
||||
|
||||
try (PreparedStatement ps = db.getConnection().prepareStatement(sql)) {
|
||||
ps.setLong(1, newTimeMs);
|
||||
ps.setString(2, sessionId);
|
||||
ps.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private ActiveSession mapRow(ResultSet rs) throws SQLException {
|
||||
String sessionId = rs.getString("sessionId");
|
||||
long loginId = rs.getLong("loginId");
|
||||
String sessionPwd = rs.getString("session_pwd");
|
||||
String storagePwd = rs.getString("storage_pwd");
|
||||
long sessionCreatedMs = rs.getLong("session_created_ms");
|
||||
long lastAuthMs = rs.getLong("last_auth_ms");
|
||||
String pushEndpoint = rs.getString("push_endpoint");
|
||||
String pushP256dhKey = rs.getString("push_p256dh_key");
|
||||
String pushAuthKey = rs.getString("push_auth_key");
|
||||
String sessionPwd = rs.getString("sessionPwd");
|
||||
String storagePwd = rs.getString("storagePwd");
|
||||
long sessionCreatedAtMs = rs.getLong("sessionCreatedAtMs");
|
||||
long lastAuthirificatedAtMs = rs.getLong("lastAuthirificatedAtMs");
|
||||
String pushEndpoint = rs.getString("pushEndpoint");
|
||||
String pushP256dhKey = rs.getString("pushP256dhKey");
|
||||
String pushAuthKey = rs.getString("pushAuthKey");
|
||||
|
||||
return new ActiveSession(
|
||||
sessionId,
|
||||
loginId,
|
||||
sessionPwd,
|
||||
storagePwd,
|
||||
sessionCreatedMs,
|
||||
lastAuthMs,
|
||||
sessionCreatedAtMs,
|
||||
lastAuthirificatedAtMs,
|
||||
pushEndpoint,
|
||||
pushP256dhKey,
|
||||
pushAuthKey
|
||||
|
||||
@@ -7,8 +7,17 @@ import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Здесь храним данные об пользователях - локальная копия того что есть в солане */
|
||||
|
||||
/**
|
||||
* SolanaUsersDAO — локальная таблица пользователей из Solana.
|
||||
*
|
||||
* Колонки:
|
||||
* - login TEXT
|
||||
* - loginId INTEGER (PK)
|
||||
* - bchId INTEGER
|
||||
* - loginKey TEXT
|
||||
* - deviceKey TEXT
|
||||
* - bchLimit INTEGER (может быть NULL)
|
||||
*/
|
||||
public final class SolanaUsersDAO {
|
||||
|
||||
private static volatile SolanaUsersDAO instance;
|
||||
@@ -29,7 +38,7 @@ public final class SolanaUsersDAO {
|
||||
|
||||
public void insert(SolanaUser user) throws SQLException {
|
||||
String sql = """
|
||||
INSERT INTO solana_users (login, loginId, bchId, pubkey0, pubkey1, bchLimit)
|
||||
INSERT INTO solana_users (login, loginId, bchId, loginKey, deviceKey, bchLimit)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
""";
|
||||
|
||||
@@ -37,8 +46,8 @@ public final class SolanaUsersDAO {
|
||||
ps.setString(1, user.getLogin());
|
||||
ps.setLong(2, user.getLoginId());
|
||||
ps.setLong(3, user.getBchId());
|
||||
ps.setString(4, user.getPubkey0());
|
||||
ps.setString(5, user.getPubkey1());
|
||||
ps.setString(4, user.getLoginKey());
|
||||
ps.setString(5, user.getDeviceKey());
|
||||
|
||||
if (user.getBchLimit() != null) {
|
||||
ps.setInt(6, user.getBchLimit());
|
||||
@@ -52,7 +61,7 @@ public final class SolanaUsersDAO {
|
||||
|
||||
public SolanaUser getByLoginId(long loginId) throws SQLException {
|
||||
String sql = """
|
||||
SELECT login, loginId, bchId, pubkey0, pubkey1, bchLimit
|
||||
SELECT login, loginId, bchId, loginKey, deviceKey, bchLimit
|
||||
FROM solana_users
|
||||
WHERE loginId = ?
|
||||
""";
|
||||
@@ -69,7 +78,7 @@ public final class SolanaUsersDAO {
|
||||
|
||||
public SolanaUser getByLogin(String login) throws SQLException {
|
||||
String sql = """
|
||||
SELECT login, loginId, bchId, pubkey0, pubkey1, bchLimit
|
||||
SELECT login, loginId, bchId, loginKey, deviceKey, bchLimit
|
||||
FROM solana_users
|
||||
WHERE LOWER(login) = LOWER(?)
|
||||
""";
|
||||
@@ -86,7 +95,7 @@ public final class SolanaUsersDAO {
|
||||
|
||||
public List<SolanaUser> searchByLoginPrefix(String prefix) throws SQLException {
|
||||
String sql = """
|
||||
SELECT login, loginId, bchId, pubkey0, pubkey1, bchLimit
|
||||
SELECT login, loginId, bchId, loginKey, deviceKey, bchLimit
|
||||
FROM solana_users
|
||||
WHERE LOWER(login) LIKE ?
|
||||
ORDER BY login
|
||||
@@ -111,8 +120,8 @@ public final class SolanaUsersDAO {
|
||||
rs.getLong("loginId"),
|
||||
rs.getString("login"),
|
||||
rs.getLong("bchId"),
|
||||
rs.getString("pubkey0"),
|
||||
rs.getString("pubkey1"),
|
||||
rs.getString("loginKey"),
|
||||
rs.getString("deviceKey"),
|
||||
rs.getObject("bchLimit") != null ? rs.getInt("bchLimit") : null
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,30 +1,34 @@
|
||||
package shine.db.entities;
|
||||
|
||||
/**
|
||||
* ActiveSession — запись об активной сессии пользователя.
|
||||
* Модель активной сессии (таблица active_sessions).
|
||||
*
|
||||
* Поля:
|
||||
* - sessionId – строка (base64 от 32 байт)
|
||||
* - loginId – long
|
||||
* - sessionPwd – строка (секрет шага 1)
|
||||
* - storagePwd – строка (секрет клиента для хранения данных)
|
||||
* - sessionCreatedAtMs – long (время создания)
|
||||
* - lastAuthirificatedAtMs – long (последнее подтверждение/refresh)
|
||||
* - pushEndpoint – строка (WebPush, пока null/пусто)
|
||||
* - pushP256dhKey – строка (WebPush, пока null/пусто)
|
||||
* - pushAuthKey – строка (WebPush, пока null/пусто)
|
||||
* Поля соответствуют схеме:
|
||||
*
|
||||
* CREATE TABLE active_sessions (
|
||||
* sessionId TEXT NOT NULL PRIMARY KEY,
|
||||
* loginId INTEGER NOT NULL,
|
||||
* sessionPwd TEXT NOT NULL,
|
||||
* storagePwd TEXT NOT NULL,
|
||||
* sessionCreatedAtMs INTEGER NOT NULL,
|
||||
* lastAuthirificatedAtMs INTEGER NOT NULL,
|
||||
* pushEndpoint TEXT,
|
||||
* pushP256dhKey TEXT,
|
||||
* pushAuthKey TEXT,
|
||||
* FOREIGN KEY (loginId) REFERENCES solana_users(loginId)
|
||||
* );
|
||||
*/
|
||||
public class ActiveSession {
|
||||
|
||||
private String sessionId;
|
||||
private long loginId;
|
||||
private String sessionPwd;
|
||||
private String storagePwd;
|
||||
private long sessionCreatedAtMs;
|
||||
private long lastAuthirificatedAtMs;
|
||||
private String pushEndpoint;
|
||||
private String pushP256dhKey;
|
||||
private String pushAuthKey;
|
||||
private String sessionId; // TEXT base64(32 bytes)
|
||||
private long loginId; // INTEGER
|
||||
private String sessionPwd; // TEXT
|
||||
private String storagePwd; // TEXT
|
||||
private long sessionCreatedAtMs; // INTEGER
|
||||
private long lastAuthirificatedAtMs; // INTEGER
|
||||
private String pushEndpoint; // TEXT (nullable)
|
||||
private String pushP256dhKey; // TEXT (nullable)
|
||||
private String pushAuthKey; // TEXT (nullable)
|
||||
|
||||
public ActiveSession() {
|
||||
}
|
||||
@@ -49,9 +53,12 @@ public class ActiveSession {
|
||||
this.pushAuthKey = pushAuthKey;
|
||||
}
|
||||
|
||||
// --- getters / setters ---
|
||||
|
||||
public String getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public void setSessionId(String sessionId) {
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
@@ -59,6 +66,7 @@ public class ActiveSession {
|
||||
public long getLoginId() {
|
||||
return loginId;
|
||||
}
|
||||
|
||||
public void setLoginId(long loginId) {
|
||||
this.loginId = loginId;
|
||||
}
|
||||
@@ -66,6 +74,7 @@ public class ActiveSession {
|
||||
public String getSessionPwd() {
|
||||
return sessionPwd;
|
||||
}
|
||||
|
||||
public void setSessionPwd(String sessionPwd) {
|
||||
this.sessionPwd = sessionPwd;
|
||||
}
|
||||
@@ -73,6 +82,7 @@ public class ActiveSession {
|
||||
public String getStoragePwd() {
|
||||
return storagePwd;
|
||||
}
|
||||
|
||||
public void setStoragePwd(String storagePwd) {
|
||||
this.storagePwd = storagePwd;
|
||||
}
|
||||
@@ -80,6 +90,7 @@ public class ActiveSession {
|
||||
public long getSessionCreatedAtMs() {
|
||||
return sessionCreatedAtMs;
|
||||
}
|
||||
|
||||
public void setSessionCreatedAtMs(long sessionCreatedAtMs) {
|
||||
this.sessionCreatedAtMs = sessionCreatedAtMs;
|
||||
}
|
||||
@@ -87,6 +98,7 @@ public class ActiveSession {
|
||||
public long getLastAuthirificatedAtMs() {
|
||||
return lastAuthirificatedAtMs;
|
||||
}
|
||||
|
||||
public void setLastAuthirificatedAtMs(long lastAuthirificatedAtMs) {
|
||||
this.lastAuthirificatedAtMs = lastAuthirificatedAtMs;
|
||||
}
|
||||
@@ -94,6 +106,7 @@ public class ActiveSession {
|
||||
public String getPushEndpoint() {
|
||||
return pushEndpoint;
|
||||
}
|
||||
|
||||
public void setPushEndpoint(String pushEndpoint) {
|
||||
this.pushEndpoint = pushEndpoint;
|
||||
}
|
||||
@@ -101,6 +114,7 @@ public class ActiveSession {
|
||||
public String getPushP256dhKey() {
|
||||
return pushP256dhKey;
|
||||
}
|
||||
|
||||
public void setPushP256dhKey(String pushP256dhKey) {
|
||||
this.pushP256dhKey = pushP256dhKey;
|
||||
}
|
||||
@@ -108,6 +122,7 @@ public class ActiveSession {
|
||||
public String getPushAuthKey() {
|
||||
return pushAuthKey;
|
||||
}
|
||||
|
||||
public void setPushAuthKey(String pushAuthKey) {
|
||||
this.pushAuthKey = pushAuthKey;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
package shine.db.entities;
|
||||
|
||||
/**
|
||||
* Локальная копия пользователя из Solana.
|
||||
*
|
||||
* Храним:
|
||||
* - login / loginId;
|
||||
* - bchId — id персонального блокчейна;
|
||||
* - loginKey — публичный ключ для логина / авторизации;
|
||||
* - deviceKey — публичный ключ устройства (второй ключ);
|
||||
* - bchLimit — лимит по количеству блоков / размеру цепочки (может быть null).
|
||||
*/
|
||||
public class SolanaUser {
|
||||
|
||||
private long loginId;
|
||||
private String login;
|
||||
private long bchId;
|
||||
private String pubkey0;
|
||||
private String pubkey1;
|
||||
private Integer bchLimit; // может быть null
|
||||
private String loginKey; // раньше pubkey0
|
||||
private String deviceKey; // раньше pubkey1
|
||||
private Integer bchLimit; // может быть null
|
||||
|
||||
public SolanaUser() {
|
||||
}
|
||||
@@ -15,14 +25,14 @@ public class SolanaUser {
|
||||
public SolanaUser(long loginId,
|
||||
String login,
|
||||
long bchId,
|
||||
String pubkey0,
|
||||
String pubkey1,
|
||||
String loginKey,
|
||||
String deviceKey,
|
||||
Integer bchLimit) {
|
||||
this.loginId = loginId;
|
||||
this.login = login;
|
||||
this.bchId = bchId;
|
||||
this.pubkey0 = pubkey0;
|
||||
this.pubkey1 = pubkey1;
|
||||
this.loginKey = loginKey;
|
||||
this.deviceKey = deviceKey;
|
||||
this.bchLimit = bchLimit;
|
||||
}
|
||||
|
||||
@@ -50,20 +60,22 @@ public class SolanaUser {
|
||||
this.bchId = bchId;
|
||||
}
|
||||
|
||||
public String getPubkey0() {
|
||||
return pubkey0;
|
||||
/** Публичный ключ логина (основной ключ пользователя). */
|
||||
public String getLoginKey() {
|
||||
return loginKey;
|
||||
}
|
||||
|
||||
public void setPubkey0(String pubkey0) {
|
||||
this.pubkey0 = pubkey0;
|
||||
public void setLoginKey(String loginKey) {
|
||||
this.loginKey = loginKey;
|
||||
}
|
||||
|
||||
public String getPubkey1() {
|
||||
return pubkey1;
|
||||
/** Публичный ключ устройства (device key). */
|
||||
public String getDeviceKey() {
|
||||
return deviceKey;
|
||||
}
|
||||
|
||||
public void setPubkey1(String pubkey1) {
|
||||
this.pubkey1 = pubkey1;
|
||||
public void setDeviceKey(String deviceKey) {
|
||||
this.deviceKey = deviceKey;
|
||||
}
|
||||
|
||||
public Integer getBchLimit() {
|
||||
|
||||
Reference in New Issue
Block a user