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:
yuanyuanxianganddeepseek-v4-pro committed 2026-10-06 17:50:30 +02:00
1 parent d269df9171
commit d80d8f21da
7 files changed
+110 -35

No files matched your search

+45 -3
View File
@@ -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());