Skip to content

Commit 007c02f

Browse files
committed
fix: Mod 白名单 + Config 原子写 + 错误状态码
- ModController:下载 URL 白名单 + modId 正则校验\n- Config:Save 原子写(tmp+Move),Load 坏文件自动备份 .bak\n- ConvertController:失败路径改 4xx/5xx 而非 200
1 parent e00f9f5 commit 007c02f

3 files changed

Lines changed: 39 additions & 4 deletions

File tree

ChuChartManager/Config.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ public class Config
2121
public void Save()
2222
{
2323
Directory.CreateDirectory(AppDataDir);
24-
File.WriteAllText(ConfigFilePath, JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true }));
24+
var tmpPath = ConfigFilePath + ".tmp";
25+
File.WriteAllText(tmpPath, JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true }));
26+
File.Move(tmpPath, ConfigFilePath, overwrite: true);
2527
}
2628

2729
public static Config Load()
@@ -31,8 +33,15 @@ public static Config Load()
3133
{
3234
return JsonSerializer.Deserialize<Config>(File.ReadAllText(ConfigFilePath)) ?? new Config();
3335
}
34-
catch
36+
catch (Exception ex)
3537
{
38+
var backupPath = ConfigFilePath + ".bak";
39+
try
40+
{
41+
File.Copy(ConfigFilePath, backupPath, overwrite: true);
42+
}
43+
catch { }
44+
Log.Warn($"配置文件损坏,已备份到 {backupPath}: {ex.Message}");
3645
return new Config();
3746
}
3847
}

ChuChartManager/Controllers/ConvertController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public ActionResult<ConvertResult> ConvertChart([FromBody] ConvertRequest req)
7272
catch (ConversionException ex)
7373
{
7474
allAlerts.AddRange(ex.Alerts);
75-
return Ok(new ConvertResult
75+
return BadRequest(new ConvertResult
7676
{
7777
Success = false,
7878
Output = "",
@@ -82,7 +82,7 @@ public ActionResult<ConvertResult> ConvertChart([FromBody] ConvertRequest req)
8282
}
8383
catch (Exception ex)
8484
{
85-
return Ok(new ConvertResult
85+
return StatusCode(500, new ConvertResult
8686
{
8787
Success = false,
8888
Output = "",

ChuChartManager/Controllers/ModController.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ public async Task<ActionResult> InstallLoader([FromBody] InstallRequest? request
8787
if (string.IsNullOrEmpty(loaderUrl))
8888
return NotFound("No release found");
8989

90+
if (!IsAllowedDownloadUrl(loaderUrl))
91+
return BadRequest("下载 URL 不在白名单内");
92+
9093
var binPath = Path.Combine(gamePath, "bin");
9194
var loaderData = await Http.GetByteArrayAsync(loaderUrl);
9295
await System.IO.File.WriteAllBytesAsync(Path.Combine(binPath, "version.dll"), loaderData);
@@ -119,6 +122,9 @@ public async Task<ActionResult> InstallAppleChu([FromBody] InstallRequest? reque
119122
if (string.IsNullOrEmpty(url))
120123
return NotFound("No release found");
121124

125+
if (!IsAllowedDownloadUrl(url))
126+
return BadRequest("下载 URL 不在白名单内");
127+
122128
var data = await Http.GetByteArrayAsync(url);
123129
var modsDir = Path.Combine(binPath, "mods");
124130
Directory.CreateDirectory(modsDir);
@@ -137,6 +143,19 @@ public async Task<ActionResult> InstallAppleChu([FromBody] InstallRequest? reque
137143

138144
public record InstallRequest(string? Url);
139145

146+
private static bool IsAllowedDownloadUrl(string? url)
147+
{
148+
if (string.IsNullOrEmpty(url)) return false;
149+
return Uri.TryCreate(url, UriKind.Absolute, out var uri)
150+
&& uri.Host is "github.com" or "objects.githubusercontent.com" or "api.github.com"
151+
&& uri.AbsolutePath.StartsWith("/MuNET-OSS/", StringComparison.OrdinalIgnoreCase);
152+
}
153+
154+
private static bool IsValidModId(string modId)
155+
{
156+
return !string.IsNullOrEmpty(modId) && System.Text.RegularExpressions.Regex.IsMatch(modId, @"^[A-Za-z0-9_-]+$");
157+
}
158+
140159
private static async Task<GitHubRelease?> GetLatestRelease(string repo, string assetName)
141160
{
142161
try
@@ -153,6 +172,9 @@ public record InstallRequest(string? Url);
153172
[HttpGet("manifest/{modId}")]
154173
public ActionResult<object> GetManifest(string modId)
155174
{
175+
if (!IsValidModId(modId))
176+
return BadRequest("无效的 modId");
177+
156178
var source = Path.Combine(StaticSettings.ExeDir, "Resources", modId, "manifest.toml");
157179
if (!System.IO.File.Exists(source))
158180
return NotFound();
@@ -164,6 +186,8 @@ public ActionResult<object> GetManifest(string modId)
164186
[HttpGet("config/{modId}")]
165187
public ActionResult<ModConfigRequest> GetConfig(string modId)
166188
{
189+
if (!IsValidModId(modId))
190+
return BadRequest("无效的 modId");
167191
if (!TryResolveGameFile($"{modId}.toml", out var path))
168192
return BadRequest("GamePath not set");
169193
if (!System.IO.File.Exists(path))
@@ -181,6 +205,8 @@ public ActionResult<ModConfigRequest> GetConfig(string modId)
181205
[HttpPut("config/{modId}")]
182206
public ActionResult SaveConfig(string modId, [FromBody] ModConfigRequest request)
183207
{
208+
if (!IsValidModId(modId))
209+
return BadRequest("无效的 modId");
184210
if (!TryResolveGameFile($"{modId}.toml", out var path))
185211
return BadRequest("GamePath not set");
186212

0 commit comments

Comments
 (0)