diff --git a/.idea/.idea.Abyss/.idea/workspace.xml b/.idea/.idea.Abyss/.idea/workspace.xml index d5f002a..8d7c248 100644 --- a/.idea/.idea.Abyss/.idea/workspace.xml +++ b/.idea/.idea.Abyss/.idea/workspace.xml @@ -10,13 +10,13 @@ - + - + + + - - - + - { + "keyToString": { + ".NET Launch Settings Profile.Abyss: http.executor": "Run", + ".NET Launch Settings Profile.Abyss: https.executor": "Debug", + ".NET Project.AbyssCli.executor": "Run", + "ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true", + "ModuleVcsDetector.initialDetectionPerformed": "true", + "Publish to folder.Publish Abyss to folder x86.executor": "Run", + "Publish to folder.Publish Abyss to folder.executor": "Run", + "RunOnceActivity.ShowReadmeOnStart": "true", + "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true", + "RunOnceActivity.git.unshallow": "true", + "XThreadsFramesViewSplitterKey": "0.30266345", + "git-widget-placeholder": "main", + "last_opened_file_path": "/storage/Images/31/summary.json", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable", + "vue.rearranger.settings.migration": "true" } -}]]> +} @@ -207,6 +204,11 @@ + + + + + diff --git a/Abyss/Components/Controllers/Media/ImageController.cs b/Abyss/Components/Controllers/Media/ImageController.cs index c5f94fc..650f6a4 100644 --- a/Abyss/Components/Controllers/Media/ImageController.cs +++ b/Abyss/Components/Controllers/Media/ImageController.cs @@ -11,7 +11,7 @@ using System.IO; [ApiController] [Route("api/[controller]")] -public class ImageController(ILogger logger, ResourceService rs, ConfigureService config) : Controller +public class ImageController(ILogger logger, ResourceService rs, ConfigureService config) : BaseController { public readonly string ImageFolder = Path.Combine(config.MediaRoot, "Images"); @@ -78,6 +78,4 @@ public class ImageController(ILogger logger, ResourceService rs return PhysicalFile(d, "image/jpeg", enableRangeProcessing: true); } - - private string Ip => HttpContext.Connection.RemoteIpAddress?.ToString() ?? "127.0.0.1"; } \ No newline at end of file diff --git a/Abyss/Components/Controllers/Media/LiveController.cs b/Abyss/Components/Controllers/Media/LiveController.cs index 82bd74a..e8464bf 100644 --- a/Abyss/Components/Controllers/Media/LiveController.cs +++ b/Abyss/Components/Controllers/Media/LiveController.cs @@ -6,7 +6,7 @@ namespace Abyss.Components.Controllers.Media; [ApiController] [Route("api/[controller]")] -public class LiveController(ILogger logger, ResourceService rs, ConfigureService config): Controller +public class LiveController(ILogger logger, ResourceService rs, ConfigureService config): BaseController { public readonly string LiveFolder = Path.Combine(config.MediaRoot, "Live"); @@ -33,25 +33,17 @@ public class LiveController(ILogger logger, ResourceService rs, return r ? Ok("Success") : BadRequest(); } - [HttpGet("{id}/{item}")] - public async Task GetLive(string id, string? token, string item) + [HttpGet("{id}/{token}/{item}")] + public async Task GetLive(string id, string token, string item) { var d = Helpers.SafePathCombine(LiveFolder, [id, item]); var f = Helpers.SafePathCombine(LiveFolder, [id]); if (d == null || f == null) return BadRequest(); - // TODO: ffplay does not add the m3u8 query parameter in ts requests, so special treatment is given to ts here - // TODO: It should be pointed out that this implementation is not secure and should be modified in subsequent updates - if (d.EndsWith(".ts")) - { - if(System.IO.File.Exists(d)) - return PhysicalFile(d, Helpers.GetContentType(d)); - else - return NotFound(); - } + // TODO: (History)ffplay does not add the m3u8 query parameter in ts requests, so special treatment is given to ts here + // TODO: (History)It should be pointed out that this implementation is not secure and should be modified in subsequent updates - if(token == null) - return StatusCode(403, new { message = "403 Denied" }); + // TODO: It's still not very elegant, but it's a bit better to some extent bool r = await rs.Valid(f, token, OperationType.Read, Ip); if(!r) return StatusCode(403, new { message = "403 Denied" }); @@ -61,6 +53,4 @@ public class LiveController(ILogger logger, ResourceService rs, else return NotFound(); } - - private string Ip => HttpContext.Connection.RemoteIpAddress?.ToString() ?? "127.0.0.1"; } \ No newline at end of file diff --git a/Abyss/Components/Controllers/Media/VideoController.cs b/Abyss/Components/Controllers/Media/VideoController.cs index 520a995..b5b4a5a 100644 --- a/Abyss/Components/Controllers/Media/VideoController.cs +++ b/Abyss/Components/Controllers/Media/VideoController.cs @@ -10,7 +10,7 @@ namespace Abyss.Components.Controllers.Media; [ApiController] [Route("api/[controller]")] -public class VideoController(ILogger logger, ResourceService rs, ConfigureService config) : Controller +public class VideoController(ILogger logger, ResourceService rs, ConfigureService config) : BaseController { private ILogger _logger = logger; @@ -109,6 +109,4 @@ public class VideoController(ILogger logger, ResourceService rs if (!r) return StatusCode(403, new { message = "403 Denied" }); return PhysicalFile(d, "video/mp4", enableRangeProcessing: true); } - - private string Ip => HttpContext.Connection.RemoteIpAddress?.ToString() ?? "127.0.0.1"; } \ No newline at end of file diff --git a/Abyss/Components/Controllers/Security/UserController.cs b/Abyss/Components/Controllers/Security/UserController.cs index 2b54f45..fe6a95a 100644 --- a/Abyss/Components/Controllers/Security/UserController.cs +++ b/Abyss/Components/Controllers/Security/UserController.cs @@ -3,6 +3,7 @@ using System.Text.RegularExpressions; using Abyss.Components.Services; +using Abyss.Components.Static; using Abyss.Model; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; @@ -12,7 +13,7 @@ namespace Abyss.Components.Controllers.Security; [ApiController] [Route("api/[controller]")] [EnableRateLimiting("Fixed")] -public class UserController(UserService user, ILogger logger) : Controller +public class UserController(UserService user, ILogger logger) : BaseController { private readonly ILogger _logger = logger; private readonly UserService _user = user; @@ -125,6 +126,4 @@ public class UserController(UserService user, ILogger logger) : return false; return Regex.IsMatch(input, @"^[a-zA-Z0-9]+$"); } - - private string Ip => HttpContext.Connection.RemoteIpAddress?.ToString() ?? "127.0.0.1"; } \ No newline at end of file diff --git a/Abyss/Components/Static/ControllerExtensions.cs b/Abyss/Components/Static/ControllerExtensions.cs new file mode 100644 index 0000000..c1ead1a --- /dev/null +++ b/Abyss/Components/Static/ControllerExtensions.cs @@ -0,0 +1,57 @@ +using System.Net; +using Microsoft.AspNetCore.Mvc; + +namespace Abyss.Components.Static; + +public abstract class BaseController : Controller +{ + private string? _ip; + + protected string Ip + { + get + { + if (_ip != null) + return _ip; + + _ip = GetClientIpAddress(); + + if (string.IsNullOrEmpty(_ip)) + throw new InvalidOperationException("invalid IP"); + + return _ip; + } + } + + private string? GetClientIpAddress() + { + var remoteIp = HttpContext.Connection.RemoteIpAddress; + + if (remoteIp != null && (IPAddress.IsLoopback(remoteIp) || remoteIp.ToString() == "::1")) + { + return remoteIp.ToString(); + } + + string? ip = remoteIp?.ToString(); + + if (HttpContext.Request.Headers.TryGetValue("X-Forwarded-For", out var forwardedFor)) + { + var forwardedIps = forwardedFor.ToString().Split(',', StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Trim()) + .Where(x => !string.IsNullOrEmpty(x)) + .ToArray(); + + if (forwardedIps.Length > 0) + { + ip = forwardedIps[0]; + } + } + + if (string.IsNullOrEmpty(ip) && HttpContext.Request.Headers.TryGetValue("X-Real-IP", out var realIp)) + { + ip = realIp.ToString(); + } + + return ip; + } +} \ No newline at end of file diff --git a/Abyss/Program.cs b/Abyss/Program.cs index 3b53873..b2c2d19 100644 --- a/Abyss/Program.cs +++ b/Abyss/Program.cs @@ -25,7 +25,6 @@ public class Program { options.AddFixedWindowLimiter("Fixed", policyOptions => { - // 时间窗口长度 policyOptions.Window = TimeSpan.FromSeconds(30); policyOptions.PermitLimit = 10; policyOptions.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; @@ -48,8 +47,7 @@ public class Program app.MapOpenApi(); } - app.UseHttpsRedirection(); - + // app.UseHttpsRedirection(); app.UseAuthorization(); app.MapStaticAssets(); app.MapControllers();