This commit is contained in:
Александр Бабаев 2024-03-11 23:32:03 +03:00
parent bb29af7cff
commit 2a66cf7b61
5 changed files with 196 additions and 75 deletions

View File

@ -8,7 +8,7 @@
<RootNamespace>anbs_cp.Database</RootNamespace> <RootNamespace>anbs_cp.Database</RootNamespace>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageId>ANBSoftware.ComponentsPack.Database</PackageId> <PackageId>ANBSoftware.ComponentsPack.Database</PackageId>
<Version>2024.2.6.0</Version> <Version>2024.3.11.0</Version>
<Company>Александр Бабаев</Company> <Company>Александр Бабаев</Company>
<Product>Набор компонентов ANB Software для работы с БД</Product> <Product>Набор компонентов ANB Software для работы с БД</Product>
<Description>Библиотека полезных методов языка C# для работы с базами данных</Description> <Description>Библиотека полезных методов языка C# для работы с базами данных</Description>
@ -16,10 +16,11 @@
<PackageProjectUrl>https://git.babaev-an.ru/babaev-an/anbsoftware_componentspack</PackageProjectUrl> <PackageProjectUrl>https://git.babaev-an.ru/babaev-an/anbsoftware_componentspack</PackageProjectUrl>
<RepositoryUrl>https://git.babaev-an.ru/babaev-an/anbsoftware_componentspack</RepositoryUrl> <RepositoryUrl>https://git.babaev-an.ru/babaev-an/anbsoftware_componentspack</RepositoryUrl>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<Authors>Александр Бабаев</Authors>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapper" Version="2.1.28" /> <PackageReference Include="Dapper" Version="2.1.35" />
<PackageReference Include="MySqlConnector" Version="2.3.5" /> <PackageReference Include="MySqlConnector" Version="2.3.5" />
</ItemGroup> </ItemGroup>

View File

@ -1,5 +1,4 @@
using anbs_cp.ForNet.Enums; using anbs_cp.ForNet.Enums;
using Ganss.Xss; using Ganss.Xss;
namespace anbs_cp.ForNet.Classes; namespace anbs_cp.ForNet.Classes;
@ -9,47 +8,53 @@ namespace anbs_cp.ForNet.Classes;
/// </summary> /// </summary>
public static class Sanitizer public static class Sanitizer
{ {
#region Свойства
/// <summary> /// <summary>
/// Очистка текста по уровню очистки /// Все теги запрещены
/// </summary> /// </summary>
/// <param name="html">Текст</param> public static SanitizerAllowedHtml AllowedNone => GetNone();
/// <param name="level">Уровень очистка</param>
/// <returns>Очищенный текст</returns> /// <summary>
public static string SanitizeHtml (string html, ESanitizerLevel level) /// Все теги разрешены
/// </summary>
public static SanitizerAllowedHtml AllowedAll => GetAll();
/// <summary>
/// Оставлены только текстовые теги
/// </summary>
public static SanitizerAllowedHtml AllowedTextOnly => GetTextFormatOnly();
/// <summary>
/// Оставлены только текстовые теги, а также img и a
/// </summary>
public static SanitizerAllowedHtml AllowedImageAndLinks => GetImageAndLinks();
/// <summary>
/// Применяются все теги, кроме iframe
/// </summary>
public static SanitizerAllowedHtml AllowedAllExceptIFrame => GetAllExceptIFrame();
#endregion
#region Методы
/// <summary>
/// Очистка html-кода <paramref name="html"/> согласно параметрам <paramref name="allowedHtml"/>
/// </summary>
/// <param name="html">HTML-код</param>
/// <param name="allowedHtml">Параметры очистки</param>
/// <returns>Очищенный html-кода</returns>
private static string SanitizeHtml(string html, SanitizerAllowedHtml allowedHtml)
{ {
// Создаю очиститель
HtmlSanitizer sanitizer = new() HtmlSanitizer sanitizer = new()
{ {
// - сохраняю дочерние удалённых
KeepChildNodes = true KeepChildNodes = true
}; };
switch (level) // Выключаю все параметры HTML
{
case ESanitizerLevel.NoTags:
PrepareForNone(ref sanitizer);
break;
case ESanitizerLevel.TextFormatOnly:
PrepareForTextFormatOnly(ref sanitizer);
break;
case ESanitizerLevel.ImageAndLinks:
PrepareForImageAndLinks(ref sanitizer);
break;
case ESanitizerLevel.AllExceptIFrame:
PrepareForAllExceptIFrame(ref sanitizer);
break;
default:
PrepareForNone(ref sanitizer);
break;
}
return level != ESanitizerLevel.All ? sanitizer.Sanitize(html) : html;
}
/// <summary>
/// Очистка всех тегов
/// </summary>
/// <param name="sanitizer"><see cref="HtmlSanitizer"/></param>
private static void PrepareForNone (ref HtmlSanitizer sanitizer)
{
sanitizer.AllowedTags.Clear(); sanitizer.AllowedTags.Clear();
sanitizer.AllowedSchemes.Clear(); sanitizer.AllowedSchemes.Clear();
sanitizer.AllowedCssProperties.Clear(); sanitizer.AllowedCssProperties.Clear();
@ -57,66 +62,146 @@ public static class Sanitizer
sanitizer.AllowedAttributes.Clear(); sanitizer.AllowedAttributes.Clear();
sanitizer.AllowedAtRules.Clear(); sanitizer.AllowedAtRules.Clear();
sanitizer.AllowDataAttributes = false; sanitizer.AllowDataAttributes = false;
// Загружаю параметры
sanitizer.AllowedTags.UnionWith(allowedHtml.AllowedTags);
sanitizer.AllowedSchemes.UnionWith(allowedHtml.AllowedSchemes);
sanitizer.AllowedCssProperties.UnionWith(allowedHtml.AllowedCssProperties);
sanitizer.AllowedClasses.UnionWith(allowedHtml.AllowedClasses);
sanitizer.AllowedAttributes.UnionWith(allowedHtml.AllowedAttributes);
sanitizer.AllowDataAttributes = allowedHtml.AllowDataAttributes;
// Очищаю html согласно правилам
return sanitizer.Sanitize(html);
} }
/// <summary> /// <summary>
/// Остаются только текстовые теги /// Очистка html-кода по уровню очистки
/// </summary> /// </summary>
/// <param name="sanitizer"><see cref="HtmlSanitizer"/></param> /// <param name="html">HTML-код</param>
private static void PrepareForTextFormatOnly (ref HtmlSanitizer sanitizer) /// <param name="level">Уровень очистка</param>
/// <returns>Очищенный html-код</returns>
public static string SanitizeHtml(string html, ESanitizerLevel level)
{ {
string[] allowedTags = // Получаю параметры очистки
SanitizerAllowedHtml allowedHtml = level switch
{ {
"strong", "b", "em", "i", "u", "hr", "strike", "div", "ol", "ul", "li", "p", "span", "h1", "h2", "h3", "h4" ESanitizerLevel.NoTags => AllowedNone,
}; ESanitizerLevel.TextFormatOnly => AllowedTextOnly,
string[] allowedAttributes = ESanitizerLevel.ImageAndLinks => AllowedImageAndLinks,
{ ESanitizerLevel.AllExceptIFrame => AllowedAllExceptIFrame,
"align", "bgcolor", "border", "cellpadding", "cellspacing", "charset", "checked", "class", "clear", "color", "cols", "colspan", ESanitizerLevel.All => AllowedAll,
"datetime", "disabled", "headers", "height", "high", "hspace", "label", "lang", "list", "low", "max", "maxlength", "min", "name", var _ => AllowedAll
"nowrap", "placeholder", "required", "rev", "rows", "rowspan", "rules", "selected", "size", "span", "spellcheck", "style", "summary",
"tabindex", "title", "type", "valign", "value", "vspace", "width", "wrap"
}; };
sanitizer.AllowedTags.Clear(); // Очищаю код и возвращаю результат очистки
return SanitizeHtml(html, allowedHtml);
}
sanitizer.AllowedTags.UnionWith(allowedTags); #endregion
sanitizer.AllowedAtRules.Clear(); #region Вспомогателдьные методы
sanitizer.AllowDataAttributes = false;
sanitizer.AllowedAttributes.Clear(); /// <summary>
sanitizer.AllowedAttributes.UnionWith(allowedAttributes); /// Получаю параметры, удаляющие все теги
/// </summary>
/// <returns>Параметры очистки</returns>
private static SanitizerAllowedHtml GetNone() =>
new()
{
AllowedTags = [],
AllowedAttributes = [],
AllowedCssProperties = [],
AllowedClasses = [],
AllowedSchemes = [],
AllowDataAttributes = false
};
/// <summary>
/// Получаю параметры по умолчанию (разрешающие все теги)
/// </summary>
/// <returns>Параметры очистки</returns>
private static SanitizerAllowedHtml GetAll()
{
// Создаю очиститель
HtmlSanitizer sanitizer = new();
// Создаю модель
return new()
{
AllowedTags = sanitizer.AllowedTags.ToList(),
AllowedAttributes = sanitizer.AllowedAttributes.ToList(),
AllowedCssProperties = sanitizer.AllowedCssProperties.ToList(),
AllowedClasses = sanitizer.AllowedClasses.ToList(),
AllowedSchemes = sanitizer.AllowedSchemes.ToList(),
AllowDataAttributes = true
};
} }
/// <summary> /// <summary>
/// Остаются текстовые теги + изображения и ссылки /// Параметры, оставляющие только текстовые теги
/// </summary> /// </summary>
/// <param name="sanitizer"><see cref="HtmlSanitizer"/></param> /// <returns>Параметры очистки</returns>
private static void PrepareForImageAndLinks (ref HtmlSanitizer sanitizer) private static SanitizerAllowedHtml GetTextFormatOnly() =>
new()
{
AllowedTags =
[
"strong", "b", "em", "i", "u", "hr", "strike", "div", "ol", "ul", "li", "p", "span", "h1", "h2", "h3",
"h4"
],
// ReSharper disable StringLiteralTypo
AllowedAttributes =
[
"align", "bgcolor", "border", "cellpadding", "cellspacing", "charset", "checked", "class", "clear",
"color",
"cols", "colspan", "datetime", "disabled", "headers", "height", "high", "hspace", "label", "lang",
"list",
"low", "max", "maxlength", "min", "name", "nowrap", "placeholder", "required", "rev", "rows", "rowspan",
"rules", "selected", "size", "span", "spellcheck", "style", "summary", "tabindex", "title", "type",
"valign",
"value", "vspace", "width", "wrap"
]
// ReSharper restore StringLiteralTypo
};
/// <summary>
/// Параметры, оставляющие только текстовые теги, а также img и a
/// </summary>
/// <returns>Параметры очистки</returns>
private static SanitizerAllowedHtml GetImageAndLinks()
{ {
PrepareForTextFormatOnly(ref sanitizer); // Получаю текстовые параметры
string[] allowedTags = SanitizerAllowedHtml result = AllowedTextOnly;
{
"a", "img"
};
string[] allowedAttributes = // Добавляю теги
{ result.AllowedTags.AddRange(["a", "img"]);
"alt", "href", "hreflang", "nohref", "rel", "src", "target"
};
sanitizer.AllowedTags.UnionWith(allowedTags); // Добавляю параметры
// ReSharper disable StringLiteralTypo
result.AllowedAttributes.AddRange(["alt", "href", "hreflang", "nohref", "rel", "src", "target"]);
// ReSharper restore StringLiteralTypo
sanitizer.AllowedAttributes.UnionWith(allowedAttributes); // Возвращаю результат
return result;
} }
/// <summary> /// <summary>
/// Остаются все теги, за исключением IFRAME /// Применяются все теги, кроме iframe
/// </summary> /// </summary>
/// <param name="sanitizer"><see cref="HtmlSanitizer"/></param> /// <returns>Параметры очистки</returns>
private static void PrepareForAllExceptIFrame (ref HtmlSanitizer sanitizer) private static SanitizerAllowedHtml GetAllExceptIFrame()
{ {
sanitizer.AllowedTags.Remove("iframe"); // Получаю все параметры
SanitizerAllowedHtml result = AllowedAll;
// Удаляю iframe
result.AllowedTags.Remove("iframe");
// Возвращаю результат
return result;
} }
#endregion
} }

View File

@ -0,0 +1,37 @@
namespace anbs_cp.ForNet.Classes;
/// <summary>
/// Допустимые параметры для очистки HTML
/// </summary>
public sealed class SanitizerAllowedHtml
{
/// <summary>
/// Допустимые теги
/// </summary>
public List<string> AllowedTags { get; set; } = [];
/// <summary>
/// Допустимые аттрибуты
/// </summary>
public List<string> AllowedAttributes { get; set; } = [];
/// <summary>
/// Допустимые параметры css
/// </summary>
public List<string> AllowedCssProperties { get; set; } = [];
/// <summary>
/// Допустимые классы
/// </summary>
public List<string> AllowedClasses { get; set; } = [];
/// <summary>
/// Допустимые схемы
/// </summary>
public List<string> AllowedSchemes { get; set; } = [];
/// <summary>
/// Допустимы ли data-атрибуты
/// </summary>
public bool AllowDataAttributes { get; set; } = false;
}

View File

@ -6,7 +6,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageId>ANBSoftware.ComponentsPackForNet</PackageId> <PackageId>ANBSoftware.ComponentsPackForNet</PackageId>
<Version>2024.2.24.0</Version> <Version>2024.3.11.0</Version>
<Authors>Александр Бабаев</Authors> <Authors>Александр Бабаев</Authors>
<Product>Набор компонентов ANB Software для ASP.NET Core</Product> <Product>Набор компонентов ANB Software для ASP.NET Core</Product>
<Description>Библиотека полезных методов языка C# для ASP.NET Core</Description> <Description>Библиотека полезных методов языка C# для ASP.NET Core</Description>

View File

@ -1,2 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp120</s:String></wpf:ResourceDictionary>