Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
5bc46cd
fix(daemon): 修复插件安装路由权限问题
luluxiaoyu May 25, 2026
559a90b
fix(daemon): 修复部分插件图标无法正常获取的问题
luluxiaoyu May 25, 2026
ac3879e
chore(daemon): 优化代码
luluxiaoyu May 25, 2026
1f28942
fix(webpanel & daemon): 修复chmlfrp无法创建隧道的问题 #135
luluxiaoyu May 25, 2026
89f09cf
feat(daemon): 游戏玩家列表新增中文匹配支持 & 优化下载外置登录库时的状态刷新 #133
luluxiaoyu May 28, 2026
8983509
fix(webpanel): 修复网页控制台登录页面在黑暗模式下背景图不正常缩放的问题
luluxiaoyu May 28, 2026
f654ae8
fix(daemon): 修复桌面环境打开浏览器时出现的奇怪错误 #124
luluxiaoyu May 28, 2026
a88d0d8
feat(daemon & webpanel): 新增SSL配置功能(支持本地自签证书 & 上传自定义证书) #96
luluxiaoyu May 28, 2026
924008d
perf(daemon & webpanel): 优化SSL证书的加载逻辑
luluxiaoyu May 29, 2026
e28d697
feat(daemon): 本地丢失SSL证书或SSL证书无效时自动生成一份临时自签名证书
luluxiaoyu May 29, 2026
f755d3f
dev(webpanel): 开发环境下自动切换http/https
luluxiaoyu May 29, 2026
a331733
perf(webpanel): 优化SSL设置模块UI
luluxiaoyu May 29, 2026
e24f6ad
perf(webpanel): 拆分系统设置为单独的菜单路由
luluxiaoyu May 29, 2026
e73eda2
fix(webpanel): 修复移动端下插件管理页面内容溢出的问题
luluxiaoyu May 29, 2026
2bc61c1
perf(webpanel & daemon): 优化修改证书的界面设计
luluxiaoyu May 29, 2026
fc03eff
bumpver(daemon & webpanel): 更新到v1.4.5版本
luluxiaoyu May 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion MSLX.Daemon/Controllers/AppInfoController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public IActionResult GetStatus()
["targetFrontendVersion"] = new JObject
{
["desktop"] = "1.0.0",
["panel"] = "1.4.4"
["panel"] = "1.4.5"
},
["systemInfo"] = systemInfo
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Text.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
Expand Down Expand Up @@ -34,14 +35,17 @@ public Task<IActionResult> DeleteTunnel([FromQuery] int tunnelId)
public Task<IActionResult> GetTunnelConfig([FromQuery] string node, [FromQuery] string tunnelName)
=> ForwardGetAsync(
$"{ChmlFrpApiBaseUrl}/tunnel_config?node={Uri.EscapeDataString(node)}&tunnel_names={Uri.EscapeDataString(tunnelName)}");

[HttpPost("create-tunnel")]
public async Task<IActionResult> CreateTunnel([FromBody] JToken body)
public async Task<IActionResult> CreateTunnel()
{
using var reader = new StreamReader(Request.Body);
var rawBody = await reader.ReadToEndAsync();

var response = await GeneralApi.PostAsync(
$"{ChmlFrpApiBaseUrl}/create_tunnel",
HttpService.PostContentType.Json,
body,
rawBody,
BuildProxyHeaders());

return BuildActionResult(response);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MSLX.Daemon.Services;
using MSLX.SDK.Models;
Expand All @@ -22,6 +23,7 @@ public PluginActionController(PluginManager pluginManager)
}

[HttpPost("action")]
[Authorize(Roles = "admin")]
public IActionResult HandleAction([FromBody] PluginActionRequest request)
{
var dllPath = GetDllPathById(request.Id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@ public IActionResult GetPluginList()
if (System.IO.File.Exists(dllPath + ".delete")) status = "下次重启删除";
else if (System.IO.File.Exists(dllPath + ".new")) status = "下次重启更新";
else if (System.IO.File.Exists(dllPath + ".disabled")) status = "下次重启禁用";
var iconPath = (p.Metadata.Icon != null && p.Metadata.Icon.StartsWith("http"))
? "https://www.mslmc.cn/logo.png"
: $"/plugins/{p.Metadata.Id.ToLower()}/{p.Metadata.Version.ToLower()}/{p.Metadata.Icon}";
var iconPath = p.Metadata.Icon switch
{
null or "" => "https://www.mslmc.cn/logo.png",
var icon when icon.StartsWith("http", StringComparison.OrdinalIgnoreCase) => icon,
var icon => $"/plugins/{p.Metadata.Id.ToLower()}/{p.Metadata.Version.ToLower()}/{icon}"
};

resultList.Add(new
{
Expand Down
176 changes: 150 additions & 26 deletions MSLX.Daemon/Controllers/SettingsController.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MSLX.Daemon.Utils;
using MSLX.Daemon.Utils.ConfigUtils;
using MSLX.SDK.Models;
using MSLX.SDK.Models.Settings;
Expand All @@ -8,7 +9,7 @@ namespace MSLX.Daemon.Controllers;

[ApiController]
[Route("api/settings")]
public class SettingsController: ControllerBase
public class SettingsController : ControllerBase
{
[HttpGet]
[Authorize(Roles = "admin")]
Expand All @@ -20,18 +21,19 @@ public IActionResult GetSettings()
Message = "获取成功",
Data = new
{
FireWallBanLocalAddr = IConfigBase.Config.ReadConfig()["fireWallBanLocalAddr"]?? false,
OpenWebConsoleOnLaunch = IConfigBase.Config.ReadConfig()["openWebConsoleOnLaunch"]?? true,
NeoForgeInstallerMirrors = IConfigBase.Config.ReadConfig()["neoForgeInstallerMirrors"]?? "MSL Mirrors",
ListenHost = IConfigBase.Config.ReadConfig()["listenHost"]?? "localhost",
ListenPort = IConfigBase.Config.ReadConfig()["listenPort"]?? 1027,
OAuthMSLClientID = IConfigBase.Config.ReadConfig()["oAuthMSLClientID"]?? "",
OAuthMSLClientSecret = IConfigBase.Config.ReadConfig()["oAuthMSLClientSecret"]?? "",
FireWallBanLocalAddr = IConfigBase.Config.ReadConfig()["fireWallBanLocalAddr"] ?? false,
OpenWebConsoleOnLaunch = IConfigBase.Config.ReadConfig()["openWebConsoleOnLaunch"] ?? true,
NeoForgeInstallerMirrors =
IConfigBase.Config.ReadConfig()["neoForgeInstallerMirrors"] ?? "MSL Mirrors",
ListenHost = IConfigBase.Config.ReadConfig()["listenHost"] ?? "localhost",
ListenPort = IConfigBase.Config.ReadConfig()["listenPort"] ?? 1027,
OAuthMSLClientID = IConfigBase.Config.ReadConfig()["oAuthMSLClientID"] ?? "",
OAuthMSLClientSecret = IConfigBase.Config.ReadConfig()["oAuthMSLClientSecret"] ?? "",
}
}
);
}

[HttpPost]
[Authorize(Roles = "admin")]
public IActionResult UpdateSettings([FromBody] UpdateSettingsRequest request)
Expand Down Expand Up @@ -61,14 +63,18 @@ public IActionResult GetWebPanelStyle()
Message = "获取成功",
Data = new
{
WebPanelStyleLightBackground = IConfigBase.Config.ReadConfig()["webPanelStyleLightBackground"]?? "",
WebPanelStyleDarkBackground = IConfigBase.Config.ReadConfig()["webPanelStyleDarkBackground"]?? "",
WebPanelStyleLightBackgroundOpacity = IConfigBase.Config.ReadConfig()["webPanelStyleLightBackgroundOpacity"]?? 1.0,
WebPanelStyleDarkBackgroundOpacity = IConfigBase.Config.ReadConfig()["webPanelStyleDarkBackgroundOpacity"]?? 1.0,
WebPanelStyleLightComponentsOpacity = IConfigBase.Config.ReadConfig()["webPanelStyleLightComponentsOpacity"]?? 0.4,
WebPanelStyleDarkComponentsOpacity = IConfigBase.Config.ReadConfig()["webPanelStyleDarkComponentsOpacity"]?? 0.6,
WebpPanelTerminalBlurLight = IConfigBase.Config.ReadConfig()["webpPanelTerminalBlurLight"]?? 5.0,
WebpPanelTerminalBlurDark = IConfigBase.Config.ReadConfig()["webpPanelTerminalBlurDark"]?? 5.0,
WebPanelStyleLightBackground = IConfigBase.Config.ReadConfig()["webPanelStyleLightBackground"] ?? "",
WebPanelStyleDarkBackground = IConfigBase.Config.ReadConfig()["webPanelStyleDarkBackground"] ?? "",
WebPanelStyleLightBackgroundOpacity =
IConfigBase.Config.ReadConfig()["webPanelStyleLightBackgroundOpacity"] ?? 1.0,
WebPanelStyleDarkBackgroundOpacity =
IConfigBase.Config.ReadConfig()["webPanelStyleDarkBackgroundOpacity"] ?? 1.0,
WebPanelStyleLightComponentsOpacity =
IConfigBase.Config.ReadConfig()["webPanelStyleLightComponentsOpacity"] ?? 0.4,
WebPanelStyleDarkComponentsOpacity =
IConfigBase.Config.ReadConfig()["webPanelStyleDarkComponentsOpacity"] ?? 0.6,
WebpPanelTerminalBlurLight = IConfigBase.Config.ReadConfig()["webpPanelTerminalBlurLight"] ?? 5.0,
WebpPanelTerminalBlurDark = IConfigBase.Config.ReadConfig()["webpPanelTerminalBlurDark"] ?? 5.0,

// 日志染色级别
WebPanelColorizeLogLevel = IConfigBase.Config.ReadConfig()["webPanelColorizeLogLevel"] ?? 1,
Expand All @@ -80,20 +86,138 @@ public IActionResult GetWebPanelStyle()
[Authorize(Roles = "admin")]
public IActionResult UpdateWebPanelStyle([FromBody] UpdateWebPanelStyleSettingsRequest request)
{
IConfigBase.Config.WriteConfigKey("webPanelStyleLightBackground",request.WebPanelStyleLightBackground);
IConfigBase.Config.WriteConfigKey("webPanelStyleDarkBackground",request.WebPanelStyleDarkBackground);
IConfigBase.Config.WriteConfigKey("webPanelStyleLightBackgroundOpacity",request.WebPanelStyleLightBackgroundOpacity);
IConfigBase.Config.WriteConfigKey("webPanelStyleDarkBackgroundOpacity",request.WebPanelStyleDarkBackgroundOpacity);
IConfigBase.Config.WriteConfigKey("webPanelStyleLightComponentsOpacity",request.WebPanelStyleLightComponentsOpacity);
IConfigBase.Config.WriteConfigKey("webPanelStyleDarkComponentsOpacity",request.WebPanelStyleDarkComponentsOpacity);
IConfigBase.Config.WriteConfigKey("webpPanelTerminalBlurLight",request.WebpPanelTerminalBlurLight);
IConfigBase.Config.WriteConfigKey("webpPanelTerminalBlurDark",request.WebpPanelTerminalBlurDark);
IConfigBase.Config.WriteConfigKey("webPanelColorizeLogLevel",request.WebPanelColorizeLogLevel);
IConfigBase.Config.WriteConfigKey("webPanelStyleLightBackground", request.WebPanelStyleLightBackground);
IConfigBase.Config.WriteConfigKey("webPanelStyleDarkBackground", request.WebPanelStyleDarkBackground);
IConfigBase.Config.WriteConfigKey("webPanelStyleLightBackgroundOpacity",
request.WebPanelStyleLightBackgroundOpacity);
IConfigBase.Config.WriteConfigKey("webPanelStyleDarkBackgroundOpacity",
request.WebPanelStyleDarkBackgroundOpacity);
IConfigBase.Config.WriteConfigKey("webPanelStyleLightComponentsOpacity",
request.WebPanelStyleLightComponentsOpacity);
IConfigBase.Config.WriteConfigKey("webPanelStyleDarkComponentsOpacity",
request.WebPanelStyleDarkComponentsOpacity);
IConfigBase.Config.WriteConfigKey("webpPanelTerminalBlurLight", request.WebpPanelTerminalBlurLight);
IConfigBase.Config.WriteConfigKey("webpPanelTerminalBlurDark", request.WebpPanelTerminalBlurDark);
IConfigBase.Config.WriteConfigKey("webPanelColorizeLogLevel", request.WebPanelColorizeLogLevel);
return Ok(new ApiResponse<object>
{
Code = 200,
Message = "更新成功",
}
);
}

#region SSL设置

[HttpGet("ssl")]
[Authorize(Roles = "admin")]
public IActionResult GetSslSettings()
{
string certDir = Path.Combine(IConfigBase.GetAppConfigPath(), "certs");
string pemPath = Path.Combine(certDir, "server.pem");
string keyPath = Path.Combine(certDir, "server.key");

bool hasCert = System.IO.File.Exists(pemPath) && System.IO.File.Exists(keyPath);
string? certContent = hasCert ? System.IO.File.ReadAllText(pemPath) : null;

bool isSelfSigned = false;

var activeCert = MSLX.Daemon.Utils.SslCertificateManager.GetCertificate();
if (activeCert != null)
{
isSelfSigned = activeCert.Subject.Contains("MSLX Local Certificate") ||
activeCert.Subject.Contains("MSLX Emergency Temporary Certificate");
}

return Ok(new ApiResponse<SslSettingsResponse>
{
Code = 200,
Message = "获取成功",
Data = new SslSettingsResponse
{
EnableSsl = (bool?)IConfigBase.Config.ReadConfig()["enableSsl"] ?? false,
HasCertificate = hasCert,
CertificateContent = certContent,
IsSelfSigned = isSelfSigned
}
});
}

[HttpPost("ssl")]
[Authorize(Roles = "admin")]
public IActionResult UpdateSslSettings([FromBody] UpdateSslSettingsRequest request)
{
try
{
string certDir = Path.Combine(IConfigBase.GetAppConfigPath(), "certs");
if (!Directory.Exists(certDir))
{
Directory.CreateDirectory(certDir);
}

// 自签名
if (request.UseSelfSignedCert)
{
using var rsa = System.Security.Cryptography.RSA.Create(2048);
var dnBuilder = new System.Security.Cryptography.X509Certificates.X500DistinguishedNameBuilder();
dnBuilder.AddCommonName("MSLX Local Certificate");
dnBuilder.AddOrganizationName("净善宫");
dnBuilder.AddOrganizationalUnitName("纳西妲最可爱啦!");
dnBuilder.AddLocalityName("Sumeru");
dnBuilder.AddCountryOrRegion("CN");
var req = new System.Security.Cryptography.X509Certificates.CertificateRequest(
dnBuilder.Build(),
rsa,
System.Security.Cryptography.HashAlgorithmName.SHA256,
System.Security.Cryptography.RSASignaturePadding.Pkcs1);

using var cert = req.CreateSelfSigned(DateTimeOffset.UtcNow.AddDays(-1),
DateTimeOffset.UtcNow.AddYears(10));

System.IO.File.WriteAllText(Path.Combine(certDir, "server.pem"), cert.ExportCertificatePem());
System.IO.File.WriteAllText(Path.Combine(certDir, "server.key"), rsa.ExportRSAPrivateKeyPem());
}
// 自定义证书
else if (!string.IsNullOrWhiteSpace(request.Certificate) && !string.IsNullOrWhiteSpace(request.PrivateKey))
{
System.IO.File.WriteAllText(Path.Combine(certDir, "server.pem"), request.Certificate.Trim());
System.IO.File.WriteAllText(Path.Combine(certDir, "server.key"), request.PrivateKey.Trim());
}

if (request.EnableSsl)
{
string checkPem = Path.Combine(IConfigBase.GetAppConfigPath(), "certs", "server.pem");
if (!System.IO.File.Exists(checkPem))
{
return BadRequest(new ApiResponse<object>
{
Code = 400,
Message = "无法开启 SSL:未找到证书文件,请一起提交证书内容或勾选生成自签名证书。"
});
}
}

IConfigBase.Config.WriteConfigKey("enableSsl", request.EnableSsl);
if (request.EnableSsl)
{
SslCertificateManager.ReloadCertificate();
}

return Ok(new ApiResponse<object>
{
Code = 200,
Message = "SSL 配置已更新,请重启面板以应用网络协议更改"
});
}
catch (Exception ex)
{
return StatusCode(500, new ApiResponse<object>
{
Code = 500,
Message = $"保存 SSL 配置失败: {ex.Message}"
});
}
}

#endregion
}
1 change: 0 additions & 1 deletion MSLX.Daemon/Frontend/assets/css/mslx-app-main.CDS3ItPM.css

This file was deleted.

1 change: 1 addition & 0 deletions MSLX.Daemon/Frontend/assets/css/mslx-app-main.D0dYkhEK.css

Large diffs are not rendered by default.

Loading
Loading