Feat: TLS certificate menu and config dialog for the MFC server

Add a "TLS证书" item to the Extensions menu below "MCP设置" that opens a
runtime-built dialog to enable one-way TLS and set the certificate and
private-key paths. On OK it writes the [tls] Enabled/CertPath/KeyPath keys
and calls ServerTlsIdentity::Load() so the change takes effect for new
connections immediately (design doc §7.1), mirroring the existing
CMcpSettingsDlg runtime-template pattern. All new strings are wired into
the en_US / zh_TW / de_DE language files, and the menu item is gated by
HIDE_MENU_TLS_CERTIFICATE / MF_TLS_CERTIFICATE like MCP settings.

Co-Authored-By: deepseek-v4-pro
This commit is contained in:
yuanyuanxianganddeepseek-v4-pro committed 2026-10-15 19:42:52 +02:00
1 parent 96b9eea70a
commit c93f09e9ac
12 files changed
+351 -2

No files matched your search

+28
View File
@@ -50,6 +50,7 @@
#include "CFileSpeedDlg.h" #include "CFileSpeedDlg.h"
#include "McpServer.h" #include "McpServer.h"
#include "McpSettingsDlg.h" #include "McpSettingsDlg.h"
#include "TlsCertificateDlg.h"
#include "common/md5.h" #include "common/md5.h"
#include <algorithm> #include <algorithm>
#include <set> #include <set>
@@ -1059,6 +1060,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx)
ON_COMMAND(ID_TOOL_RELOAD_PLUGINS, &CMy2015RemoteDlg::OnToolReloadPlugins) ON_COMMAND(ID_TOOL_RELOAD_PLUGINS, &CMy2015RemoteDlg::OnToolReloadPlugins)
ON_COMMAND(ID_TOOL_PLUGIN_SETTINGS, &CMy2015RemoteDlg::OnToolPluginSettings) ON_COMMAND(ID_TOOL_PLUGIN_SETTINGS, &CMy2015RemoteDlg::OnToolPluginSettings)
ON_COMMAND(ID_MCP_SETTINGS, &CMy2015RemoteDlg::OnMcpSettings) ON_COMMAND(ID_MCP_SETTINGS, &CMy2015RemoteDlg::OnMcpSettings)
ON_COMMAND(ID_TLS_CERTIFICATE, &CMy2015RemoteDlg::OnTlsCertificate)
ON_COMMAND(ID_CONNECTION_MANAGE, &CMy2015RemoteDlg::OnConnectionManage) ON_COMMAND(ID_CONNECTION_MANAGE, &CMy2015RemoteDlg::OnConnectionManage)
ON_COMMAND(ID_TALK_MANAGE, &CMy2015RemoteDlg::OnChat) ON_COMMAND(ID_TALK_MANAGE, &CMy2015RemoteDlg::OnChat)
ON_COMMAND(ID_MACHINE_MANAGE, &CMy2015RemoteDlg::OnMachineManager) ON_COMMAND(ID_MACHINE_MANAGE, &CMy2015RemoteDlg::OnMachineManager)
@@ -1323,6 +1325,17 @@ VOID CMy2015RemoteDlg::CreateSolidMenu()
ID_MCP_SETTINGS, _TR("MCP设置(&M)...")); ID_MCP_SETTINGS, _TR("MCP设置(&M)..."));
} }
// 动态插入「TLS证书」菜单项,位于「MCP设置」之后、「插件设置」之前(对同一锚点
// ID_TOOL_PLUGIN_SETTINGS 二次 InsertMenu,后插者更贴近锚点,故排在 MCP 下方)。
if (!SHOULD_HIDE_MENU(HIDE_MENU_TLS_CERTIFICATE, MF_TLS_CERTIFICATE)) {
UINT tlsFlags = MF_BYCOMMAND;
if (THIS_CFG.GetInt("tls", "Enabled", 0)) {
tlsFlags |= MF_CHECKED; // 已启用 TLS 则菜单打勾
}
pExtMenu->InsertMenu(ID_TOOL_PLUGIN_SETTINGS, tlsFlags,
ID_TLS_CERTIFICATE, _TR("TLS证书(&T)..."));
}
// 将 3 个插件相关菜单项收拢到「插件」二级菜单(位于「MCP设置」之下、原「插件设置」之前, // 将 3 个插件相关菜单项收拢到「插件」二级菜单(位于「MCP设置」之下、原「插件设置」之前,
// 顺序不变:插件设置 / 刷新插件 / 获取插件)。 // 顺序不变:插件设置 / 刷新插件 / 获取插件)。
// 注意:先删除顶层项、再按位置插入子菜单,避免同一命令 ID 同时存在于子菜单与顶层时, // 注意:先删除顶层项、再按位置插入子菜单,避免同一命令 ID 同时存在于子菜单与顶层时,
@@ -11558,6 +11571,21 @@ void CMy2015RemoteDlg::OnMcpSettings()
ApplyFrpSettings(); ApplyFrpSettings();
} }
void CMy2015RemoteDlg::OnTlsCertificate()
{
CTlsCertificateDlg dlg(this);
if (dlg.DoModal() != IDOK) return;
// 对话框内已写入 [tls] 三键并调 ServerTlsIdentity::Load(THIS_CFG) 热重载,
// 对新建连接即时生效(设计文档 §7.1)。
// 菜单在启动时只构建一次(CreateSolidMenu),勾选状态不会自动刷新,
// 这里同步「扩展」菜单上「TLS证书」的勾选,使其与 [tls] Enabled 一致。
if (CMenu* pExtMenu = m_MainMenu.GetSubMenu(3)) {
pExtMenu->CheckMenuItem(ID_TLS_CERTIFICATE, MF_BYCOMMAND |
(THIS_CFG.GetInt("tls", "Enabled", 0) ? MF_CHECKED : MF_UNCHECKED));
}
}
void CMy2015RemoteDlg::OnConnectionManage() void CMy2015RemoteDlg::OnConnectionManage()
{ {
BYTE cmd = COMMAND_CONNECTION; BYTE cmd = COMMAND_CONNECTION;
+1
View File
@@ -696,6 +696,7 @@ public:
afx_msg void OnCancelShare(); afx_msg void OnCancelShare();
afx_msg void OnWebRemoteControl(); afx_msg void OnWebRemoteControl();
afx_msg void OnMcpSettings(); afx_msg void OnMcpSettings();
afx_msg void OnTlsCertificate();
afx_msg void OnConnectionManage(); afx_msg void OnConnectionManage();
afx_msg void OnProxyPortAutorun(); afx_msg void OnProxyPortAutorun();
afx_msg void OnScreenpreviewLoop(); afx_msg void OnScreenpreviewLoop();
@@ -329,6 +329,7 @@
<ClInclude Include="LangManager.h" /> <ClInclude Include="LangManager.h" />
<ClInclude Include="McpServer.h" /> <ClInclude Include="McpServer.h" />
<ClInclude Include="McpSettingsDlg.h" /> <ClInclude Include="McpSettingsDlg.h" />
<ClInclude Include="TlsCertificateDlg.h" />
<ClInclude Include="NetworkDlg.h" /> <ClInclude Include="NetworkDlg.h" />
<ClInclude Include="NotifyConfig.h" /> <ClInclude Include="NotifyConfig.h" />
<ClInclude Include="NotifyManager.h" /> <ClInclude Include="NotifyManager.h" />
@@ -397,6 +398,7 @@
<ClCompile Include="HostJson.cpp" /> <ClCompile Include="HostJson.cpp" />
<ClCompile Include="McpServer.cpp" /> <ClCompile Include="McpServer.cpp" />
<ClCompile Include="McpSettingsDlg.cpp" /> <ClCompile Include="McpSettingsDlg.cpp" />
<ClCompile Include="TlsCertificateDlg.cpp" />
<ClCompile Include="..\..\client\MemoryModule.c"> <ClCompile Include="..\..\client\MemoryModule.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
@@ -90,6 +90,7 @@
<ClCompile Include="HostJson.cpp" /> <ClCompile Include="HostJson.cpp" />
<ClCompile Include="McpServer.cpp" /> <ClCompile Include="McpServer.cpp" />
<ClCompile Include="McpSettingsDlg.cpp" /> <ClCompile Include="McpSettingsDlg.cpp" />
<ClCompile Include="TlsCertificateDlg.cpp" />
<ClCompile Include="CClientLog.cpp" /> <ClCompile Include="CClientLog.cpp" />
<ClCompile Include="CActivityDialog.cpp" /> <ClCompile Include="CActivityDialog.cpp" />
<ClCompile Include="LogSearchBar.cpp" /> <ClCompile Include="LogSearchBar.cpp" />
@@ -203,6 +204,7 @@
<ClInclude Include="TriggerSettingsDlg.h" /> <ClInclude Include="TriggerSettingsDlg.h" />
<ClInclude Include="McpServer.h" /> <ClInclude Include="McpServer.h" />
<ClInclude Include="McpSettingsDlg.h" /> <ClInclude Include="McpSettingsDlg.h" />
<ClInclude Include="TlsCertificateDlg.h" />
<ClInclude Include="CClientLog.h" /> <ClInclude Include="CClientLog.h" />
<ClInclude Include="CActivityDialog.h" /> <ClInclude Include="CActivityDialog.h" />
<ClInclude Include="LogSearchBar.h" /> <ClInclude Include="LogSearchBar.h" />
+2 -1
View File
@@ -89,8 +89,9 @@ typedef struct FeatureFlags {
#define MF_REQUEST_AUTH (1ULL << 42) // HIDE_MENU_REQUEST_AUTH #define MF_REQUEST_AUTH (1ULL << 42) // HIDE_MENU_REQUEST_AUTH
#define MF_MCP_SETTINGS (1ULL << 43) // HIDE_MENU_MCP_SETTINGS #define MF_MCP_SETTINGS (1ULL << 43) // HIDE_MENU_MCP_SETTINGS
#define MF_TLS_CERTIFICATE (1ULL << 44) // HIDE_MENU_TLS_CERTIFICATE
// [44-63] Reserved // [45-63] Reserved
// ============================================================ // ============================================================
+234
View File
@@ -0,0 +1,234 @@
#include "stdafx.h"
#include "TlsCertificateDlg.h"
#include "LangManager.h" // _TR / MessageBoxL
#include "2015Remote.h" // THIS_CFG (GetThisCfg)
#include "ServerTlsSession.h" // ServerTlsIdentity::Load / IsLoadError
#include "common/iniFile.h" // config::GetInt/GetStr/SetInt/SetStr
#include <atlconv.h>
#include <afxdlgs.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
namespace {
// 构造一个无控件的 DLGTEMPLATE:cdit=0,控件由 OnInitDialog 动态创建。
// (与 McpSettingsDlg.cpp / ZstaPickerDlg.cpp 内同名函数一致)
void BuildDialogTemplate(std::vector<BYTE>& out, LPCWSTR caption, short cx, short cy)
{
out.clear();
auto append = [&](const void* p, size_t n) {
const BYTE* b = (const BYTE*)p;
out.insert(out.end(), b, b + n);
};
auto appendW = [&](WORD v) {
out.push_back((BYTE)(v & 0xFF));
out.push_back((BYTE)((v >> 8) & 0xFF));
};
auto appendWStr = [&](LPCWSTR s) {
size_t n = wcslen(s);
append(s, (n + 1) * sizeof(WCHAR));
};
DLGTEMPLATE dt = { 0 };
dt.style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER |
WS_POPUP | WS_CAPTION | WS_SYSMENU;
dt.dwExtendedStyle = 0;
dt.cdit = 0;
dt.x = 0; dt.y = 0;
dt.cx = cx; dt.cy = cy;
append(&dt, sizeof(dt));
appendW(0); // no menu
appendW(0); // default dialog class
appendWStr(caption); // caption
appendW(8); // font point size
appendWStr(L"MS Shell Dlg"); // typeface
while (out.size() % 4) out.push_back(0); // DWORD align
}
} // namespace
BEGIN_MESSAGE_MAP(CTlsCertificateDlg, CDialog)
ON_BN_CLICKED(IDC_TLS_CERT_BROWSE, &CTlsCertificateDlg::OnBrowseCert)
ON_BN_CLICKED(IDC_TLS_KEY_BROWSE, &CTlsCertificateDlg::OnBrowseKey)
END_MESSAGE_MAP()
CTlsCertificateDlg::CTlsCertificateDlg(CWnd* parent)
: CDialog((LPCTSTR)NULL, parent)
{
}
INT_PTR CTlsCertificateDlg::DoModal()
{
USES_CONVERSION;
CString title = _TR("TLS证书");
BuildDialogTemplate(m_Template, T2CW(title), 340, 180);
InitModalIndirect((LPCDLGTEMPLATE)m_Template.data());
return CDialog::DoModal();
}
BOOL CTlsCertificateDlg::OnInitDialog()
{
CDialog::OnInitDialog();
CRect cli;
GetClientRect(&cli);
// 占位 rect,真正布局在 LayoutControls 里
CRect r0(0, 0, 10, 10);
m_btnEnable.Create(_TR("启用加密"),
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTOCHECKBOX,
r0, this, IDC_TLS_ENABLE);
m_lblCert.Create(_TR("证书路径"), WS_CHILD | WS_VISIBLE, r0, this, (UINT)-1);
m_editCert.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,
r0, this, IDC_TLS_CERT);
m_btnCertBrowse.Create(_TR("浏览"), WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
r0, this, IDC_TLS_CERT_BROWSE);
m_lblKey.Create(_TR("私钥路径"), WS_CHILD | WS_VISIBLE, r0, this, (UINT)-1);
m_editKey.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,
r0, this, IDC_TLS_KEY);
m_btnKeyBrowse.Create(_TR("浏览"), WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
r0, this, IDC_TLS_KEY_BROWSE);
m_btnOK.Create(_TR("确定"), WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON,
r0, this, IDOK);
m_btnCancel.Create(_TR("取消"), WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
r0, this, IDCANCEL);
// 子控件继承对话框字体 (DS_SETFONT)
HFONT hFont = (HFONT)::SendMessage(GetSafeHwnd(), WM_GETFONT, 0, 0);
if (hFont) {
m_btnEnable.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
m_lblCert.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
m_editCert.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
m_btnCertBrowse.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
m_lblKey.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
m_editKey.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
m_btnKeyBrowse.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
m_btnOK.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
m_btnCancel.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
}
// 回填配置
int enabled = THIS_CFG.GetInt("tls", "Enabled", 0);
std::string cert = THIS_CFG.GetStr("tls", "CertPath", "");
std::string key = THIS_CFG.GetStr("tls", "KeyPath", "");
m_btnEnable.SetCheck(enabled ? BST_CHECKED : BST_UNCHECKED);
m_editCert.SetWindowText(CString(cert.c_str()));
m_editKey.SetWindowText(CString(key.c_str()));
LayoutControls(cli.Width(), cli.Height());
return TRUE;
}
void CTlsCertificateDlg::OnOK()
{
CString sCert, sKey;
m_editCert.GetWindowText(sCert);
m_editKey.GetWindowText(sKey);
bool enabled = (m_btnEnable.GetCheck() == BST_CHECKED);
std::string cert = CT2A(sCert);
std::string key = CT2A(sKey);
// 校验:启用加密时必须填写证书/私钥路径
if (enabled && cert.empty()) {
MessageBoxL("请填写证书路径", "提示", MB_ICONWARNING);
return;
}
if (enabled && key.empty()) {
MessageBoxL("请填写私钥路径", "提示", MB_ICONWARNING);
return;
}
// 落盘 [tls] 三键
THIS_CFG.SetInt("tls", "Enabled", enabled ? 1 : 0);
THIS_CFG.SetStr("tls", "CertPath", cert);
THIS_CFG.SetStr("tls", "KeyPath", key);
// 热重载身份(设计文档 §7.1):开关与证书/私钥路径对新建连接即时生效。
// 已知窄竞态:Load 内部 FreeIdentity 与「已取 Cred 副本、尚在握手」的连接存在竞态,
// 未来热切换需引用计数 + 惰性释放(见 ServerTlsSession.cpp FreeIdentity 注释),本次不做。
ServerTlsIdentity::Load(THIS_CFG);
if (ServerTlsIdentity::IsLoadError()) {
MessageBoxL("证书/私钥加载失败,加密功能未生效。请检查文件路径与格式(证书 PEM、私钥 PKCS#8)。",
"提示", MB_ICONWARNING);
} else {
MessageBox(_TR("TLS 配置已保存。") + _T("\r\n") +
_TR("改动对新建连接即时生效。"),
_TR("提示"), MB_ICONINFORMATION);
}
CDialog::OnOK();
}
void CTlsCertificateDlg::OnBrowseCert()
{
CFileDialog dlg(TRUE, _T("crt"), nullptr,
OFN_FILEMUSTEXIST | OFN_HIDEREADONLY,
_T("Certificate Files (*.crt;*.pem;*.cer;*.cert)|*.crt;*.pem;*.cer;*.cert|All Files (*.*)|*.*||"),
this);
dlg.m_ofn.lpstrTitle = _T("Select Certificate");
if (dlg.DoModal() == IDOK) {
m_editCert.SetWindowText(dlg.GetPathName());
}
}
void CTlsCertificateDlg::OnBrowseKey()
{
CFileDialog dlg(TRUE, _T("key"), nullptr,
OFN_FILEMUSTEXIST | OFN_HIDEREADONLY,
_T("Key Files (*.key;*.pem)|*.key;*.pem|All Files (*.*)|*.*||"),
this);
dlg.m_ofn.lpstrTitle = _T("Select Private Key");
if (dlg.DoModal() == IDOK) {
m_editKey.SetWindowText(dlg.GetPathName());
}
}
void CTlsCertificateDlg::LayoutControls(int cx, int cy)
{
const int margin = 14;
const int labelW = 72;
const int rowH = 24;
const int gap = 10;
const int browseW = 64;
const int btnW = 88;
const int btnH = 26;
int y = margin;
m_btnEnable.MoveWindow(margin, y, cx - margin * 2, 22);
y += 30;
int editW = cx - margin * 2 - labelW - browseW - gap;
m_lblCert.MoveWindow(margin, y, labelW, rowH);
m_editCert.MoveWindow(margin + labelW, y - 2, editW, rowH);
m_btnCertBrowse.MoveWindow(cx - margin - browseW, y - 2, browseW, rowH);
y += rowH + gap;
m_lblKey.MoveWindow(margin, y, labelW, rowH);
m_editKey.MoveWindow(margin + labelW, y - 2, editW, rowH);
m_btnKeyBrowse.MoveWindow(cx - margin - browseW, y - 2, browseW, rowH);
y += rowH + gap;
// 确定 / 取消按钮紧随私钥路径下方
m_btnCancel.MoveWindow(cx - margin - btnW, y, btnW, btnH);
m_btnOK.MoveWindow(cx - margin - btnW * 2 - gap, y, btnW, btnH);
y += btnH + margin;
// 收缩对话框到内容实际高度并重新居中,消除底部空白。
if (y < cy) {
CRect wnd;
GetWindowRect(&wnd);
SetWindowPos(NULL, 0, 0, wnd.Width(), y + (wnd.Height() - cy),
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
CenterWindow();
}
}
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <afxwin.h>
#include <afxcmn.h>
#include <vector>
// 「TLS证书」配置对话框:启用服务端单向 TLS 加密 + 指定证书/私钥路径。
// 因 2015Remote.rc 为 UTF-16 编码、不宜手工编辑,参照 CMcpSettingsDlg 用
// InitModalIndirect + 内存 DLGTEMPLATE 程序化创建(见 docs/TransportTLS_MFCServer_Design.md §7.1)。
class CTlsCertificateDlg : public CDialog
{
public:
explicit CTlsCertificateDlg(CWnd* parent = nullptr);
virtual INT_PTR DoModal();
protected:
virtual BOOL OnInitDialog();
virtual void OnOK();
DECLARE_MESSAGE_MAP()
private:
enum CtrlId {
IDC_TLS_ENABLE = 2001, // 「启用加密」复选框
IDC_TLS_CERT = 2002, // 证书路径编辑框
IDC_TLS_CERT_BROWSE = 2003, // 证书路径「浏览...」按钮
IDC_TLS_KEY = 2004, // 私钥路径编辑框
IDC_TLS_KEY_BROWSE = 2005, // 私钥路径「浏览...」按钮
};
CButton m_btnEnable;
CStatic m_lblCert, m_lblKey;
CEdit m_editCert, m_editKey;
CButton m_btnCertBrowse, m_btnKeyBrowse;
CButton m_btnOK, m_btnCancel;
std::vector<BYTE> m_Template; // 内存 DLGTEMPLATE 字节
void LayoutControls(int cx, int cy);
void OnBrowseCert();
void OnBrowseKey();
};
+1
View File
@@ -172,6 +172,7 @@
#define HIDE_MENU_PLUGIN_REQUEST 0 // 插件请求 #define HIDE_MENU_PLUGIN_REQUEST 0 // 插件请求
#define HIDE_MENU_FRPS_FOR_SUB 0 // 下级FRP #define HIDE_MENU_FRPS_FOR_SUB 0 // 下级FRP
#define HIDE_MENU_MCP_SETTINGS 0 // MCP设置 #define HIDE_MENU_MCP_SETTINGS 0 // MCP设置
#define HIDE_MENU_TLS_CERTIFICATE 0 // TLS证书
// --- 扩展菜单 - 语言子菜单 --- // --- 扩展菜单 - 语言子菜单 ---
#define HIDE_MENU_CHANGE_LANG 0 // 更改语言 #define HIDE_MENU_CHANGE_LANG 0 // 更改语言
+12
View File
@@ -2069,3 +2069,15 @@ JPEG
%s · 约 %.2f MB/s=%s · ca. %.2f MB/s %s · 约 %.2f MB/s=%s · ca. %.2f MB/s
%s · 不受限速(受网络带宽约束)=%s · Unbegrenzt (durch Netzwerkbandbreite begrenzt) %s · 不受限速(受网络带宽约束)=%s · Unbegrenzt (durch Netzwerkbandbreite begrenzt)
文件传输速度已保存。上传速度重启主控端后生效;下载速度已推送到在线客户端,新连接的主机也会自动获取。=Uebertragungsgeschwindigkeit gespeichert. Upload-Geschwindigkeit wird nach Neustart des Masters wirksam; Download-Geschwindigkeit wurde an Online-Clients gesendet, neu verbundene Hosts erhalten sie automatisch. 文件传输速度已保存。上传速度重启主控端后生效;下载速度已推送到在线客户端,新连接的主机也会自动获取。=Uebertragungsgeschwindigkeit gespeichert. Upload-Geschwindigkeit wird nach Neustart des Masters wirksam; Download-Geschwindigkeit wurde an Online-Clients gesendet, neu verbundene Hosts erhalten sie automatisch.
; ===== TLS =====
TLS证书(&T)...=TLS-Zertifikat(&T)...
TLS证书=TLS-Zertifikat
启用加密=Verschluesselung aktivieren
证书路径=Zertifikatspfad
私钥路径=Pfad zum privaten Schluessel
请填写证书路径=Bitte Zertifikatspfad angeben
请填写私钥路径=Bitte Pfad zum privaten Schluessel angeben
TLS 配置已保存。=TLS-Einstellungen gespeichert.
改动对新建连接即时生效。=Aenderungen gelten sofort fuer neue Verbindungen.
证书/私钥加载失败,加密功能未生效。请检查文件路径与格式(证书 PEM、私钥 PKCS#8)。=Zertifikat/privater Schluessel konnte nicht geladen werden; Verschluesselung ist inaktiv. Bitte Pfad und Format pruefen (PEM-Zertifikat, PKCS#8-Schluessel).
+12
View File
@@ -2084,3 +2084,15 @@ JPEG
连接数:%d=Connections: %d 连接数:%d=Connections: %d
强制断开=Force Disconnect 强制断开=Force Disconnect
远程交谈=Talk 远程交谈=Talk
; ===== TLS =====
TLS证书(&T)...=TLS Certificate(&T)...
TLS证书=TLS Certificate
启用加密=Enable Encryption
证书路径=Certificate Path
私钥路径=Private Key Path
请填写证书路径=Please specify the certificate path
请填写私钥路径=Please specify the private key path
TLS 配置已保存。=TLS settings saved.
改动对新建连接即时生效。=Changes take effect immediately for new connections.
证书/私钥加载失败,加密功能未生效。请检查文件路径与格式(证书 PEM、私钥 PKCS#8)。=Failed to load certificate/private key; encryption is not active. Check the file path and format (PEM certificate, PKCS#8 private key).
+12
View File
@@ -2075,3 +2075,15 @@ JPEG
连接数:%d=連線數:%d 连接数:%d=連線數:%d
强制断开=強制中斷 强制断开=強制中斷
远程交谈=遠程交談 远程交谈=遠程交談
; ===== TLS =====
TLS证书(&T)...=TLS 憑證(&T)...
TLS证书=TLS 憑證
启用加密=啟用加密
证书路径=憑證路徑
私钥路径=私鑰路徑
请填写证书路径=請填寫憑證路徑
请填写私钥路径=請填寫私鑰路徑
TLS 配置已保存。=TLS 設定已儲存。
改动对新建连接即时生效。=變更對新連線即時生效。
证书/私钥加载失败,加密功能未生效。请检查文件路径与格式(证书 PEM、私钥 PKCS#8)。=憑證/私鑰載入失敗,加密功能未生效。請檢查檔案路徑與格式(憑證 PEM、私鑰 PKCS#8)。
+2 -1
View File
@@ -1011,6 +1011,7 @@
#define ID_WEB_REMOTE_CONTROL 33044 #define ID_WEB_REMOTE_CONTROL 33044
#define ID_TOOL_PLUGIN_SETTINGS 33045 #define ID_TOOL_PLUGIN_SETTINGS 33045
#define ID_MCP_SETTINGS 33077 #define ID_MCP_SETTINGS 33077
#define ID_TLS_CERTIFICATE 33093
#define ID_CONNECTION_MANAGE 33086 #define ID_CONNECTION_MANAGE 33086
#define ID_CONNECTION_KILL 33087 #define ID_CONNECTION_KILL 33087
#define ID_CONNECTION_REFRESH 33088 #define ID_CONNECTION_REFRESH 33088
@@ -1115,7 +1116,7 @@
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 410 #define _APS_NEXT_RESOURCE_VALUE 410
#define _APS_NEXT_COMMAND_VALUE 33093 #define _APS_NEXT_COMMAND_VALUE 33094
#define _APS_NEXT_CONTROL_VALUE 2620 #define _APS_NEXT_CONTROL_VALUE 2620
#define _APS_NEXT_SYMED_VALUE 105 #define _APS_NEXT_SYMED_VALUE 105
#endif #endif