From 43ae15b71cbf31b7fc83b7b47df3442b27a9b54d Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Thu, 18 Jul 2024 10:52:39 +0200 Subject: [PATCH] =?UTF-8?q?Refaktorierung=20f=C3=BCr=20HTML-Sanitization?= =?UTF-8?q?=20mit=20neuer=20Sanitizer-Klasse.=20-=20Bestehende=20Sanitizat?= =?UTF-8?q?ion=20=C3=BCberarbeitet.=20-=20Injektionsmethode=20f=C3=BCr=20f?= =?UTF-8?q?lexible=20Konfiguration=20implementiert.=20-=20Wichtige=20Absch?= =?UTF-8?q?nitte=20in=20`show-envelope`=20hervorgehoben.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Resources/Resource.de-DE.resx | 4 ++-- .../Resources/Resource.en-US.resx | 4 ++-- EnvelopeGenerator.Web/Program.cs | 13 +++++++++---- .../Sanitizers/DIExtensions.cs | 17 +++++++++++++++++ .../Sanitizers/HighlightHtmlSanitizer.cs | 8 ++++++++ .../Views/Home/ShowEnvelope.cshtml | 15 ++++++--------- .../Views/_ViewImports.cshtml | 2 ++ EnvelopeGenerator.Web/wwwroot/css/site.css | 16 +++++++++++++++- EnvelopeGenerator.Web/wwwroot/js.7z | Bin 11792 -> 0 bytes 9 files changed, 61 insertions(+), 18 deletions(-) create mode 100644 EnvelopeGenerator.Web/Sanitizers/DIExtensions.cs create mode 100644 EnvelopeGenerator.Web/Sanitizers/HighlightHtmlSanitizer.cs delete mode 100644 EnvelopeGenerator.Web/wwwroot/js.7z diff --git a/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx b/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx index e15f5066..16e01cec 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx @@ -145,10 +145,10 @@ Englisch - Sie müssen {0} Vorgang unterzeichen. Bitte prüfen Sie die Seite {1}. + Sie müssen {0} Vorgang unterzeichen. <span class="highlight highlight-envelope-info-1">Bitte prüfen Sie die Seite {1}</span>. - Erstellt am {0} von {1}. Sie können den Absender über <a href="mailto:{2}?subject={3}&body=Sehr%20geehrter%20{4}%20{5},%0A%0A%0A">{6}</a> kontaktieren. + Erstellt am {0} von {1}. Sie können den Absender über <span class="highlight highlight-envelope-info-2"><a href="mailto:{2}?subject={3}&body=Sehr%20geehrter%20{4}%20{5},%0A%0A%0A">{6}</a></span> kontaktieren. Abschließen diff --git a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx index 48217dd7..b95cb7e4 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx @@ -145,10 +145,10 @@ English - You have to sign {0} process. Please check page {1}. + You have to sign {0} process. <span class="highlight highlight-envelope-info-1">Please check page {1}</span>. - Created on {0} by {1}. You can contact the sender via <a href="mailto:{2}?subject={3}&body=Dear%20{4}%20{5},%0A%0A%0A">{6}</a>. + Created on {0} by {1}. You can contact the sender via <span class="highlight highlight-envelope-info-2"><a href="mailto:{2}?subject={3}&body=Dear%20{4}%20{5},%0A%0A%0A">{6}</a></span>. Finalize diff --git a/EnvelopeGenerator.Web/Program.cs b/EnvelopeGenerator.Web/Program.cs index 431c989e..f5064f51 100644 --- a/EnvelopeGenerator.Web/Program.cs +++ b/EnvelopeGenerator.Web/Program.cs @@ -16,6 +16,7 @@ using Microsoft.Extensions.Options; using EnvelopeGenerator.Application; using DigitalData.EmailProfilerDispatcher; using EnvelopeGenerator.Infrastructure; +using EnvelopeGenerator.Web.Sanitizers; var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger(); logger.Info("Logging initialized!"); @@ -126,11 +127,15 @@ try builder.Services.AddSingleton(HtmlEncoder.Default); builder.Services.AddSingleton(UrlEncoder.Default); - builder.Services.AddSingleton(_ => + builder.Services.AddSanitizer(); + builder.Services.AddSanitizer(s => { - var sanitizer = new HtmlSanitizer(); - //configure sanitzer - return sanitizer; + s.AllowedTags.Add("a"); + s.AllowedAttributes.Add("href"); + s.AllowedAttributes.Add("class"); + s.AllowedClasses.Add("highlight"); + s.AllowedClasses.Add("highlight-envelope-info-1"); + s.AllowedClasses.Add("highlight-envelope-info-2"); }); // Register the FlagIconCssClass instance as a singleton diff --git a/EnvelopeGenerator.Web/Sanitizers/DIExtensions.cs b/EnvelopeGenerator.Web/Sanitizers/DIExtensions.cs new file mode 100644 index 00000000..65dccfc5 --- /dev/null +++ b/EnvelopeGenerator.Web/Sanitizers/DIExtensions.cs @@ -0,0 +1,17 @@ +using Ganss.Xss; +using Microsoft.Extensions.DependencyInjection; + +namespace EnvelopeGenerator.Web.Sanitizers +{ + public static class DIExtensions + { + public static IServiceCollection AddSanitizer(this IServiceCollection services, Action? optionActions = null) + where THtmlSanitizer : HtmlSanitizer => services + .AddSingleton(serviceProvider => + { + var sanitizer = ActivatorUtilities.CreateInstance(serviceProvider); + optionActions?.Invoke(sanitizer); + return sanitizer; + }); + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Sanitizers/HighlightHtmlSanitizer.cs b/EnvelopeGenerator.Web/Sanitizers/HighlightHtmlSanitizer.cs new file mode 100644 index 00000000..9a3cb148 --- /dev/null +++ b/EnvelopeGenerator.Web/Sanitizers/HighlightHtmlSanitizer.cs @@ -0,0 +1,8 @@ +using Ganss.Xss; + +namespace EnvelopeGenerator.Web.Sanitizers +{ + public class HighlightHtmlSanitizer : HtmlSanitizer + { + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Views/Home/ShowEnvelope.cshtml b/EnvelopeGenerator.Web/Views/Home/ShowEnvelope.cshtml index c91d1334..3a9bc1cd 100644 --- a/EnvelopeGenerator.Web/Views/Home/ShowEnvelope.cshtml +++ b/EnvelopeGenerator.Web/Views/Home/ShowEnvelope.cshtml @@ -38,15 +38,12 @@
@($"{envelope?.Title.TrySanitize(_sanitizer)}")
-

@(string.Format(_localizer[WebKey.EnvelopeInfo1], pages.Count(), stPageIndexes.TrySanitize(_sanitizer)))

-

@Html.Raw(string.Format(_localizer[WebKey.EnvelopeInfo2], - envelope?.AddedWhen.ToString(userCulture?.Info?.DateTimeFormat), - $"{sender?.Prename} {sender?.Name}".TrySanitize(_sanitizer), - sender?.Email.TryEncode(_encoder), - envelope?.Title.TryEncode(_encoder), - sender?.Prename.TryEncode(_encoder), - sender?.Name.TryEncode(_encoder), - sender?.Email.TryEncode(_encoder)).TrySanitize(_sanitizer))

+

@Html.Raw(string.Format(_localizer[WebKey.EnvelopeInfo1], pages.Count(), stPageIndexes).TrySanitize(_hlSanitizer))

+

+ + @Html.Raw(string.Format(_localizer[WebKey.EnvelopeInfo2], envelope?.AddedWhen.ToString(userCulture?.Info?.DateTimeFormat), $"{sender?.Prename} {sender?.Name}", sender?.Email, envelope?.Title, sender?.Prename, sender?.Name, sender?.Email).TrySanitize(_hlSanitizer)) + +

diff --git a/EnvelopeGenerator.Web/Views/_ViewImports.cshtml b/EnvelopeGenerator.Web/Views/_ViewImports.cshtml index 7d1c9b1d..25a878c5 100644 --- a/EnvelopeGenerator.Web/Views/_ViewImports.cshtml +++ b/EnvelopeGenerator.Web/Views/_ViewImports.cshtml @@ -1,10 +1,12 @@ @using EnvelopeGenerator.Web @using EnvelopeGenerator.Web.Models +@using EnvelopeGenerator.Web.Sanitizers @using Microsoft.Extensions.Localization @using EnvelopeGenerator.Application.Resources @inject IStringLocalizer _localizer @inject System.Text.Encodings.Web.UrlEncoder _encoder @inject Ganss.Xss.HtmlSanitizer _sanitizer +@inject HighlightHtmlSanitizer _hlSanitizer @inject Microsoft.AspNetCore.Http.IHttpContextAccessor _accessor @inject Cultures _cultures @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/css/site.css b/EnvelopeGenerator.Web/wwwroot/css/site.css index b9614890..ee387b54 100644 --- a/EnvelopeGenerator.Web/wwwroot/css/site.css +++ b/EnvelopeGenerator.Web/wwwroot/css/site.css @@ -201,7 +201,13 @@ footer#page-footer { min-width: 4vw; } -/* Additional styles for better mobile responsiveness */ +.highlight { + font-weight: 700; + font-size: 13px; +} + + +/* styles for mobile responsiveness */ @media (max-width: 767px) { .navbar { flex-direction: column; @@ -256,3 +262,11 @@ footer#page-footer { max-width: 90%; } } +@media (max-height: 850px) { + .collapse .card-text, .collapsing .card-text { + font-size: 0.5rem; /* Font size reduced */ + margin: 0rem; + padding: 0rem; + } +} + diff --git a/EnvelopeGenerator.Web/wwwroot/js.7z b/EnvelopeGenerator.Web/wwwroot/js.7z deleted file mode 100644 index 79a0f9cf2606c36d25fd07cf85021c0c3a3ab102..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11792 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