From c38f404ef3974d8d0198f91fcdb21bcf22710f1e Mon Sep 17 00:00:00 2001 From: dijunkun Date: Thu, 19 Jun 2025 17:43:29 +0800 Subject: [PATCH] [feat] use sqllite3 to manager device id and password --- src/client_id_generator.cpp | 9 -- src/client_id_generator.h | 25 ---- src/device_db_manager/device_db_manager.cpp | 137 ++++++++++++++++++++ src/device_db_manager/device_db_manager.h | 37 ++++++ src/signal_server.cpp | 4 +- src/signal_server.h | 4 +- xmake.lua | 12 +- 7 files changed, 188 insertions(+), 40 deletions(-) delete mode 100644 src/client_id_generator.cpp delete mode 100644 src/client_id_generator.h create mode 100644 src/device_db_manager/device_db_manager.cpp create mode 100644 src/device_db_manager/device_db_manager.h diff --git a/src/client_id_generator.cpp b/src/client_id_generator.cpp deleted file mode 100644 index 6e42965..0000000 --- a/src/client_id_generator.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "client_id_generator.h" - -ClientIdGenerator::ClientIdGenerator() {} - -ClientIdGenerator::~ClientIdGenerator() {} - -std::string ClientIdGenerator::GeneratorNewId() { - return std::to_string(++base_id_); -} \ No newline at end of file diff --git a/src/client_id_generator.h b/src/client_id_generator.h deleted file mode 100644 index a7bd4e2..0000000 --- a/src/client_id_generator.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * @Author: DI JUNKUN - * @Date: 2024-08-06 - * Copyright (c) 2024 by DI JUNKUN, All Rights Reserved. - */ - -#ifndef _CLIENT_ID_GENERATOR_H_ -#define _CLIENT_ID_GENERATOR_H_ - -#include -#include - -class ClientIdGenerator { - public: - ClientIdGenerator(); - ~ClientIdGenerator(); - - public: - std::string GeneratorNewId(); - - private: - int base_id_ = 300000000; -}; - -#endif \ No newline at end of file diff --git a/src/device_db_manager/device_db_manager.cpp b/src/device_db_manager/device_db_manager.cpp new file mode 100644 index 0000000..1a6ef76 --- /dev/null +++ b/src/device_db_manager/device_db_manager.cpp @@ -0,0 +1,137 @@ +#include "device_db_manager.h" + +#include + +#include +#include +#include +#include +#include + +#include "log.h" + +DeviceDBManager::DeviceDBManager(const std::string& dbPath) : db(nullptr) { + if (sqlite3_open(dbPath.c_str(), &db) != SQLITE_OK) { + LOG_ERROR("Failed to open database: {} with error msg {}", dbPath, + sqlite3_errmsg(db)); + } + initDB(); +} + +DeviceDBManager::~DeviceDBManager() { + if (db) sqlite3_close(db); +} + +void DeviceDBManager::initDB() { + const char* sql = + "CREATE TABLE IF NOT EXISTS devices (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "device_id TEXT UNIQUE NOT NULL," + "password_hash TEXT NOT NULL);"; + + char* errMsg = nullptr; + int rc = sqlite3_exec(db, sql, nullptr, nullptr, &errMsg); + if (rc != SQLITE_OK) { + LOG_ERROR("Failed to initialize DB: {}", errMsg); + sqlite3_free(errMsg); + } +} + +std::string DeviceDBManager::sha256(const std::string& str) { + unsigned char hash[SHA256_DIGEST_LENGTH]; + SHA256(reinterpret_cast(str.c_str()), str.size(), hash); + + std::stringstream ss; + for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) + ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i]; + + return ss.str(); +} + +std::string DeviceDBManager::generateDeviceId() { + static std::mt19937 rng(static_cast( + std::chrono::steady_clock::now().time_since_epoch().count())); + std::uniform_int_distribution dist(0, 9); + + std::string id; + for (int i = 0; i < 9; ++i) { + id += '0' + dist(rng); + } + return id; +} + +std::string DeviceDBManager::addDevice(const std::string& password) { + std::string hash = sha256(password); + + const int maxTry = 10; + for (int i = 0; i < maxTry; ++i) { + std::string deviceId = generateDeviceId(); + + const char* sql = + "INSERT INTO devices (device_id, password_hash) VALUES (?, ?);"; + sqlite3_stmt* stmt = nullptr; + if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { + LOG_ERROR("Failed to prepare insert statement"); + return ""; + } + + sqlite3_bind_text(stmt, 1, deviceId.c_str(), -1, SQLITE_TRANSIENT); + sqlite3_bind_text(stmt, 2, hash.c_str(), -1, SQLITE_TRANSIENT); + + int rc = sqlite3_step(stmt); + sqlite3_finalize(stmt); + + if (rc == SQLITE_DONE) { + return deviceId; + } else if (rc == SQLITE_CONSTRAINT) { + continue; + } else { + LOG_ERROR("Failed to insert device: {}", sqlite3_errmsg(db)); + return ""; + } + } + + LOG_ERROR("Failed to generate unique device ID after {} attempts.", maxTry); + return ""; +} + +bool DeviceDBManager::verifyDevice(const std::string& deviceId, + const std::string& password) { + std::string hash = sha256(password); + const char* sql = + "SELECT COUNT(*) FROM devices WHERE device_id = ? AND password_hash = ?;"; + + sqlite3_stmt* stmt = nullptr; + if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { + LOG_ERROR("Failed to prepare verify statement."); + return false; + } + + sqlite3_bind_text(stmt, 1, deviceId.c_str(), -1, SQLITE_TRANSIENT); + sqlite3_bind_text(stmt, 2, hash.c_str(), -1, SQLITE_TRANSIENT); + + bool found = false; + if (sqlite3_step(stmt) == SQLITE_ROW) { + int count = sqlite3_column_int(stmt, 0); + found = (count > 0); + } + + sqlite3_finalize(stmt); + return found; +} + +bool DeviceDBManager::removeDevice(const std::string& deviceId) { + const char* sql = "DELETE FROM devices WHERE device_id = ?;"; + + sqlite3_stmt* stmt = nullptr; + if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { + LOG_ERROR("Failed to prepare delete statement."); + return false; + } + + sqlite3_bind_text(stmt, 1, deviceId.c_str(), -1, SQLITE_TRANSIENT); + + bool success = (sqlite3_step(stmt) == SQLITE_DONE); + sqlite3_finalize(stmt); + return success; +} diff --git a/src/device_db_manager/device_db_manager.h b/src/device_db_manager/device_db_manager.h new file mode 100644 index 0000000..71b31cd --- /dev/null +++ b/src/device_db_manager/device_db_manager.h @@ -0,0 +1,37 @@ +/* + * @Author: DI JUNKUN + * @Date: 2025-06-19 + * Copyright (c) 2025 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _DEVICE_DB_MANAGER_H_ +#define _DEVICE_DB_MANAGER_H_ + +#include + +#include + +class DeviceDBManager { + public: + explicit DeviceDBManager(const std::string& dbPath); + ~DeviceDBManager(); + + DeviceDBManager(const DeviceDBManager&) = delete; + DeviceDBManager& operator=(const DeviceDBManager&) = delete; + + public: + std::string addDevice(const std::string& password); + + bool verifyDevice(const std::string& deviceId, const std::string& password); + bool removeDevice(const std::string& deviceId); + + private: + std::string sha256(const std::string& str); + void initDB(); + std::string generateDeviceId(); + + private: + sqlite3* db; +}; + +#endif // _DEVICE_DB_MANAGER_H_ diff --git a/src/signal_server.cpp b/src/signal_server.cpp index 5042477..b93d257 100644 --- a/src/signal_server.cpp +++ b/src/signal_server.cpp @@ -47,6 +47,8 @@ SignalServer::~SignalServer() {} bool SignalServer::on_open(websocketpp::connection_hdl hdl) { ws_connections_[hdl] = ws_connection_id_++; + + device_db_manager_ = std::make_unique(""); return true; } @@ -155,7 +157,7 @@ void SignalServer::on_message(websocketpp::connection_hdl hdl, case "login"_H: { std::string host_id = j["user_id"].get(); if (host_id.empty()) { - host_id = client_id_generator_.GeneratorNewId(); + host_id = ""; // todo LOG_INFO("New client, assign id [{}] to it", host_id); } diff --git a/src/signal_server.h b/src/signal_server.h index 1a5fa20..731f9a6 100644 --- a/src/signal_server.h +++ b/src/signal_server.h @@ -9,7 +9,7 @@ #include #include -#include "client_id_generator.h" +#include "device_db_manager.h" #include "transmission_manager.h" using nlohmann::json; @@ -48,7 +48,7 @@ class SignalServer { private: TransmissionManager transmission_manager_; - ClientIdGenerator client_id_generator_; + std::unique_ptr device_db_manager_; }; #endif \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index a8cb31f..3f3d6da 100644 --- a/xmake.lua +++ b/xmake.lua @@ -6,7 +6,7 @@ set_languages("c++17") add_rules("mode.release", "mode.debug") -add_requires("asio 1.24.0", "nlohmann_json", "spdlog 1.11.0") +add_requires("asio 1.24.0", "nlohmann_json", "spdlog 1.14.1", "sqlite3 3.49.0", "openssl") add_defines("ASIO_STANDALONE", "ASIO_HAS_STD_TYPE_TRAITS", "ASIO_HAS_STD_SHARED_PTR", "ASIO_HAS_STD_ADDRESSOF", "ASIO_HAS_STD_ATOMIC", @@ -22,7 +22,7 @@ elseif is_os("linux") then set_config("cxxflags", "-fPIC") end -add_packages("spdlog") +add_packages("spdlog", "openssl", "sqlite3") includes("thirdparty") @@ -36,9 +36,15 @@ target("common") set_kind("headeronly") add_includedirs("src/common", {public = true}) +target("device_db_manager") + set_kind("object") + add_deps("log") + add_files("src/device_db_manager/*.cpp") + add_includedirs("src/device_db_manager", {public = true}) + target("signal_server") set_kind("binary") - add_deps("log", "common") + add_deps("log", "common", "device_db_manager") add_files("src/*.cpp") add_packages("asio", "nlohmann_json", "spdlog") add_includedirs("thirdparty/websocketpp/include")