using iFileProxy.Config; using iFileProxy.Models; using Serilog; using System.Net; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; namespace iFileProxy.Helpers { public class MasterHelper { private readonly static Serilog.ILogger _logger = Log.Logger.ForContext(); /// /// 检测链接是否为合法的网址格式 /// /// 待检测的链接 /// public static bool CheckUrlIsValid(string? uri) { try { if (string.IsNullOrWhiteSpace(uri)) return false; var regex = @"(http://)?([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?"; Regex re = new Regex(regex); return re.IsMatch(uri); } catch (Exception e) { Console.WriteLine(e); } return false; } /// /// 获取一个给定的范围随机数 /// /// 最小值 /// 最大值 /// public static int GenerateRandomNumber(int minValue, int maxValue) { Random random = new Random(); // 创建一个新的Random实例 int randomNumber = random.Next(minValue, maxValue + 1); // 生成位于[minValue, maxValue]范围内的随机数 return randomNumber; } /// /// 获取客户端IP地址 /// /// HttpContext /// public static string GetClientIPAddr(HttpContext c) { // 尝试从 X-Forwarded-For 请求头获取客户端IP地址 string? clientIp = c.Request.Headers["X-Forwarded-For"].FirstOrDefault(); // 如果 X-Forwarded-For 头不存在,回退到 RemoteIpAddress if (string.IsNullOrEmpty(clientIp)) { clientIp = c.Connection.RemoteIpAddress?.ToString(); } IPAddress? ipAddress = null; if (IPAddress.TryParse(clientIp, out ipAddress)) return ipAddress.ToString(); return "127.0.0.1"; } /// /// 检查要下载的文件是否存在 /// /// /// public static bool CheckDownloadFileExists(string fileName) { if (File.Exists(Path.Combine(AppConfig.GetCurrConfig().DownloadOptions.SavePath, fileName))) { _logger.Debug("文件存在: {fileName}", fileName); return true; } _logger.Debug("文件不存在: {fileName}", fileName); return false; } public static long GetDownloadFileSize(string fileName) { if (CheckDownloadFileExists(fileName)) { return new FileInfo(Path.Combine(AppConfig.GetCurrConfig().DownloadOptions.SavePath, fileName)).Length; } else return -1; } /// /// 删除指定的已下载文件 /// /// /// public static bool RemoveDownloadFile(string fileName) { var f = Path.Combine(AppConfig.GetCurrConfig().DownloadOptions.SavePath, fileName); if (File.Exists(f)) { try { File.Delete(f); if (File.Exists(f + ".aria2")) File.Delete(f + ".aria2"); // aria2c的临时文件 return true; } catch (Exception) { return false; throw; } } else return false; } /// /// 获取文件哈希 /// /// 文件路径 /// 哈希算法 /// public static string GetFileHash(string fileName, FileHashAlgorithm algorithm) { byte[] hash = []; if (File.Exists(fileName)) { using FileStream fileStream = File.OpenRead(fileName); hash = algorithm switch { FileHashAlgorithm.MD5 => MD5.HashData(fileStream), FileHashAlgorithm.SHA1 => SHA1.HashData(fileStream), FileHashAlgorithm.SHA256 => SHA256.HashData(fileStream), FileHashAlgorithm.SHA384 => SHA384.HashData(fileStream), FileHashAlgorithm.SHA512 => SHA512.HashData(fileStream), _ => MD5.HashData(fileStream), }; StringBuilder sBuilder = new StringBuilder(); for (int i = 0; i < hash.Length; i++) { sBuilder.Append(hash[i].ToString("x2")); } return sBuilder.ToString(); } return null; } /// /// 从HttpContext中提取调试信息 /// public static async Task ExtractDebugInfo(HttpContext context) { var debugInfo = new HttpContextDebugInfo { RequestId = context.TraceIdentifier, Path = context.Request.Path, Method = context.Request.Method, ClientIP = GetClientIPAddr(context), UserAgent = context.Request.Headers.UserAgent.ToString(), Host = context.Request.Host.ToString(), ContentType = context.Request.ContentType ?? string.Empty, ContentLength = context.Request.ContentLength, IsHttps = context.Request.IsHttps, Headers = context.Request.Headers.ToDictionary( h => h.Key, h => h.Value.ToArray(), StringComparer.OrdinalIgnoreCase ), QueryParams = context.Request.Query.ToDictionary( q => q.Key, q => q.Value.ToArray(), StringComparer.OrdinalIgnoreCase ), Cookies = context.Request.Cookies.ToDictionary( c => c.Key, c => c.Value, StringComparer.OrdinalIgnoreCase ) }; // 获取表单数据 if (context.Request.HasFormContentType) { var form = await context.Request.ReadFormAsync(); debugInfo.FormData = form.ToDictionary( f => f.Key, f => f.Value.ToArray(), StringComparer.OrdinalIgnoreCase ); } // 获取请求体 if (context.Request.Body.CanRead) { context.Request.EnableBuffering(); using var reader = new StreamReader( context.Request.Body, encoding: System.Text.Encoding.UTF8, detectEncodingFromByteOrderMarks: false, leaveOpen: true ); debugInfo.RequestBody = await reader.ReadToEndAsync(); context.Request.Body.Position = 0; } return debugInfo; } // 定义正则表达式 private static readonly Regex exp1 = new Regex(@"^(?:https?://)?github\.com/(?.+?)/(?.+?)/(?:releases|archive)/.*$", RegexOptions.IgnoreCase); private static readonly Regex exp2 = new Regex(@"^(?:https?://)?github\.com/(?.+?)/(?.+?)/(?:blob|raw)/.*$", RegexOptions.IgnoreCase); private static readonly Regex exp3 = new Regex(@"^(?:https?://)?github\.com/(?.+?)/(?.+?)/(?:info|git-).*$", RegexOptions.IgnoreCase); private static readonly Regex exp4 = new Regex(@"^(?:https?://)?raw\.(?:githubusercontent|github)\.com/(?.+?)/(?.+?)/.+?/.+$", RegexOptions.IgnoreCase); private static readonly Regex exp5 = new Regex(@"^(?:https?://)?gist\.(?:githubusercontent|github)\.com/(?.+?)/.+?/.+$", RegexOptions.IgnoreCase); public static bool IsGithubUrl(string url) { // 判断url是否匹配任何一个正则表达式 return exp1.IsMatch(url) || exp2.IsMatch(url) || exp3.IsMatch(url) || exp4.IsMatch(url) || exp5.IsMatch(url); } } }