iFileProxy/src/Helpers/MasterHelper.cs

232 lines
8.7 KiB
C#

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<MasterHelper>();
/// <summary>
/// 检测链接是否为合法的网址格式
/// </summary>
/// <param name="uri">待检测的链接</param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取一个给定的范围随机数
/// </summary>
/// <param name="minValue">最小值</param>
/// <param name="maxValue">最大值</param>
/// <returns></returns>
public static int GenerateRandomNumber(int minValue, int maxValue)
{
Random random = new Random(); // 创建一个新的Random实例
int randomNumber = random.Next(minValue, maxValue + 1); // 生成位于[minValue, maxValue]范围内的随机数
return randomNumber;
}
/// <summary>
/// 获取客户端IP地址
/// </summary>
/// <param name="c">HttpContext</param>
/// <returns></returns>
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";
}
/// <summary>
/// 检查要下载的文件是否存在
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 删除指定的已下载文件
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取文件哈希
/// </summary>
/// <param name="fileName">文件路径</param>
/// <param name="algorithm">哈希算法</param>
/// <returns></returns>
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;
}
/// <summary>
/// 从HttpContext中提取调试信息
/// </summary>
public static async Task<HttpContextDebugInfo> 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/(?<author>.+?)/(?<repo>.+?)/(?:releases|archive)/.*$", RegexOptions.IgnoreCase);
private static readonly Regex exp2 = new Regex(@"^(?:https?://)?github\.com/(?<author>.+?)/(?<repo>.+?)/(?:blob|raw)/.*$", RegexOptions.IgnoreCase);
private static readonly Regex exp3 = new Regex(@"^(?:https?://)?github\.com/(?<author>.+?)/(?<repo>.+?)/(?:info|git-).*$", RegexOptions.IgnoreCase);
private static readonly Regex exp4 = new Regex(@"^(?:https?://)?raw\.(?:githubusercontent|github)\.com/(?<author>.+?)/(?<repo>.+?)/.+?/.+$", RegexOptions.IgnoreCase);
private static readonly Regex exp5 = new Regex(@"^(?:https?://)?gist\.(?:githubusercontent|github)\.com/(?<author>.+?)/.+?/.+$", 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);
}
}
}