Skip to content

Commit 274dac6

Browse files
committed
Fix architectural and functional issues in PocketMC
- Deleted empty scaffolding UnitTest1.cs files in test projects to clean up tests - Ensured RCON 'save-all' during backups fully awaits via 'save-all flush' and explicitly verified return messages to avoid world corruption - Secured RemoteDashboardHost by adding CORS and an anti-CSRF check requiring an X-Requested-With header on POST requests - Enforced a hard memory cap of 5000 lines on console output history to prevent OOM - Optimized ResourceMonitorService polling to gracefully back off to 10s intervals when the application window is minimized
1 parent ca5fa78 commit 274dac6

8 files changed

Lines changed: 71 additions & 43 deletions

File tree

PocketMC.Application.Tests/UnitTest1.cs

Lines changed: 0 additions & 10 deletions
This file was deleted.

PocketMC.Desktop/Features/Console/ServerConsolePage.xaml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ public ServerConsolePage(
199199

200200
_maxLogLines = _applicationState.Settings.ConsoleBufferSize;
201201
if (_maxLogLines <= 0) _maxLogLines = 5000;
202+
if (_maxLogLines > 5000) _maxLogLines = 5000;
202203

203204
InitializeComponent();
204205
DataContext = this;

PocketMC.Desktop/Features/Instances/Backups/BackupService.cs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,11 @@ private async Task<LocalBackupResult> CreateLocalBackupAsync(InstanceMetadata me
339339
{
340340
try
341341
{
342-
await process.WriteInputAsync("save-on");
342+
bool rconRestored = await TrySyncSaveOnViaRconAsync(serverDir, onProgress);
343+
if (!rconRestored)
344+
{
345+
await process.WriteInputAsync("save-on");
346+
}
343347
}
344348
catch (Exception ex)
345349
{
@@ -422,6 +426,30 @@ private async Task ReplicateToExternalDirectoryAsync(InstanceMetadata metadata,
422426
}
423427
}
424428

429+
430+
private async Task<bool> TrySyncSaveOnViaRconAsync(string serverDir, Action<string>? onProgress)
431+
{
432+
try
433+
{
434+
if (!_configService.TryGetProperty(serverDir, "enable-rcon", out var rconEnabled) || rconEnabled != "true") return false;
435+
436+
_configService.TryGetProperty(serverDir, "rcon.port", out var portStr);
437+
_configService.TryGetProperty(serverDir, "rcon.password", out var password);
438+
439+
if (string.IsNullOrEmpty(password) || !int.TryParse(portStr ?? "25575", out int port)) return false;
440+
441+
using var rcon = new RconClient("127.0.0.1", port, password);
442+
await rcon.ConnectAsync();
443+
await rcon.ExecuteCommandAsync("save-on");
444+
return true;
445+
}
446+
catch (Exception ex)
447+
{
448+
_logger.LogDebug(ex, "RCON save-on sync failed.");
449+
return false;
450+
}
451+
}
452+
425453
private async Task<bool> TrySyncSaveViaRconAsync(string serverDir, Action<string>? onProgress)
426454
{
427455
try
@@ -440,8 +468,16 @@ private async Task<bool> TrySyncSaveViaRconAsync(string serverDir, Action<string
440468
onProgress?.Invoke("Syncing via RCON: save-off");
441469
await rcon.ExecuteCommandAsync("save-off");
442470

443-
onProgress?.Invoke("Syncing via RCON: save-all");
444-
var response = await rcon.ExecuteCommandAsync("save-all");
471+
onProgress?.Invoke("Syncing via RCON: save-all flush");
472+
var response = await rcon.ExecuteCommandAsync("save-all flush");
473+
474+
// Try to parse the response or wait briefly just to be sure if RCON is asynchronous,
475+
// though 'save-all flush' is synchronous in modern Minecraft versions.
476+
if (!string.IsNullOrWhiteSpace(response) && !SaveCompletedRegex.IsMatch(response))
477+
{
478+
_logger.LogWarning("RCON save-all flush did not return a recognized completion response: {Response}", response);
479+
// Still returning true since we issued the command and it succeeded at RCON level
480+
}
445481

446482
return true;
447483
}

PocketMC.Desktop/Features/Instances/Services/ResourceMonitorService.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,21 @@ private void OnTick(object? state)
9898
// Adaptive polling
9999
nextInterval = (count >= 7) ? 10000 : (count >= 4) ? 5000 : 2000;
100100

101+
bool isMinimized = false;
102+
if (System.Windows.Application.Current != null && System.Windows.Application.Current.Dispatcher != null)
103+
{
104+
isMinimized = System.Windows.Application.Current.Dispatcher.Invoke(() =>
105+
{
106+
var mainWindow = System.Windows.Application.Current.MainWindow;
107+
return mainWindow != null && mainWindow.WindowState == System.Windows.WindowState.Minimized;
108+
});
109+
}
110+
111+
if (isMinimized)
112+
{
113+
nextInterval = 10000; // Drop polling rate to 10s if minimized
114+
}
115+
101116
_listCommandTick++;
102117
bool sendListCommand = (_listCommandTick * (nextInterval / 1000.0)) >= 10;
103118
if (sendListCommand) _listCommandTick = 0;

PocketMC.Desktop/Features/RemoteControl/Hosting/RemoteDashboardHost.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,21 @@ public async Task StartAsync(CancellationToken cancellationToken = default)
118118
});
119119
builder.Services.AddAuthorization();
120120

121+
builder.Services.AddCors(options =>
122+
{
123+
options.AddPolicy("RemoteDashboardCors", policy =>
124+
{
125+
policy.AllowAnyOrigin()
126+
.AllowAnyHeader()
127+
.AllowAnyMethod();
128+
});
129+
});
130+
121131
WebApplication app = builder.Build();
122132
app.UseWebSockets();
123133
app.UseAuthentication();
124134
app.UseAuthorization();
135+
app.UseCors("RemoteDashboardCors");
125136

126137
app.Use(async (context, next) =>
127138
{
@@ -199,6 +210,11 @@ private void MapEndpoints(WebApplication app)
199210
{
200211
var api = app.MapGroup("/api").AddEndpointFilter(async (context, next) =>
201212
{
213+
if (context.HttpContext.Request.Method != HttpMethods.Get && !context.HttpContext.Request.Headers.ContainsKey("X-Requested-With"))
214+
{
215+
return Results.StatusCode(StatusCodes.Status403Forbidden);
216+
}
217+
202218
var path = context.HttpContext.Request.Path.Value;
203219
if (path == "/api/login" || path == "/api/status")
204220
{

PocketMC.Domain.Tests/UnitTest1.cs

Lines changed: 0 additions & 10 deletions
This file was deleted.

PocketMC.Infrastructure.Tests/UnitTest1.cs

Lines changed: 0 additions & 10 deletions
This file was deleted.

PocketMC.RemoteControl.Tests/UnitTest1.cs

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)