Refactor: extract Linux/macOS client shared code into common

This commit is contained in:
yuanyuanxiang
2026-05-10 09:49:07 +02:00
parent 70354e244c
commit d46176f4ef
9 changed files with 443 additions and 424 deletions

103
common/client_auth_state.h Normal file
View File

@@ -0,0 +1,103 @@
// client_auth_state.h
// Linux/macOS 客户端服务端身份校验状态 + helperLayer 1 防护)。
//
// 行为模型:
// - g_loginMsgstartTime + "|" + clientID启动时填一次跨重连不变
// - g_loginTime每次新连接重置为当前时刻
// - g_settingsVerified服务端 CMD_MASTERSETTING 通过签名校验后置 true
// 重连时重置为 false
//
// 客户端是常驻服务——服务端可能频繁重启 / 长期离线 / 临时不可达,这些都不应
// 让进程退出。校验失败仅作"本次连接不可信"处理:断开本连接 + 让外层重连。
// 功能侧的安全由子连接 authTOKEN_CONN_AUTH兜底——没通过校验的服务端无法
// 触发任何 sub-connection 功能。
//
// 跨线程访问:
// - g_settingsVerified 在 DataProcessIO 线程写、心跳循环main 线程)读
// - 用 std::atomic<bool> + acquire/release 内存序保证可见性
//
// C++17 inline 变量保证多翻译单元共享同一实例,无 ODR 冲突。
#pragma once
#include <atomic>
#include <cstring>
#include <ctime>
#include <string>
#include "common/commands.h"
// 全局 namespace 中的 verifyMessage由 client/sign_shim_unix.cppLinux/macOS
// 私有 .libWindows提供。必须在任何 namespace 之外声明,否则会被解析成
// ClientAuth::verifyMessage 导致链接失败。
extern bool verifyMessage(const std::string& publicKey, BYTE* msg, int len,
const std::string& signature);
namespace ClientAuth {
// ============== 跨重连保留的状态 ==============
inline std::string g_loginMsg;
inline time_t g_loginTime = 0;
inline std::atomic<bool> g_settingsVerified{false};
// ============== Helpers ==============
// 进入新连接前调用g_loginTime = nowverified = false
inline void OnNewConnection()
{
g_loginTime = time(nullptr);
g_settingsVerified.store(false, std::memory_order_release);
}
// DataProcess 开头的 gate未通过校验前仅放行 CMD_MASTERSETTING校验本身
// 其它命令一律静默忽略——既防止未授权服务端 spawn 子连接线程做 DoS
// 也防止它发 COMMAND_BYE 之类把客户端进程关掉。
inline bool IsCommandAllowed(unsigned char cmd)
{
return g_settingsVerified.load(std::memory_order_acquire) || cmd == CMD_MASTERSETTING;
}
// 处理 CMD_MASTERSETTINGpayload = szBuffer + 1payloadLen = ulLength - 1
// 强制要求完整 MasterSettings包含 Signature 字段);不完整 / 签名失败 → 不更新
// g_settingsVerified让心跳循环 30s 超时自然把本次连接断开重连。
//
// 返回 true校验通过已 store(true)),通过 outReportInterval / outSettingsCopy
// 返回 settings 内容供调用方继续应用(更新心跳间隔、密码哈希等)
// 返回 false本次响应异常调用方应直接 return不要继续处理
//
// 注意:参数采用 unsigned char* 而非 BYTE* 避免依赖 Windows typedef
// BYTE 在 commands.h 已 typedef 为 unsigned char等价。
inline bool HandleMasterSettings(const unsigned char* payload, int payloadLen,
MasterSettings* outSettings)
{
if (payloadLen < (int)sizeof(MasterSettings)) {
return false;
}
MasterSettings settings = {};
std::memcpy(&settings, payload, sizeof(MasterSettings));
// 服务端身份校验:用 g_loginMsg (= szStartTime + "|" + clientID) 与 settings.Signature
// 验证签名。失败 → 不立即退出,让超时兜底+重连逻辑处理。
// 注意 ::verifyMessage 在全局 namespace见本头部 extern 声明),不能省略 :: 前缀,
// 否则会被解析为 ClientAuth::verifyMessage链接失败。
std::string sig((char*)settings.Signature,
(char*)settings.Signature + sizeof(settings.Signature));
if (!::verifyMessage("", (BYTE*)g_loginMsg.data(), (int)g_loginMsg.length(), sig)) {
return false;
}
g_settingsVerified.store(true, std::memory_order_release);
if (outSettings) *outSettings = settings;
return true;
}
// 心跳循环里检查 30s 超时:登录后 30 秒内必须收到并通过 MasterSettings 校验,
// 失败 → 调用方应显式断开本连接让外层重连。永不退出进程。
inline bool IsTimedOut()
{
return !g_settingsVerified.load(std::memory_order_acquire) &&
g_loginTime > 0 &&
time(nullptr) - g_loginTime > 30;
}
} // namespace ClientAuth