Skip to content

Commit 076aa70

Browse files
fix: register missing endpoints in LocalApiHost and tighten manifest path containment
Endpoint registration gap (production WPF host was missing 5 routes): - Add MapProfiles, MapInstall, MapCleanup, MapDiagnostics, MapSafeMode to LocalApiHost - Sync Program.cs to match: add MapInstall, MapCleanup, MapDiagnostics, MapSafeMode (MapProfiles was already present in Program.cs) BatchReinstallService #4 containment check: - After resolving relative paths, reject archives whose normalized absolute path does not start with the manifest's directory; set SourceArchivePath to empty so the existing extension + File.Exists guards skip them with a clear log entry Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 3a12a46 commit 076aa70

3 files changed

Lines changed: 24 additions & 3 deletions

File tree

LSPDFRManager.LocalApi/LocalApiHost.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,16 @@ public static async Task StartAsync(CancellationToken cancellationToken = defaul
7676
app.MapLogs();
7777
app.MapCompatibility();
7878
app.MapConfig();
79+
app.MapProfiles();
7980
app.MapPatrolReadiness();
8081
app.MapBackups();
8182
app.MapJobs();
8283
app.MapBrowse();
8384
app.MapLibrary();
85+
app.MapInstall();
86+
app.MapCleanup();
87+
app.MapDiagnostics();
88+
app.MapSafeMode();
8489
app.MapFallbackToFile("index.html");
8590

8691
await app.StartAsync(cancellationToken);

LSPDFRManager.LocalApi/Program.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,16 @@
2121
app.MapLogs();
2222
app.MapCompatibility();
2323
app.MapConfig();
24-
app.MapLibrary();
2524
app.MapProfiles();
2625
app.MapPatrolReadiness();
2726
app.MapBackups();
2827
app.MapJobs();
2928
app.MapBrowse();
29+
app.MapLibrary();
30+
app.MapInstall();
31+
app.MapCleanup();
32+
app.MapDiagnostics();
33+
app.MapSafeMode();
3034
app.MapFallbackToFile("index.html");
3135

3236
app.Run("http://127.0.0.1:5284");

Services/BatchReinstallService.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,24 @@ private void RestoreConfigSnapshots(ModManifest manifest, IProgress<string>? pro
120120

121121
// Resolve relative SourceArchivePaths against the manifest's directory so that
122122
// bare manifest + sibling archives work without absolute paths in the JSON.
123-
// Path.GetFullPath also collapses any ../ traversal segments.
123+
// Path.GetFullPath collapses any ../ traversal segments.
124+
// After normalization, reject paths that escape the manifest directory —
125+
// an absolute path in the JSON that points outside the manifest's folder
126+
// has no legitimate use case and could reference arbitrary system files.
124127
var manifestDir = Path.GetDirectoryName(Path.GetFullPath(manifestPath)) ?? string.Empty;
128+
var sep = Path.DirectorySeparatorChar;
125129
foreach (var mod in bare.Mods)
126130
{
127-
if (!string.IsNullOrWhiteSpace(mod.SourceArchivePath) && !Path.IsPathRooted(mod.SourceArchivePath))
131+
if (string.IsNullOrWhiteSpace(mod.SourceArchivePath))
132+
continue;
133+
134+
if (!Path.IsPathRooted(mod.SourceArchivePath))
128135
mod.SourceArchivePath = Path.GetFullPath(Path.Combine(manifestDir, mod.SourceArchivePath));
136+
137+
// Reject paths that escape the manifest directory (after normalization).
138+
var normalizedDir = manifestDir.TrimEnd(sep) + sep;
139+
if (!mod.SourceArchivePath.StartsWith(normalizedDir, StringComparison.OrdinalIgnoreCase))
140+
mod.SourceArchivePath = string.Empty; // extension + existence checks will skip it
129141
}
130142

131143
return (bare, null);

0 commit comments

Comments
 (0)