using System.ComponentModel;
using System.IdentityModel.Tokens.Jwt;
using System.Web;
using AngleSharp;
using Dpz.Core.EnumLibrary;
using Dpz.Core.Public.ViewModel.V4;
using Dpz.Core.Service.ObjectStorage.Services;
using Dpz.Core.Service.V4.Services;
using Dpz.Core.Web.Models;
using Dpz.Core.Web.Pager;
using Ganss.Xss;
using Markdig;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration;
namespace Dpz.Core.Web.Library;
public static class WebToolsExtensions
{
public static readonly string Version = Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "";
public const string DefaultGroupId = "5e09be6ae22e4d3b7810b6c7";
public static readonly Dictionary<int, string> Wind = new()
{
{ 0, "静风" },
{ 1, "软风" },
{ 2, "轻风" },
{ 3, "微风" },
{ 4, "和风" },
{ 5, "清风" },
{ 6, "强风" },
{ 7, "疾风" },
{ 8, "大风" },
{ 9, "强大风" },
{ 10, "超强大风" },
{ 11, "暴风" },
{ 12, "飓风" },
};
/// <summary>
/// 系统启动时间
/// </summary>
public static readonly DateTime StartTime = new(2018, 2, 11, 13, 56, 24, DateTimeKind.Local);
/// <summary>
/// 根据Identity反射获取当前用户信息
/// 未授权用户返回 null
/// </summary>
/// <param name="principal"></param>
/// <returns></returns>
public static VmUserInfo? GetIdentity(this ClaimsPrincipal principal)
{
if (principal.IsLogin())
{
var userInfo = new VmUserInfo();
foreach (var claims in principal.Claims)
{
var property = typeof(VmUserInfo).GetProperty(claims.Type);
if (property == null) continue;
if (property.PropertyType == typeof(DateTime?))
{
property.SetValue(userInfo, DateTime.Parse(claims.Value));
}
else if (property.PropertyType == typeof(Sex))
{
var sex = Enum.Parse(typeof(Sex), claims.Value);
property.SetValue(userInfo, sex);
}
else if (property.PropertyType == typeof(bool?))
{
bool.TryParse(claims.Value, out var result);
property.SetValue(userInfo, result);
}
else if (property.PropertyType == typeof(Permissions?))
{
if (Enum.TryParse(claims.Value, out Permissions permissions))
{
property.SetValue(userInfo, permissions);
}
}
else
{
typeof(VmUserInfo).GetProperty(claims.Type)?.SetValue(userInfo, claims.Value);
}
}
return userInfo;
}
return null;
}
public static VmUserInfo GetStrictIdentity(this ClaimsPrincipal principal)
{
return principal.GetIdentity() ?? throw new InvalidCredentialException();
}
public static VmUserInfo? GetIdentity(this HttpContext httpContext, TokenManagement? token)
{
if (token?.Secret == null)
{
return httpContext.User.GetIdentity();
}
var validated = httpContext.ValidationJwtBearer(token);
if (!validated)
return null;
return httpContext.User.GetIdentity();
}
public static bool ValidationJwtBearer(this HttpContext httpContext, TokenManagement token)
{
string? bearerToken = httpContext.Request.Headers["Authorization"];
bearerToken = bearerToken?.Replace($"{JwtBearerDefaults.AuthenticationScheme} ", "");
if (!string.IsNullOrEmpty(bearerToken))
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = token.Issuer,
ValidAudience = token.Audience,
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(token.Secret)),
ValidateLifetime = true
};
try
{
var principal =
new JwtSecurityTokenHandler().ValidateToken(bearerToken, tokenValidationParameters,
out var securityToken);
if (principal.Identity?.IsAuthenticated == true &&
securityToken is JwtSecurityToken jwtSecurityToken &&
jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256,
StringComparison.InvariantCultureIgnoreCase))
{
httpContext.User = principal;
return true;
}
}
catch (Exception e)
{
Log.Logger.Error(e, "validation jwt fail");
return false;
}
}
return false;
}
public static VmUserInfo? GetIdentity(this Controller controller)
{
return controller.ViewData["CurrentUser"] as VmUserInfo;
}
public static bool IsAdmin(this ClaimsPrincipal principal)
{
var identity = principal.GetIdentity();
if (identity?.Permissions == null) return false;
return identity.Permissions.Value.HasFlag(Permissions.System);
}
/// <summary>
/// 获取当前用户信息
/// 未授权用户返回 null
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static async Task<VmUserInfo?> GetUserInfo(this HttpContext context)
{
var auth = await context.AuthenticateAsync(Program.AuthorizeCookieName);
if (auth.Succeeded && auth.Principal?.IsLogin() == true)
{
return auth.Principal.GetIdentity();
}
return null;
}
public static bool IsLogin(this ClaimsPrincipal? principal)
{
return principal?.Identity?.IsAuthenticated == true;
}
/// <summary>
/// 获取SessionId
/// </summary>
/// <param name="controller"></param>
/// <returns></returns>
public static string? SessionId(this Controller controller)
{
return controller.ViewData["SessionId"]?.ToString();
}
/// <summary>
/// 获取IP地址
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public static string GetIpAddress(this HttpRequest? request)
{
if (request == null) return "";
#if DEBUG
return "113.110.235.52";
#endif
var xff = request.Headers["X-Forwarded-For"];
return string.IsNullOrEmpty(xff)
? request.HttpContext.Connection.RemoteIpAddress.ToString()
: xff.ToString();
}
/// <summary>
/// 设置标题
/// </summary>
/// <param name="controller"></param>
/// <param name="title"></param>
public static void SetTitle(this Controller controller, string title)
{
controller.ViewData["Title"] = $"{title} - 叫我阿胖";
}
/// <summary>
/// 是否为ajax请求
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public static bool IsAjax(this HttpRequest request)
{
var with = request.Headers["X-Requested-With"];
return string.Equals(with, "XMLHttpRequest", StringComparison.OrdinalIgnoreCase);
}
public static async Task<List<SelectListItem>> ArticleTagsAsync(this IArticleService articleService)
{
var tags = await articleService.GetAllTagsAsync();
return tags.Select(x => new SelectListItem(x, x)).ToList();
}
/// <summary>
/// 获取枚举描述
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
public static string GetDescription(this Enum e)
{
var value = e.ToString();
var attribute = e.GetType().GetField(value)?.GetCustomAttribute<DescriptionAttribute>();
return attribute?.Description ?? "";
}
/// <summary>
/// 个性化显示文件大小
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
public static string FileSize(this long length)
{
var sizeText = length + " bytes";
if (length > 1024m && length < 1024m * 1024m * 3)
{
sizeText = (length / 1024m).ToString("F") + " KB";
}
else if (length > 1024m * 1024m * 3 && length < 1024m * 1024m * 1024m)
{
sizeText = (length / 1024m / 1024m).ToString("F") + " MB";
}
else if (length > 1024m * 1024m * 1024m)
{
sizeText = (length / 1024m / 1024m / 1024m).ToString("F") + " GB";
}
return sizeText;
}
public static Dictionary<string, List<string>> GetPublicAction()
{
var controllers = Assembly.GetExecutingAssembly().GetExportedTypes()
.Where(x => x.Namespace == "Dpz.Core.Web.Controllers");
var actions = controllers.ToDictionary(x => x.Name, x =>
{
return x.GetMethods().Where(y =>
y.IsPublic &&
y.ReturnType == typeof(Task<IActionResult>) &&
y.GetCustomAttribute<CheckAuthorizeAttribute>() == null)
.Select(y => y.Name)
.ToList();
});
return actions;
}
public static object ToGridManagerSource<T>(this IPagedList<T> source)
{
return new { totals = source.TotalItemCount, data = source };
}
public static IHtmlSanitizer CustomHtmlSanitizer(this IConfiguration configuration)
{
var sanitizer = new HtmlSanitizer();
var rule = configuration.GetSection("XSS").Get<CrossSiteRule>();
if (rule != null)
{
if (rule.Attributes?.Add?.Length > 0)
{
rule.Attributes.Add.ForEach(x => sanitizer.AllowedAttributes.Add(x));
}
if (rule.Attributes?.Remove?.Length > 0)
{
rule.Attributes.Remove.ForEach(x => sanitizer.AllowedAttributes.Remove(x));
}
if (rule.Tags?.Add?.Length > 0)
{
rule.Tags.Add.ForEach(x => sanitizer.AllowedTags.Add(x));
}
if (rule.Tags?.Remove?.Length > 0)
{
rule.Tags.Remove.ForEach(x => sanitizer.AllowedTags.Remove(x));
}
if (rule.CssProperties?.Add?.Length > 0)
{
rule.CssProperties.Add.ForEach(x => sanitizer.AllowedCssProperties.Add(x));
}
if (rule.CssProperties?.Remove?.Length > 0)
{
rule.CssProperties.Remove.ForEach(x => sanitizer.AllowedAttributes.Remove(x));
}
}
return sanitizer;
}
/// <summary>
/// 从markdown转成html,并从html内容中清除链接的跳转平台,并且在新标签页打开
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
public static async Task<string> ClearLinkAsync(this string content)
{
var pipeline = new MarkdownPipelineBuilder()
.UsePipeTables()
.UseTaskLists()
.UseEmphasisExtras()
.UseAutoIdentifiers()
.UseAdvancedExtensions()
.DisableHtml()
.Build();
var detail = Markdown.ToHtml(content, pipeline);
var context = BrowsingContext.New(Configuration.Default);
var document = await context.OpenAsync(y => y.Content(detail));
var images = document.GetElementsByTagName("img");
foreach (var image in images)
{
var src = image.GetAttribute("src");
image.SetAttribute("class", "lazy");
image.SetAttribute("loading", "lazy");
image.SetAttribute("src", $"{Program.CdnBaseAddress}/loaders/bars.svg");
image.SetAttribute("data-src", src ?? $"{Program.CdnBaseAddress}/images/notfound.png");
}
var links = document.GetElementsByTagName("a");
foreach (var item in links)
{
var href = item.GetAttribute("href");
if (href != null)
{
var uri = new Uri(href);
var parameters = HttpUtility.ParseQueryString(uri.Query);
var target = parameters["target"];
if (!string.IsNullOrEmpty(target))
{
item.SetAttribute("href", target);
}
item.SetAttribute("target", "_blank");
}
}
return document.Body?.InnerHtml ?? "";
}
/// <summary>
/// 构建https的URI
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static string ForceHttps(this string url)
{
var uri = new UriBuilder(url);
var hadDefaultPort = uri.Uri.IsDefaultPort;
uri.Scheme = Uri.UriSchemeHttps;
uri.Port = hadDefaultPort ? -1 : uri.Port;
return uri.ToString();
}
public static async Task DeleteMusicAsync(this IObjectStorageOperation objectStorageService, VmMusic music)
{
if (music == null)
throw new ArgumentNullException(nameof(music));
if (string.IsNullOrEmpty(music.MusicUrl))
throw new ArgumentException("property MusicUrl is empty or null", nameof(music.MusicUrl));
await objectStorageService.DeleteAsync(music.MusicUrl);
if (!string.IsNullOrEmpty(music.CoverUrl))
await objectStorageService.DeleteAsync(music.CoverUrl);
if (!string.IsNullOrEmpty(music.LyricUrl))
await objectStorageService.DeleteAsync(music.LyricUrl);
}
public static string GetUpyunHost(this IConfiguration configuration)
{
var host = configuration["upyun:Host"];
if (string.IsNullOrEmpty(host))
throw new Exception("no upyun.Host node");
return host;
}
public static ModelStateResult CheckModelState(this ModelStateDictionary modelState)
{
if (modelState.IsValid)
{
var messages = modelState
.SelectMany(x => x.Value?.Errors ?? new ModelErrorCollection())
.Select(x => x.ErrorMessage)
.Where(x => !string.IsNullOrEmpty(x))
.ToList();
if (messages.Count == 0)
{
return new ModelStateResult(false, []);
}
return new ModelStateResult(true, messages);
}
return new ModelStateResult(false, []);
}
}