修复Login Token的IP地址获取异常的问题,更新SQL

This commit is contained in:
root 2024-12-04 22:43:08 +08:00
parent 94642457a8
commit f1e43edde7
10 changed files with 281 additions and 8 deletions

View file

@ -23,6 +23,9 @@ namespace iFileProxy.Config
[JsonPropertyName("Database")]
public Database Database { get; set; }
[JsonPropertyName("GithubProxy")]
public GithubProxyOptions GithubProxyOptions { get; set; } = new();
public static AppConfig GetCurrConfig(string configPath = "iFileProxy.json")
{
if (File.Exists(configPath))
@ -140,4 +143,22 @@ namespace iFileProxy.Config
[JsonPropertyName("Description")]
public string Description { get; set; }
}
public class GithubProxyOptions
{
/// <summary>
/// 文件大小限制(字节)
/// </summary>
public long SizeLimit { get; set; } = 1024L * 1024L * 1024L; // 默认1GB
/// <summary>
/// 黑名单列表
/// </summary>
public List<string> Blacklist { get; set; } = [];
/// <summary>
/// 是否启用 jsDelivr 加速
/// </summary>
public bool EnableJsDelivr { get; set; } = false;
}
}

View file

@ -0,0 +1,87 @@
using Microsoft.AspNetCore.Mvc;
using iFileProxy.Services;
using iFileProxy.Models;
namespace iFileProxy.Controllers
{
[Route("[controller]")]
[ApiController]
public class GithubProxyController : ControllerBase
{
private readonly ILogger<GithubProxyController> _logger;
private readonly GithubProxyService _proxyService;
public GithubProxyController(
ILogger<GithubProxyController> logger,
GithubProxyService proxyService)
{
_logger = logger;
_proxyService = proxyService;
}
[HttpGet("{**url}")]
public async Task<IActionResult> ProxyDownload(string url)
{
try
{
// 1. URL 格式化
url = url.StartsWith("http") ? url : $"https://{url}";
// 2. 验证 URL
var (isValid, author, repo) = _proxyService.ValidateUrl(url);
if (!isValid || author == null || repo == null)
{
return BadRequest(new CommonRsp
{
Retcode = 1,
Message = "Invalid GitHub URL"
});
}
// 3. 检查黑名单
if (_proxyService.IsBlocked(author, repo))
{
return Forbid();
}
// 4. 处理URLCDN或Raw
url = _proxyService.ProcessUrl(url);
// 5. 代理请求
var response = await _proxyService.ProxyRequestAsync(url, Request.Headers);
if (!response.Success)
{
return StatusCode(response.StatusCode, new CommonRsp
{
Retcode = 1,
Message = response.Message
});
}
// 6. 设置响应头
if (response.Headers != null)
{
foreach (var header in response.Headers)
{
Response.Headers[header.Key] = header.Value;
}
}
// 7. 返回流式响应
return new FileStreamResult(
response.Stream!,
response.ContentType ?? "application/octet-stream"
);
}
catch (Exception ex)
{
_logger.LogError(ex, "Proxy download failed");
return StatusCode(500, new CommonRsp
{
Retcode = 1,
Message = "Internal server error"
});
}
}
}
}

View file

@ -50,7 +50,7 @@ namespace iFileProxy.Controllers
{
try
{
var ip = HttpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown";
var ip = MasterHelper.GetClientIPAddr(HttpContext);
var userAgent = HttpContext.Request.Headers["User-Agent"].FirstOrDefault() ?? "unknown";
var fingerprint = HttpContext.Request.Headers["X-Device-Fingerprint"].FirstOrDefault() ?? "unknown";

View file

@ -1,3 +1,4 @@
using iFileProxy.Helpers;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
@ -21,7 +22,7 @@ namespace iFileProxy.Middleware
var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
var fingerprint = context.Request.Headers["X-Device-Fingerprint"].FirstOrDefault();
var userAgent = context.Request.Headers["User-Agent"].FirstOrDefault();
var ip = context.Connection.RemoteIpAddress?.ToString();
var ip = MasterHelper.GetClientIPAddr(context);
if (token != null)
{

View file

@ -19,7 +19,6 @@ namespace iFileProxy
Console.Write(" "); // 补全日志第一行开头的空白
var builder = WebApplication.CreateBuilder(args);
// CORS配置
builder.Services.AddCors(options =>
{
@ -27,7 +26,7 @@ namespace iFileProxy
builder =>
{
builder
.WithOrigins("http://localhost:3000", "http://admin.gitdl.cn", "https://admin.gitdl.cn","http://47.243.56.137:50050", "http://localhost:4173")
.WithOrigins("http://localhost:3000", "http://admin.gitdl.cn", "https://admin.gitdl.cn", "https://github.linxi.info", "http://github.linxi.info/", "http://localhost:4173" )
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();

View file

@ -995,7 +995,7 @@ namespace iFileProxy.Services
{ "@level", log.Level },
{ "@message", log.Message },
{ "@exception", log.Exception },
{ "@properties", JsonConvert.SerializeObject(log.Properties) },
{ "@properties", log.Properties },
{ "@timestamp", log.Timestamp }
};

View file

@ -0,0 +1,130 @@
using System.Text.RegularExpressions;
using iFileProxy.Config;
using iFileProxy.Models;
namespace iFileProxy.Services
{
public class GithubProxyService
{
private readonly ILogger<GithubProxyService> _logger;
private readonly AppConfig _appConfig;
private readonly HttpClient _httpClient;
private static readonly Regex[] URL_PATTERNS =
{
new(@"^(?:https?://)?github\.com/(?<author>.+?)/(?<repo>.+?)/(?:releases|archive)/.*$"),
new(@"^(?:https?://)?github\.com/(?<author>.+?)/(?<repo>.+?)/(?:blob|raw)/.*$"),
new(@"^(?:https?://)?raw\.(?:githubusercontent|github)\.com/(?<author>.+?)/(?<repo>.+?)/.+?/.+$"),
new(@"^(?:https?://)?gist\.(?:githubusercontent|github)\.com/(?<author>.+?)/.+?/.+$")
};
public GithubProxyService(
ILogger<GithubProxyService> logger,
AppConfig appConfig,
HttpClient httpClient)
{
_logger = logger;
_appConfig = appConfig;
_httpClient = httpClient;
}
public (bool isValid, string? author, string? repo) ValidateUrl(string url)
{
foreach (var pattern in URL_PATTERNS)
{
var match = pattern.Match(url);
if (match.Success)
{
return (true, match.Groups["author"].Value, match.Groups["repo"].Value);
}
}
return (false, null, null);
}
public bool IsBlocked(string author, string repo)
{
return _appConfig.GithubProxyOptions.Blacklist.Contains($"{author}/{repo}") ||
_appConfig.GithubProxyOptions.Blacklist.Contains(author);
}
public string ProcessUrl(string url)
{
if (_appConfig.GithubProxyOptions.EnableJsDelivr && url.Contains("/blob/"))
{
return url.Replace("/blob/", "@")
.Replace("github.com", "cdn.jsdelivr.net/gh");
}
else if (url.Contains("/blob/"))
{
return url.Replace("/blob/", "/raw/");
}
return url;
}
public async Task<ProxyResponse> ProxyRequestAsync(
string url,
IHeaderDictionary headers,
CancellationToken cancellationToken = default)
{
try
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
// 复制请求头
foreach (var header in headers)
{
if (!header.Key.Equals("Host", StringComparison.OrdinalIgnoreCase))
{
request.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
}
}
var response = await _httpClient.SendAsync(
request,
HttpCompletionOption.ResponseHeadersRead,
cancellationToken);
// 检查文件大小
var contentLength = response.Content.Headers.ContentLength;
if (contentLength.HasValue && contentLength.Value > _appConfig.GithubProxyOptions.SizeLimit)
{
return new ProxyResponse
{
Success = false,
StatusCode = StatusCodes.Status413PayloadTooLarge,
Message = "File too large"
};
}
return new ProxyResponse
{
Success = true,
StatusCode = (int)response.StatusCode,
Headers = response.Headers.ToDictionary(h => h.Key, h => h.Value.ToArray()),
Stream = await response.Content.ReadAsStreamAsync(cancellationToken),
ContentType = response.Content.Headers.ContentType?.ToString()
};
}
catch (Exception ex)
{
_logger.LogError(ex, "Proxy request failed");
return new ProxyResponse
{
Success = false,
StatusCode = StatusCodes.Status500InternalServerError,
Message = "Internal server error"
};
}
}
}
public class ProxyResponse
{
public bool Success { get; set; }
public int StatusCode { get; set; }
public string? Message { get; set; }
public Dictionary<string, string[]>? Headers { get; set; }
public Stream? Stream { get; set; }
public string? ContentType { get; set; }
}
}

View file

@ -10,5 +10,13 @@
"Key": "iFileProxy-JWT-Secret-Key-2024-Very-Long-Secret-Key-For-Security",
"Issuer": "iFileProxy",
"Audience": "iFileProxy.Client"
},
"GithubProxy": {
"SizeLimit": 1073741824, // 1GB in bytes
"Blacklist": [
"blockedUser1",
"blockedUser2/blockedRepo",
"blockedOrg/*"
]
}
}

View file

@ -11,12 +11,28 @@
Target Server Version : 50743
File Encoding : 65001
Date: 01/12/2024 01:28:13
Date: 04/12/2024 00:13:59
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_system_logs
-- ----------------------------
DROP TABLE IF EXISTS `t_system_logs`;
CREATE TABLE `t_system_logs` (
`log_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`level` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`exception` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
`properties` json NULL,
`timestamp` datetime NOT NULL,
PRIMARY KEY (`log_id`) USING BTREE,
INDEX `idx_timestamp`(`timestamp`) USING BTREE,
INDEX `idx_level`(`level`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for t_tasks_info
-- ----------------------------
@ -35,7 +51,7 @@ CREATE TABLE `t_tasks_info` (
`tag` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '标记',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `tid`(`tid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9130 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 111135 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for t_user_events
@ -60,6 +76,7 @@ DROP TABLE IF EXISTS `t_users`;
CREATE TABLE `t_users` (
`user_id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '昵称',
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '电子邮箱',
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名',
`password_hash` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '密码哈希值',
`mask` int(11) NOT NULL DEFAULT 0 COMMENT '权限掩码',
@ -68,7 +85,8 @@ CREATE TABLE `t_users` (
`last_login_time` datetime NULL DEFAULT NULL COMMENT '上次登录时间',
`last_login_ip` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '上次登录IP',
PRIMARY KEY (`user_id`) USING BTREE,
UNIQUE INDEX `username`(`username`) USING BTREE
UNIQUE INDEX `username`(`username`) USING BTREE,
UNIQUE INDEX `email`(`email`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;

View file

@ -39,5 +39,14 @@
"/AddOfflineTask"
],
"AllowDifferentIPsForDownload": true // IP
},
"GithubProxy": {
"SizeLimit": 1073741824,
"Blacklist": [
"blockedUser1",
"blockedUser2/blockedRepo",
"blockedOrg/*"
],
"EnableJsDelivr": false
}
}