Improve master authorization logs and web remote desktop cursor

This commit is contained in:
yuanyuanxiang
2026-05-04 14:02:35 +02:00
parent 92f3df8464
commit 773c78ac0f
16 changed files with 248 additions and 122 deletions

Binary file not shown.

View File

@@ -176,9 +176,9 @@ bool SupportsFileTransferV2(context* ctx) {
}
// 授权日志频率控制:首次必须记录,状态变化必须记录,相同状态每小时记录一次
static bool ShouldLogAuth(const std::string& sn, bool success) {
static bool ShouldLogAuth(const std::string& sn, int success) {
struct AuthLogState {
bool lastStatus;
int lastStatus;
time_t lastLogTime;
};
static std::map<std::string, AuthLogState> s_cache;
@@ -4526,12 +4526,12 @@ bool IsDateInRange(const std::string& startDate, const std::string& endDate)
return (today >= startDate && today <= endDate);
}
BOOL CMy2015RemoteDlg::AuthorizeClient(context* ctx, const std::string& sn, const std::string& passcode, uint64_t hmac, bool* outExpired)
int CMy2015RemoteDlg::AuthorizeClient(context* ctx, const std::string& sn, const std::string& passcode, uint64_t hmac, bool* outExpired)
{
if (outExpired) *outExpired = false;
if (sn.empty() || passcode.empty() || hmac == 0) {
return FALSE;
return 1;
}
auto v = splitString(passcode, '-');
if (v.size() == 6 || v.size() == 7) {
@@ -4541,7 +4541,7 @@ BOOL CMy2015RemoteDlg::AuthorizeClient(context* ctx, const std::string& sn, cons
std::string hash256 = joinString(subvector, '-');
std::string fixedKey = getFixedLengthID(finalKey);
if (hash256 != fixedKey)
return FALSE;
return 2;
}
static const char* superAdmin = getenv(BRAND_ENV_VAR);
@@ -4550,14 +4550,13 @@ BOOL CMy2015RemoteDlg::AuthorizeClient(context* ctx, const std::string& sn, cons
Mprintf("请设置环境变量 " BRAND_ENV_VAR " 来给下级授权!\n");
}
BOOL b = VerifyMessage(pwd, (BYTE*)passcode.c_str(), passcode.length(), hmac);
if (!b) return FALSE;
if (!b) return 3;
auto list = StringToVector(passcode, '-', 2);
BOOL valid = IsDateInRange(list[0], list[1]);
std::string hmacStr = std::to_string(hmac);
// 授权过期,更新或创建记录并标记为过期
if (!valid) {
Mprintf("授权已过期: %s\n", sn.c_str());
if (outExpired) *outExpired = true; // 签名有效但已过期
if (ctx != nullptr) {
std::string ip = ctx->GetClientData(ONLINELIST_IP);
@@ -4568,13 +4567,12 @@ BOOL CMy2015RemoteDlg::AuthorizeClient(context* ctx, const std::string& sn, cons
UpdateLicenseActivity(sn, passcode, hmacStr);
}
SetLicenseStatus(sn, LICENSE_STATUS_EXPIRED);
return FALSE;
return 4;
}
// 检查授权是否已被撤销
if (IsLicenseRevoked(sn)) {
Mprintf("授权已被撤销: %s\n", sn.c_str());
return FALSE;
return 5;
}
// 授权成功时更新 license 活跃信息
@@ -4587,21 +4585,20 @@ BOOL CMy2015RemoteDlg::AuthorizeClient(context* ctx, const std::string& sn, cons
UpdateLicenseActivity(sn, passcode, hmacStr);
}
return TRUE;
return 0;
}
BOOL CMy2015RemoteDlg::AuthorizeClientV2(context* ctx, const std::string& sn, const std::string& passcode, const std::string& hmacV2, bool* outExpired)
int CMy2015RemoteDlg::AuthorizeClientV2(context* ctx, const std::string& sn, const std::string& passcode, const std::string& hmacV2, bool* outExpired)
{
if (outExpired) *outExpired = false;
if (sn.empty() || passcode.empty() || hmacV2.empty()) {
return FALSE;
return 1;
}
// 检查 V2 前缀
if (hmacV2.substr(0, 3) != "v2:") {
Mprintf("V2 HMAC 格式错误: %s\n", hmacV2.c_str());
return FALSE;
return 2;
}
// 检查公钥是否已配置(全零表示未配置)
@@ -4613,15 +4610,13 @@ BOOL CMy2015RemoteDlg::AuthorizeClientV2(context* ctx, const std::string& sn, co
}
}
if (!keyConfigured) {
Mprintf("V2 公钥未配置,无法验证 V2 授权\n");
return FALSE;
return 3;
}
// 使用 V2 验证
BOOL b = verifyPasswordV2(sn, passcode, hmacV2, g_LicensePublicKey);
if (!b) {
Mprintf("V2 签名验证失败: %s\n", sn.c_str());
return FALSE;
return 4;
}
auto list = StringToVector(passcode, '-', 2);
@@ -4629,7 +4624,6 @@ BOOL CMy2015RemoteDlg::AuthorizeClientV2(context* ctx, const std::string& sn, co
// 授权过期
if (!valid) {
Mprintf("V2 授权已过期: %s\n", sn.c_str());
if (outExpired) *outExpired = true; // 签名有效但已过期
if (ctx != nullptr) {
std::string ip = ctx->GetClientData(ONLINELIST_IP);
@@ -4640,13 +4634,12 @@ BOOL CMy2015RemoteDlg::AuthorizeClientV2(context* ctx, const std::string& sn, co
UpdateLicenseActivity(sn, passcode, hmacV2);
}
SetLicenseStatus(sn, LICENSE_STATUS_EXPIRED);
return FALSE;
return 5;
}
// 检查授权是否已被撤销
if (IsLicenseRevoked(sn)) {
Mprintf("V2 授权已被撤销: %s\n", sn.c_str());
return FALSE;
return 6;
}
// 授权成功时更新 license 活跃信息
@@ -4659,7 +4652,7 @@ BOOL CMy2015RemoteDlg::AuthorizeClientV2(context* ctx, const std::string& sn, co
UpdateLicenseActivity(sn, passcode, hmacV2);
}
return TRUE;
return 0;
}
BOOL IsTrail(const std::string& passcode)
@@ -5785,7 +5778,7 @@ std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* h
const std::string& sn, const std::string& passcode, uint64_t hmac,
const std::string& hmacV2, const std::string& ip, const char* source)
{
bool authorized = false;
BOOL authorized = -1;
bool isV2 = false;
bool isTrail = false;
bool expired = false;
@@ -5794,19 +5787,19 @@ std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* h
// V2 授权验证
isV2 = true;
authorized = AuthorizeClientV2(host, sn, passcode, hmacV2, &expired);
if (authorized) {
if (authorized == 0) {
if (host) {
m_ClientMap->SetClientMapInteger(host->GetClientID(), MAP_AUTH, TRUE);
}
isTrail = IsTrail(passcode.c_str());
}
if (ShouldLogAuth(sn, authorized)) {
if (authorized) {
if (authorized == 0) {
Mprintf("[%s] %s V2 授权成功: %s [%s]\n", source, passcode.c_str(), 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);
} else {
Mprintf("[%s] %s V2 授权失败: %s [%s]\n", source, passcode.c_str(), sn.c_str(), ip.c_str());
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);
}
@@ -5815,26 +5808,26 @@ std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* h
// V1 授权验证
isV2 = false;
authorized = AuthorizeClient(host, sn, passcode, hmac, &expired);
if (authorized) {
if (authorized == 0) {
if (host) {
m_ClientMap->SetClientMapInteger(host->GetClientID(), MAP_AUTH, TRUE);
}
isTrail = IsTrail(passcode.c_str());
}
if (ShouldLogAuth(sn, authorized)) {
if (authorized) {
if (authorized == 0) {
Mprintf("[%s] %s V1 授权成功: %s [%s]\n", source, passcode.c_str(), 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);
} else {
Mprintf("[%s] %s V1 授权失败: %s [%s]\n", source, passcode.c_str(), sn.c_str(), ip.c_str());
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);
}
}
}
return std::make_tuple(authorized, isV2, isTrail, expired);
return std::make_tuple(authorized==0, isV2, isTrail, expired);
}
// 检查并发送预设续期(多点验证)
@@ -8609,6 +8602,22 @@ context* CMy2015RemoteDlg::FindHostByIP(const std::string& ip)
return NULL;
}
uint64_t CMy2015RemoteDlg::FindClientIDByIP(const std::string& ip)
{
CString clientIP(ip.c_str());
uint64_t clientID = 0;
EnterCriticalSection(&m_cs);
for (auto i = m_HostList.begin(); i != m_HostList.end(); ++i) {
context* ContextObject = *i;
if (ContextObject->GetClientData(ONLINELIST_IP) == clientIP || ContextObject->GetAdditionalData(RES_CLIENT_PUBIP) == clientIP) {
clientID = ContextObject->GetClientID();
break;
}
}
LeaveCriticalSection(&m_cs);
return clientID;
}
LRESULT CMy2015RemoteDlg::InjectShellcode(WPARAM wParam, LPARAM lParam)
{
std::string* ip = (std::string*)wParam;

View File

@@ -215,8 +215,8 @@ public:
MasterSettings m_settings;
static BOOL CALLBACK NotifyProc(CONTEXT_OBJECT* ContextObject);
static BOOL CALLBACK OfflineProc(CONTEXT_OBJECT* ContextObject);
BOOL AuthorizeClient(context* ctx, const std::string& sn, const std::string& passcode, uint64_t hmac, bool* outExpired = nullptr);
BOOL AuthorizeClientV2(context* ctx, const std::string& sn, const std::string& passcode, const std::string& hmacV2, bool* outExpired = nullptr);
int AuthorizeClient(context* ctx, const std::string& sn, const std::string& passcode, uint64_t hmac, bool* outExpired = nullptr);
int AuthorizeClientV2(context* ctx, const std::string& sn, const std::string& passcode, const std::string& hmacV2, bool* outExpired = nullptr);
VOID MessageHandle(CONTEXT_OBJECT* ContextObject);
VOID SendSelectedCommand(PBYTE szBuffer, ULONG ulLength, contextModifier cb = NULL, void* user=NULL);
VOID SendAllCommand(PBYTE szBuffer, ULONG ulLength);
@@ -255,6 +255,7 @@ public:
CGridDialog * m_gridDlg = NULL;
std::vector<DllInfo*> m_DllList;
context* FindHostByIP(const std::string& ip);
uint64_t FindClientIDByIP(const std::string& ip); // 线程安全在锁内获取ID
void InjectTinyRunDll(const std::string& ip, int pid);
NOTIFYICONDATA m_Nid;
HANDLE m_hExit;

View File

@@ -25,6 +25,26 @@ static UINT indicators[] = {
#define MAX_SEND_BUFFER 65535
#define MAX_RECV_BUFFER 65535
// 静态成员变量定义 - 历史路径记录
CString CFileManagerDlg::s_strLocalHistoryPath;
std::map<uint64_t, CString> CFileManagerDlg::s_mapRemoteHistoryPath;
CLock CFileManagerDlg::s_lockHistory;
// 获取有效的客户端ID优先用 m_ClientID否则通过 IP 找主连接
uint64_t CFileManagerDlg::GetClientID() const
{
// 优先使用已设置的 m_ClientID未来 TOKEN_CLIENTID 会设置这个)
if (m_ClientID != 0) {
return m_ClientID;
}
// 回退:通过 IP 找主连接获取 ClientID线程安全
if (g_2015RemoteDlg && m_ContextObject) {
std::string peerIP = m_ContextObject->GetPeerName();
return g_2015RemoteDlg->FindClientIDByIP(peerIP);
}
return 0;
}
typedef struct {
LVITEM* plvi;
CString sCol2;
@@ -137,10 +157,12 @@ BEGIN_MESSAGE_MAP(CFileManagerDlg, CDialog)
ON_COMMAND(IDT_LOCAL_DOWNLOADS, OnLocalDownloads)
ON_COMMAND(IDT_LOCAL_HOME, OnLocalHome)
ON_COMMAND(IDT_LOCAL_SEARCH, OnLocalSearch)
ON_COMMAND(IDT_LOCAL_HISTORY, OnLocalHistory)
ON_COMMAND(IDT_REMOTE_DESKTOP, OnRemoteDesktop)
ON_COMMAND(IDT_REMOTE_DOWNLOADS, OnRemoteDownloads)
ON_COMMAND(IDT_REMOTE_HOME, OnRemoteHome)
ON_COMMAND(IDT_REMOTE_SEARCH, OnRemoteSearch)
ON_COMMAND(IDT_REMOTE_HISTORY, OnRemoteHistory)
ON_COMMAND(IDM_TRANSFER, OnTransfer)
ON_COMMAND(IDM_RENAME, OnRename)
ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST_LOCAL, OnEndlabeleditListLocal)
@@ -494,6 +516,12 @@ void CFileManagerDlg::FixedLocalFileList(CString directory)
}
ShowMessage(_TRF("本地:装载目录 %s 完成"), m_Local_Path);
// 记录本地历史路径
if (m_Local_Path.GetLength() > 0) {
CAutoCLock lock(s_lockHistory);
s_strLocalHistoryPath = m_Local_Path;
}
}
void CFileManagerDlg::DropItemOnList(CListCtrl* pDragList, CListCtrl* pDropList)
@@ -966,6 +994,8 @@ void CFileManagerDlg::OnReceiveComplete()
ShowMessage(_TRF("搜索 \"%s\" 在 %s 完成,共 %d 个结果 (耗时 %d秒)"), m_strSearchName, m_strSearchPath, m_nSearchResultCount, dwElapsed);
}
break;
case TOKEN_CLIENTID:
break;
default:
SendException();
break;
@@ -1024,6 +1054,13 @@ void CFileManagerDlg::GetRemoteFileList(CString directory)
m_Remote_Directory_ComboBox.InsertStringL(0, m_Remote_Path);
m_Remote_Directory_ComboBox.SetCurSel(0);
// 记录远程历史路径按客户端ID区分
uint64_t clientID = GetClientID();
if (m_Remote_Path.GetLength() > 0 && clientID != 0) {
CAutoCLock lock(s_lockHistory);
s_mapRemoteHistoryPath[clientID] = m_Remote_Path;
}
// 得到返回数据前禁窗口
m_list_remote.EnableWindow(FALSE);
m_ProgressCtrl->SetPos(0);
@@ -1594,6 +1631,57 @@ void CFileManagerDlg::OnRemoteSearch()
}
}
void CFileManagerDlg::OnLocalHistory()
{
// 跳转到上次打开的本地文件夹
CString historyPath;
{
CAutoCLock lock(s_lockHistory);
historyPath = s_strLocalHistoryPath;
}
if (historyPath.IsEmpty()) {
ShowMessage(_TR("没有本地历史记录"));
return;
}
// 检查目录是否存在
if (GetFileAttributesA(historyPath) == INVALID_FILE_ATTRIBUTES) {
ShowMessage(_TRF("历史目录不存在: %s"), historyPath);
return;
}
m_Local_Path = historyPath;
FixedLocalFileList(".");
}
void CFileManagerDlg::OnRemoteHistory()
{
// 跳转到上次打开的远程文件夹按客户端ID区分
uint64_t clientID = GetClientID();
if (clientID == 0) {
ShowMessage(_TR("无法识别远程主机"));
return;
}
CString historyPath;
{
CAutoCLock lock(s_lockHistory);
auto it = s_mapRemoteHistoryPath.find(clientID);
if (it != s_mapRemoteHistoryPath.end()) {
historyPath = it->second;
}
}
if (historyPath.IsEmpty()) {
ShowMessage(_TR("没有远程历史记录"));
return;
}
m_Remote_Path = historyPath;
GetRemoteFileList(".");
}
void CFileManagerDlg::OnLocalView()
{
// TODO: Add your command handler code here

View File

@@ -7,6 +7,7 @@
#include "IOCPServer.h"
#include "SortListCtrl.h"
#include "../../common/locker.h"
#include <map>
#include <string>
#include <vector>
@@ -246,10 +247,12 @@ protected:
afx_msg void OnLocalDownloads();
afx_msg void OnLocalHome();
afx_msg void OnLocalSearch();
afx_msg void OnLocalHistory();
afx_msg void OnRemoteDesktop();
afx_msg void OnRemoteDownloads();
afx_msg void OnRemoteHome();
afx_msg void OnRemoteSearch();
afx_msg void OnRemoteHistory();
afx_msg void OnTransferV2ToRemote(); // V2: 本地文件传输到远程
afx_msg void OnTransferV2ToLocal(); // V2: 远程文件传输到本地
//}}AFX_MSG
@@ -274,6 +277,14 @@ private:
void EnableControl(BOOL bEnable = TRUE);
void CollectFilesRecursive(const std::string& dirPath, std::vector<std::string>& files);
float m_fScalingFactor;
// 历史路径记录(静态,跨实例共享)
static CString s_strLocalHistoryPath;
static std::map<uint64_t, CString> s_mapRemoteHistoryPath;
static CLock s_lockHistory; // 保护历史路径的锁
// 获取有效的客户端ID优先用 m_ClientID否则通过 IP 找主连接)
uint64_t GetClientID() const;
public:
afx_msg void OnFilemangerCompress();
afx_msg void OnFilemangerUncompress();

View File

@@ -228,7 +228,7 @@ public:
{
return m_bIsClosed;
}
uint64_t GetClientID() const {
virtual uint64_t GetClientID() const {
return m_ClientID;
}
BOOL SayByeBye()

View File

@@ -1846,13 +1846,15 @@ inline std::string GetWebPageHTML() {
// Remote cursor mapping (Windows cursor index -> CSS cursor)
// Index matches CursorInfo.h: IDC_APPSTARTING(0) to IDC_WAIT(15), 254=custom, 255=unsupported
// Custom I-beam cursor with white fill and black stroke for visibility on any background
const ibeamCursor = "url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"24\" viewBox=\"0 0 16 24\"><path fill=\"none\" stroke=\"white\" stroke-width=\"3\" d=\"M4 3h8M8 3v18M4 21h8\"/><path fill=\"none\" stroke=\"black\" stroke-width=\"1\" d=\"M4 3h8M8 3v18M4 21h8\"/></svg>') 8 12, text";
const cursorMap = [
'progress', // 0: IDC_APPSTARTING
'default', // 1: IDC_ARROW
'crosshair', // 2: IDC_CROSS
'pointer', // 3: IDC_HAND
'help', // 4: IDC_HELP
'text', // 5: IDC_IBEAM
ibeamCursor, // 5: IDC_IBEAM - custom cursor with outline
'default', // 6: IDC_ICON (no direct CSS equivalent)
'not-allowed', // 7: IDC_NO
'default', // 8: IDC_SIZE (deprecated, use default)

View File

@@ -1819,3 +1819,7 @@ IOCP
插件列表为空,无法创建触发器=Plugin list is empty, cannot create trigger
请先选择至少一个插件=Please select at least one plugin
没有本地历史记录=No local history
历史目录不存在: %s=History folder not exist: %s
无法识别远程主机=Unknown remote machine
没有远程历史记录=No remote history

View File

@@ -1810,3 +1810,7 @@ IOCP
<< 移除=<< 移除
插件列表为空,无法创建触发器=外掛列表為空,無法建立觸發器
请先选择至少一个插件=請先選擇至少一個外掛
没有本地历史记录=没有本地历史记录
历史目录不存在: %s=历史目录不存在: %s
无法识别远程主机=无法识别远程主机
没有远程历史记录=没有远程历史记录

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -506,6 +506,8 @@
#define IDT_REMOTE_DOWNLOADS 2235
#define IDT_REMOTE_HOME 2236
#define IDT_REMOTE_SEARCH 2237
#define IDT_LOCAL_HISTORY 2238
#define IDT_REMOTE_HISTORY 2239
#define IDC_BUTTON_SAVE_LICENSE 2240
#define IDC_LICENSE_LIST 2241
#define IDC_COMBO_VERSION 2245