232 lines
8.7 KiB
C#
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);
|
|
}
|
|
|
|
}
|
|
}
|