Files
SimpleRemoter/common/client_auth_state.h

104 lines
4.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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