新增车辆表及OTA权限与逻辑优化
新增车辆任务与报警表,完善实体与DbContext配置。细化OTA权限校验,增强回传会话IP安全。优化OTA上传与设置面板,调度器支持重启恢复。报警采集逻辑支持历史分段。
This commit is contained in:
@@ -8,11 +8,14 @@ namespace MiGu.Server.Controllers;
|
||||
/// WatchDog 回传包接收端。
|
||||
/// WatchDog 写死 POST 到 http://{config.serverIP}:8000/upload-mdcs/{routeKey},
|
||||
/// 必须与参考 Electron Express :8000 路径一致;/api/ota/receive/* 仅作兼容别名。
|
||||
/// 会话校验使用 TCP 对端 IP(见 Program 中 TcpRemoteIp),忽略可伪造的 X-Forwarded-For。
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[AllowAnonymous]
|
||||
public class OtaReceiveController : ControllerBase
|
||||
{
|
||||
public const string TcpRemoteIpItemKey = "TcpRemoteIp";
|
||||
|
||||
private readonly OtaStore _store;
|
||||
private readonly ILogger<OtaReceiveController> _log;
|
||||
|
||||
@@ -40,15 +43,15 @@ public class OtaReceiveController : ControllerBase
|
||||
[RequestSizeLimit(512_000_000)]
|
||||
public async Task<IActionResult> UploadHistory(string routeKey, CancellationToken ct)
|
||||
{
|
||||
var ip = HttpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown";
|
||||
var ip = ResolveTcpRemoteIp();
|
||||
if (!_store.TryGetActivePullId(ip, out _))
|
||||
{
|
||||
_log.LogWarning("OTA history rejected without active pull session from {Ip}", ip);
|
||||
_log.LogWarning("OTA history rejected without active pull session from {Ip}", ip ?? "unknown");
|
||||
return BadRequest("no active pull session");
|
||||
}
|
||||
|
||||
var day = DateTime.Now.ToString("yyyy-MM-dd");
|
||||
var dir = Path.Combine(_store.HistoryDir, day, SafeFileName(ip, "unknown"));
|
||||
var dir = Path.Combine(_store.HistoryDir, day, SafeFileName(ip ?? "unknown", "unknown"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var file = await ReadFirstFileAsync(ct);
|
||||
if (file == null || file.Length == 0) return BadRequest("empty");
|
||||
@@ -58,6 +61,7 @@ public class OtaReceiveController : ControllerBase
|
||||
var path = Path.Combine(dir, safeName);
|
||||
await using var fs = System.IO.File.Create(path);
|
||||
await file.CopyToAsync(fs, ct);
|
||||
_store.NotePullReceive(ip);
|
||||
_log.LogInformation("OTA history receive {Route} -> {Path} ({Len})", routeKey, path, file.Length);
|
||||
return Ok(new { ok = true });
|
||||
}
|
||||
@@ -66,7 +70,7 @@ public class OtaReceiveController : ControllerBase
|
||||
{
|
||||
try
|
||||
{
|
||||
var clientIp = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||
var clientIp = ResolveTcpRemoteIp();
|
||||
if (!_store.TryGetActivePullId(clientIp, out _))
|
||||
{
|
||||
_log.LogWarning("OTA mdcs rejected without active pull session from {Ip}", clientIp ?? "unknown");
|
||||
@@ -80,8 +84,9 @@ public class OtaReceiveController : ControllerBase
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(dest)!);
|
||||
await using (var fs = System.IO.File.Create(dest))
|
||||
await file.CopyToAsync(fs, ct);
|
||||
_store.NotePullReceive(clientIp);
|
||||
_log.LogInformation("OTA mdcs receive {Route} -> {Dest} ({Len})", routeKey, dest, file.Length);
|
||||
return Ok(new { ok = true, path = dest });
|
||||
return Ok(new { ok = true });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -90,6 +95,14 @@ public class OtaReceiveController : ControllerBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>优先取 ForwardedHeaders 之前写入的 TCP 对端 IP,避免 X-Forwarded-For 投毒。</summary>
|
||||
private string? ResolveTcpRemoteIp()
|
||||
{
|
||||
if (HttpContext.Items.TryGetValue(TcpRemoteIpItemKey, out var boxed) && boxed is string s && !string.IsNullOrWhiteSpace(s))
|
||||
return s;
|
||||
return HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||
}
|
||||
|
||||
private async Task<IFormFile?> ReadFirstFileAsync(CancellationToken ct)
|
||||
{
|
||||
if (!Request.HasFormContentType) return null;
|
||||
|
||||
Reference in New Issue
Block a user