#include "stdafx.h"
|
#include "UserManager.h"
|
#include <chrono>
|
#include <iostream>
|
#include <fstream>
|
#include <ctime>
|
#include <sstream>
|
|
const std::string SESSION_FILE = R"(session.dat)";
|
const std::string DATABASE_FILE = R"(BondEq.db)";
|
|
const std::string INITIAL_ADMIN_USERNAME = "admin";
|
const std::string INITIAL_ADMIN_PASSWORD = "admin";
|
|
// »ñÈ¡µ¥ÀýʵÀý
|
UserManager& UserManager::getInstance() {
|
static UserManager instance;
|
return instance;
|
}
|
|
UserManager::UserManager()
|
: m_isLoggedIn(false), m_isRememberMe(false), m_tmSessionTimeout(std::chrono::minutes(30)),
|
m_tmSessionExpiration(std::chrono::hours(72)), m_hMouseHook(nullptr), m_hKeyboardHook(nullptr),
|
m_pDB(std::make_unique<BL::SQLiteDatabase>()) {
|
initializeDatabase();
|
}
|
|
UserManager::~UserManager() {
|
terminateIdleDetection();
|
}
|
|
// ÌṩÊý¾Ý¿âÁ¬½Ó
|
std::unique_ptr<BL::Database>& UserManager::getDatabaseInstance() {
|
return m_pDB;
|
}
|
|
// ³õʼ»¯Êý¾Ý¿â£¬´´½¨Óû§±í²¢²åÈë³õʼ¹ÜÀíÔ±Óû§
|
bool UserManager::initializeDatabase() {
|
std::string dbFilePath = getDatabaseFilePath();
|
if (!m_pDB->connect(dbFilePath, true)) {
|
throw std::runtime_error("Failed to connect to database.");
|
}
|
|
std::string createTableQuery = R"(
|
CREATE TABLE IF NOT EXISTS users (
|
username VARCHAR(50) PRIMARY KEY,
|
password VARCHAR(255) NOT NULL,
|
role INT NOT NULL,
|
session_timeout INT DEFAULT 30,
|
session_expiration INT DEFAULT 72,
|
last_login TIMESTAMP
|
)
|
)";
|
m_pDB->executeQuery(createTableQuery);
|
|
std::string checkAdminQuery = "SELECT COUNT(*) FROM users WHERE role = 0";
|
auto result = m_pDB->fetchResults(checkAdminQuery);
|
|
if (result.empty() || result[0][0] == "0") {
|
std::string insertAdminQuery = "INSERT INTO users (username, password, role, session_timeout, session_expiration) VALUES ('" +
|
INITIAL_ADMIN_USERNAME + "', '" + simpleEncryptDecrypt(INITIAL_ADMIN_PASSWORD, "BandKey") + "', 0, 30, 72)";
|
m_pDB->executeQuery(insertAdminQuery);
|
}
|
|
return true;
|
}
|
|
// ¶ÔÃÜÂë½øÐйþÏ£´¦Àí
|
std::string UserManager::hashPassword(const std::string& password) {
|
return std::to_string(std::hash<std::string>{}(password));
|
}
|
|
// ¼òµ¥µÄ¼ÓÃܺͽâÃܺ¯Êý
|
std::string UserManager::simpleEncryptDecrypt(const std::string& data, const std::string& key) {
|
std::string result = data;
|
for (size_t i = 0; i < data.size(); ++i) {
|
result[i] ^= key[i % key.size()]; // ¼òµ¥Òì»ò¼ÓÃÜ
|
}
|
return result;
|
}
|
|
// ´Ó»á»°Îļþ¼ÓÔØ»á»°ÐÅÏ¢
|
bool UserManager::loadSession() {
|
std::ifstream sessionFile(getSessionFilePath(), std::ios::binary);
|
if (!sessionFile.is_open()) {
|
return false;
|
}
|
|
// ´ÓÎļþ¶ÁÈ¡¼ÓÃÜÊý¾Ý
|
std::string encryptedData((std::istreambuf_iterator<char>(sessionFile)), std::istreambuf_iterator<char>());
|
sessionFile.close();
|
|
// ½âÃÜÊý¾Ý
|
std::string decryptedData = simpleEncryptDecrypt(encryptedData, "my_secret_key");
|
|
// ½âÎö½âÃܵÄÊý¾Ý
|
std::istringstream sessionData(decryptedData);
|
std::string username;
|
std::string password;
|
std::time_t lastLoginTime;
|
int timeoutMinutes;
|
int expirationHours;
|
|
sessionData >> username >> password >> lastLoginTime >> timeoutMinutes >> expirationHours;
|
|
// Ñé֤ʱ¼ä´ÁÓÐЧÐÔ
|
auto now = std::chrono::system_clock::now();
|
auto lastLogin = std::chrono::system_clock::from_time_t(lastLoginTime);
|
auto sessionDuration = std::chrono::duration_cast<std::chrono::hours>(now - lastLogin);
|
|
if (sessionDuration > std::chrono::hours(expirationHours)) {
|
clearSession();
|
return false;
|
}
|
|
// »Ö¸´»á»°Êý¾Ý
|
m_strCurrentUser = username;
|
m_strCurrentPass = password;
|
m_tpLastLogin = lastLogin;
|
m_tmSessionTimeout = std::chrono::minutes(timeoutMinutes);
|
m_tmSessionExpiration = std::chrono::hours(expirationHours);
|
m_isLoggedIn = true;
|
m_isRememberMe = true;
|
updateActivityTime();
|
|
return true;
|
}
|
|
// ±£´æ»á»°ÐÅÏ¢µ½Îļþ
|
void UserManager::saveSession() {
|
if (!m_isRememberMe) {
|
clearSession();
|
return;
|
}
|
|
// Ôʼ»á»°Êý¾Ý
|
std::stringstream sessionData;
|
std::time_t lastLoginTime = std::chrono::system_clock::to_time_t(m_tpLastLogin);
|
sessionData << m_strCurrentUser << " " << m_strCurrentPass << " " << lastLoginTime << " "
|
<< m_tmSessionTimeout.count() << " " << m_tmSessionExpiration.count();
|
|
// ¼ÓÃÜÊý¾Ý
|
std::string encryptedData = simpleEncryptDecrypt(sessionData.str(), "my_secret_key");
|
|
// дÈë¼ÓÃÜÊý¾Ýµ½Îļþ
|
std::ofstream sessionFile(getSessionFilePath(), std::ios::binary);
|
if (sessionFile.is_open()) {
|
sessionFile << encryptedData;
|
sessionFile.close();
|
}
|
}
|
|
// Çå³ý»á»°Îļþ
|
void UserManager::clearSession() {
|
std::remove(getSessionFilePath().c_str());
|
}
|
|
// »ñÈ¡³ÌÐò·¾¶ÏµÄconfigÎļþ¼Ð·¾¶
|
std::string UserManager::getConfigFolderPath() {
|
char path[MAX_PATH];
|
GetModuleFileName(NULL, path, MAX_PATH);
|
std::string exePath = std::string(path).substr(0, std::string(path).find_last_of("\\/"));
|
std::string configPath = exePath + "\\Config\\";
|
|
// ¼ì²é²¢´´½¨configÎļþ¼Ð
|
DWORD fileAttr = GetFileAttributes(configPath.c_str());
|
if (fileAttr == INVALID_FILE_ATTRIBUTES) {
|
CreateDirectory(configPath.c_str(), NULL);
|
}
|
|
return configPath;
|
}
|
|
// »ñÈ¡session.datÎļþ·¾¶
|
std::string UserManager::getSessionFilePath() {
|
return getConfigFolderPath() + SESSION_FILE;
|
}
|
|
// »ñÈ¡Êý¾Ý¿âÎļþ·¾¶
|
std::string UserManager::getDatabaseFilePath() {
|
return getConfigFolderPath() + DATABASE_FILE;
|
}
|
|
// µÇ¼·½·¨
|
bool UserManager::login(const std::string& username, const std::string& password, bool rememberMeFlag) {
|
std::string query = "SELECT username, password, role, session_timeout, session_expiration FROM users WHERE username = '" + username + "'";
|
auto result = m_pDB->fetchResults(query);
|
|
if (result.empty() || result[0][1] != simpleEncryptDecrypt(password, "BandKey")) {
|
std::cerr << "Login failed: Invalid username or password." << std::endl;
|
return false;
|
}
|
|
m_strCurrentUser = username;
|
m_strCurrentPass = password;
|
m_enCurrentUserRole = static_cast<UserRole>(std::stoi(result[0][2]));
|
m_tmSessionTimeout = std::chrono::minutes(std::stoi(result[0][3]));
|
m_tmSessionExpiration = std::chrono::hours(std::stoi(result[0][4]));
|
m_isLoggedIn = true;
|
m_isRememberMe = rememberMeFlag;
|
updateActivityTime();
|
m_tpLastLogin = std::chrono::system_clock::now();
|
|
std::string updateLoginTime = "UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE username = '" + username + "'";
|
m_pDB->executeQuery(updateLoginTime);
|
|
saveSession();
|
return true;
|
}
|
|
// µÇ³ö·½·¨
|
void UserManager::logout() {
|
if (m_isLoggedIn) {
|
std::cout << "User logged out: " << m_strCurrentUser << std::endl;
|
m_strCurrentUser.clear();
|
m_strCurrentPass.clear();
|
m_isLoggedIn = false;
|
m_isRememberMe = false;
|
clearSession();
|
}
|
}
|
|
// ·µ»Øµ±Ç°Óû§µÄµÇ¼״̬
|
bool UserManager::isLoggedIn() const {
|
return m_isLoggedIn;
|
}
|
|
// ·µ»Øµ±Ç°Óû§µÄ¼ÇסµÇ¼״̬
|
bool UserManager::isRememberMe() const {
|
return m_isRememberMe;
|
}
|
|
// ´´½¨ÐÂÓû§£¬½ö³¬¼¶¹ÜÀíÔ±ÓÐȨÏÞ
|
bool UserManager::createUser(const std::string& username, const std::string& password, UserRole role,
|
std::chrono::minutes timeout, std::chrono::hours expiration) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can create new users." << std::endl;
|
return false;
|
}
|
|
std::string query = "INSERT INTO users (username, password, role, session_timeout, session_expiration) VALUES ('" +
|
username + "', '" + simpleEncryptDecrypt(password, "BandKey") + "', " + std::to_string(static_cast<int>(role)) + ", " +
|
std::to_string(timeout.count()) + ", " + std::to_string(expiration.count()) + ")";
|
return m_pDB->executeQuery(query);
|
}
|
|
// ɾ³ýÓû§£¬½ö³¬¼¶¹ÜÀíÔ±ÓÐȨÏÞ£¬ÇÒ²»ÄÜɾ³ý×Ô¼º
|
bool UserManager::deleteUser(const std::string& username) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can delete users." << std::endl;
|
return false;
|
}
|
if (username == m_strCurrentUser) {
|
std::cerr << "SuperAdmin cannot delete their own account." << std::endl;
|
return false;
|
}
|
|
std::string query = "DELETE FROM users WHERE username = '" + username + "'";
|
return m_pDB->executeQuery(query);
|
}
|
|
// »ñÈ¡ËùÓÐÓû§ÐÅÏ¢£¬½ö³¬¼¶¹ÜÀíÔ±ÓÐȨÏÞ
|
std::vector<std::vector<std::string>> UserManager::getUsers() {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can retrieve user data." << std::endl;
|
return {};
|
}
|
|
// ²éѯÕû¸öÓû§±í
|
std::string query = "SELECT username, password, role, session_timeout, session_expiration, last_login FROM users";
|
std::vector<std::vector<std::string>> results = m_pDB->fetchResults(query);
|
for (auto& row : results) {
|
row[1] = simpleEncryptDecrypt(row[1], "BandKey");
|
}
|
|
return results;
|
}
|
|
// ÉèÖÃÕû¸öÓû§±íµÄÊý¾Ý£¬½ö³¬¼¶¹ÜÀíÔ±ÓÐȨÏÞ
|
bool UserManager::setUsers(const std::vector<std::vector<std::string>>& usersData) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can set user data." << std::endl;
|
return false;
|
}
|
|
// Çå¿ÕÓû§±í
|
std::string deleteQuery = "DELETE FROM users";
|
if (!m_pDB->executeQuery(deleteQuery)) {
|
std::cerr << "Failed to clear the users table." << std::endl;
|
return false;
|
}
|
|
// ²åÈëеÄÓû§Êý¾Ý
|
for (const auto& user : usersData) {
|
if (user.size() != 6) {
|
std::cerr << "Invalid data format for user. Each user must have 6 fields." << std::endl;
|
return false;
|
}
|
|
std::string insertQuery = "INSERT INTO users (username, password, role, session_timeout, session_expiration, last_login) VALUES ('" +
|
user[0] + "', '" + simpleEncryptDecrypt(user[1], "BandKey") + "', " + user[2] + ", " + user[3] + ", " + user[4] + ", '" + user[5] + "')";
|
|
if (!m_pDB->executeQuery(insertQuery)) {
|
std::cerr << "Failed to insert user: " << user[0] << std::endl;
|
return false;
|
}
|
}
|
|
return true;
|
}
|
|
// ÐÞ¸ÄÓû§Ãû£¬½ö³¬¼¶¹ÜÀíÔ±ÓÐȨÏÞ
|
bool UserManager::changeUsername(const std::string& username, const std::string& newUsername) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can change usernames." << std::endl;
|
return false;
|
}
|
|
std::string query = "UPDATE users SET username = '" + newUsername + "' WHERE username = '" + username + "'";
|
bool success = m_pDB->executeQuery(query);
|
|
// Èç¹ûÊǵ±Ç°µÇ¼Óû§ÐÞ¸Ä×Ô¼ºµÄÓû§Ãû£¬¸üгÉÔ±±äÁ¿²¢±£´æ»á»°Îļþ
|
if (success && m_strCurrentUser == username) {
|
m_strCurrentUser = newUsername;
|
|
// Èç¹û¡°¼ÇסÃÜÂ롱ÒÑÆôÓ㬸üлỰÎļþ
|
if (m_isRememberMe) {
|
saveSession();
|
}
|
}
|
return success;
|
}
|
|
// ÐÞ¸ÄÓû§ÃÜÂ루½öÔÊÐíµ±Ç°Óû§»ò³¬¼¶¹ÜÀíÔ±£©
|
bool UserManager::changePassword(const std::string& username, const std::string& newPassword) {
|
if (username != m_strCurrentUser && m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Permission denied: Only the user or SuperAdmin can change passwords." << std::endl;
|
return false;
|
}
|
|
std::string query = "UPDATE users SET password = '" + simpleEncryptDecrypt(newPassword, "BandKey") +
|
"' WHERE username = '" + username + "'";
|
bool success = m_pDB->executeQuery(query);
|
|
// Èç¹ûÊǵ±Ç°Óû§ÐÞ¸Ä×Ô¼ºµÄÃÜÂ룬Í˳öµÇ¼²¢Çå³ý»á»°Îļþ
|
if (success && m_strCurrentUser == username) {
|
logout();
|
std::cout << "Password changed successfully. Please log in again." << std::endl;
|
}
|
|
return success;
|
}
|
|
// ¸ü¸ÄÓû§½ÇÉ«£¬½ö³¬¼¶¹ÜÀíÔ±ÓÐȨÏÞ
|
bool UserManager::changeUserRole(const std::string& username, UserRole newRole) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can change user roles." << std::endl;
|
return false;
|
}
|
|
// ·ÀÖ¹¹ÜÀíÔ±¸ü¸Ä×Ô¼ºµÄ½ÇÉ«
|
if (m_strCurrentUser == username) {
|
std::cerr << "SuperAdmin cannot change their own role." << std::endl;
|
return false;
|
}
|
|
std::string query = "UPDATE users SET role = " + std::to_string(static_cast<int>(newRole)) +
|
" WHERE username = '" + username + "'";
|
return m_pDB->executeQuery(query);
|
}
|
|
// ÐÞ¸ÄÓû§µÄ session_timeout£¬½ö³¬¼¶¹ÜÀíÔ±ÓÐȨÏÞ
|
bool UserManager::changeUserSessionTimeout(const std::string& username, int newTimeoutMinutes) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can change session timeout." << std::endl;
|
return false;
|
}
|
|
std::string query = "UPDATE users SET session_timeout = " + std::to_string(newTimeoutMinutes) +
|
" WHERE username = '" + username + "'";
|
bool success = m_pDB->executeQuery(query);
|
// Èç¹ûÊǵ±Ç°µÇ¼Óû§ÐÞ¸Ä×Ô¼ºµÄ³¬Ê±ÉèÖ㬸üгÉÔ±±äÁ¿
|
if (success && m_strCurrentUser == username) {
|
m_tmSessionTimeout = std::chrono::minutes(newTimeoutMinutes);
|
|
if (m_isRememberMe) {
|
saveSession();
|
}
|
}
|
return success;
|
}
|
|
// ÐÞ¸ÄÓû§µÄ session_expiration£¬½ö³¬¼¶¹ÜÀíÔ±ÓÐȨÏÞ
|
bool UserManager::changeUserSessionExpiration(const std::string& username, int newExpirationHours) {
|
if (m_enCurrentUserRole != UserRole::SuperAdmin) {
|
std::cerr << "Only SuperAdmin can change session expiration." << std::endl;
|
return false;
|
}
|
|
std::string query = "UPDATE users SET session_expiration = " + std::to_string(newExpirationHours) +
|
" WHERE username = '" + username + "'";
|
bool success = m_pDB->executeQuery(query);
|
// Èç¹ûÊǵ±Ç°µÇ¼Óû§ÐÞ¸Ä×Ô¼ºµÄ¹ýÆÚÉèÖ㬸üгÉÔ±±äÁ¿
|
if (success && m_strCurrentUser == username) {
|
m_tmSessionExpiration = std::chrono::hours(newExpirationHours);
|
|
if (m_isRememberMe) {
|
saveSession();
|
}
|
}
|
return success;
|
}
|
|
// ¸üÐÂ×îºó»î¶¯Ê±¼ä£¬ÓÃÓÚÎÞ²Ù×÷³¬Ê±¼ì²â
|
void UserManager::updateActivityTime() {
|
m_tpLastActivity = std::chrono::system_clock::now();
|
std::cout << "Activity updated at: " << std::chrono::system_clock::to_time_t(m_tpLastActivity) << std::endl;
|
}
|
|
// ÉèÖÃÎÞ²Ù×÷³¬Ê±Ê±¼ä
|
void UserManager::setSessionTimeout(std::chrono::minutes timeout) {
|
m_tmSessionTimeout = timeout;
|
}
|
|
// ¼ì²éÊÇ·ñ³¬¹ýÎÞ²Ù×÷³¬Ê±Ê±¼ä
|
bool UserManager::isInactiveTimeout() const {
|
auto now = std::chrono::system_clock::now();
|
auto elapsedSeconds = std::chrono::duration_cast<std::chrono::seconds>(now - m_tpLastActivity).count();
|
return elapsedSeconds > m_tmSessionTimeout.count() * 60;
|
}
|
|
// ³õʼ»¯ÎÞ²Ù×÷¼ì²â£¬°üÀ¨ÉèÖÃÈ«¾ÖÊó±êºÍ¼üÅ̹³×Ó
|
void UserManager::initializeIdleDetection(HWND hwnd) {
|
updateActivityTime();
|
m_hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, (HINSTANCE) nullptr, 0);
|
m_hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, (HINSTANCE) nullptr, 0);
|
::SetTimer(hwnd, 1, 60000, nullptr);
|
}
|
|
// ÖÕÖ¹ÎÞ²Ù×÷¼ì²â£¬Çå³ýÊó±êºÍ¼üÅ̹³×Ó
|
void UserManager::terminateIdleDetection() {
|
if (m_hMouseHook) {
|
UnhookWindowsHookEx(m_hMouseHook);
|
m_hMouseHook = nullptr;
|
}
|
if (m_hKeyboardHook) {
|
UnhookWindowsHookEx(m_hKeyboardHook);
|
m_hKeyboardHook = nullptr;
|
}
|
::KillTimer(nullptr, 1);
|
}
|
|
// »ñÈ¡µ±Ç°µÇ¼Óû§Ãû
|
std::string UserManager::getCurrentUser() const {
|
return m_strCurrentUser;
|
}
|
|
// Ð޸ĵ±Ç°µÇ¼Óû§Ãû
|
void UserManager::setCurrentUser(const std::string& strName) {
|
m_strCurrentUser = strName;
|
}
|
|
// »ñÈ¡µ±Ç°µÇ¼Óû§ÃÜÂë
|
std::string UserManager::getCurrentPass() const {
|
return m_strCurrentPass;
|
}
|
|
// Ð޸ĵ±Ç°µÇ¼Óû§ÃÜÂë
|
void UserManager::setCurrentPass(const std::string& strPass) {
|
m_strCurrentPass = strPass;
|
}
|
|
// »ñÈ¡µ±Ç°µÇ¼Óû§½ÇÉ«
|
UserRole UserManager::getCurrentUserRole() const {
|
return m_enCurrentUserRole;
|
}
|
|
// Ð޸ĵ±Ç°µÇ¼Óû§½ÇÉ«
|
void UserManager::setCurrentUserRole(UserRole emRole) {
|
m_enCurrentUserRole = emRole;
|
}
|
|
// »ñÈ¡µ±Ç°µÇ¼Óû§µÄÎÞ²Ù×÷³¬Ê±Ê±¼ä
|
std::chrono::minutes UserManager::getSessionTimeout() const {
|
return m_tmSessionTimeout;
|
}
|
|
// »ñÈ¡µ±Ç°µÇ¼Óû§µÄ»á»°¹ýÆÚʱ¼ä
|
std::chrono::hours UserManager::getSessionExpiration() const {
|
return m_tmSessionExpiration;
|
}
|
|
// È«¾ÖÊó±ê¹³×ӻص÷£¬¼Ç¼»î¶¯Ê±¼ä
|
LRESULT CALLBACK UserManager::LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
|
if (nCode == HC_ACTION) {
|
UserManager::getInstance().updateActivityTime();
|
std::cout << "Mouse event detected. Activity time updated." << std::endl;
|
}
|
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
}
|
|
// È«¾Ö¼üÅ̹³×ӻص÷£¬¼Ç¼»î¶¯Ê±¼ä
|
LRESULT CALLBACK UserManager::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
|
if (nCode == HC_ACTION) {
|
UserManager::getInstance().updateActivityTime();
|
std::cout << "Keyboard event detected. Activity time updated." << std::endl;
|
}
|
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
}
|