diff --git a/BTCPayServer.Abstractions/Services/Safe.cs b/BTCPayServer.Abstractions/Services/Safe.cs index b01c326e1..1ffd5134c 100644 --- a/BTCPayServer.Abstractions/Services/Safe.cs +++ b/BTCPayServer.Abstractions/Services/Safe.cs @@ -35,33 +35,35 @@ namespace BTCPayServer.Abstractions.Services return _htmlHelper.Raw(_jsonHelper.Serialize(model)); } + public IHtmlContent Meta(string inputHtml) => _htmlHelper.Raw(RawMeta(inputHtml, out _)); + public string RawMeta(string inputHtml, out bool isHtmlModified) { bool bHtmlModified; - HtmlSanitizer _metaSanitizer = new HtmlSanitizer(); + HtmlSanitizer sane = new HtmlSanitizer(); - _metaSanitizer.AllowedTags.Clear(); - _metaSanitizer.AllowedTags.Add("meta"); + sane.AllowedTags.Clear(); + sane.AllowedTags.Add("meta"); - _metaSanitizer.AllowedAttributes.Clear(); - _metaSanitizer.AllowedAttributes.Add("name"); - _metaSanitizer.AllowedAttributes.Add("http-equiv"); - _metaSanitizer.AllowedAttributes.Add("content"); - _metaSanitizer.AllowedAttributes.Add("value"); - _metaSanitizer.AllowedAttributes.Add("property"); + sane.AllowedAttributes.Clear(); + sane.AllowedAttributes.Add("name"); + sane.AllowedAttributes.Add("http-equiv"); + sane.AllowedAttributes.Add("content"); + sane.AllowedAttributes.Add("value"); + sane.AllowedAttributes.Add("property"); - _metaSanitizer.AllowDataAttributes = false; + sane.AllowDataAttributes = false; - _metaSanitizer.RemovingTag += (sender, e) => bHtmlModified = true; - _metaSanitizer.RemovingAtRule += (sender, e) => bHtmlModified = true; - _metaSanitizer.RemovingAttribute += (sender, e) => bHtmlModified = true; - _metaSanitizer.RemovingComment += (sender, e) => bHtmlModified = true; - _metaSanitizer.RemovingCssClass += (sender, e) => bHtmlModified = true; - _metaSanitizer.RemovingStyle += (sender, e) => bHtmlModified = true; + sane.RemovingTag += (sender, e) => bHtmlModified = true; + sane.RemovingAtRule += (sender, e) => bHtmlModified = true; + sane.RemovingAttribute += (sender, e) => bHtmlModified = true; + sane.RemovingComment += (sender, e) => bHtmlModified = true; + sane.RemovingCssClass += (sender, e) => bHtmlModified = true; + sane.RemovingStyle += (sender, e) => bHtmlModified = true; bHtmlModified = false; - var sRet = _metaSanitizer.Sanitize(inputHtml); + var sRet = sane.Sanitize(inputHtml); isHtmlModified = bHtmlModified; return sRet; diff --git a/BTCPayServer/Controllers/GreenField/GreenfieldAppsController.cs b/BTCPayServer/Controllers/GreenField/GreenfieldAppsController.cs index 0175b618d..8cb2bd560 100644 --- a/BTCPayServer/Controllers/GreenField/GreenfieldAppsController.cs +++ b/BTCPayServer/Controllers/GreenField/GreenfieldAppsController.cs @@ -6,6 +6,7 @@ using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Contracts; using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Models; +using BTCPayServer.Abstractions.Services; using BTCPayServer.Client; using BTCPayServer.Client.Models; using BTCPayServer.Data; @@ -38,13 +39,16 @@ namespace BTCPayServer.Controllers.Greenfield private readonly UserManager _userManager; private readonly IFileService _fileService; + public Safe Safe { get; } + public GreenfieldAppsController( AppService appService, UriResolver uriResolver, StoreRepository storeRepository, CurrencyNameTable currencies, IFileService fileService, - UserManager userManager + UserManager userManager, + Safe safe ) { _appService = appService; @@ -53,6 +57,7 @@ namespace BTCPayServer.Controllers.Greenfield _currencies = currencies; _fileService = fileService; _userManager = userManager; + Safe = safe; } [HttpPost("~/api/v1/stores/{storeId}/apps/crowdfund")] @@ -305,7 +310,8 @@ namespace BTCPayServer.Controllers.Greenfield var parsedSounds = ValidateStringArray(request.Sounds); var parsedColors = ValidateStringArray(request.AnimationColors); Enum.TryParse(request.ResetEvery.ToString(), true, out var resetEvery); - + if (request.HtmlMetaTags is not null) + request.HtmlMetaTags = Safe.RawMeta(request.HtmlMetaTags, out _); return new CrowdfundSettings { Title = request.Title?.Trim() ?? request.AppName, @@ -342,6 +348,8 @@ namespace BTCPayServer.Controllers.Greenfield private PointOfSaleSettings ToPointOfSaleSettings(PointOfSaleAppRequest request, PointOfSaleSettings settings) { Enum.TryParse(request.DefaultView.ToString(), true, out var defaultView); + if (request.HtmlMetaTags is not null) + request.HtmlMetaTags = Safe.RawMeta(request.HtmlMetaTags, out _); return new PointOfSaleSettings { diff --git a/BTCPayServer/Plugins/Crowdfund/Controllers/UICrowdfundController.cs b/BTCPayServer/Plugins/Crowdfund/Controllers/UICrowdfundController.cs index 26eb379a4..162ddd6d5 100644 --- a/BTCPayServer/Plugins/Crowdfund/Controllers/UICrowdfundController.cs +++ b/BTCPayServer/Plugins/Crowdfund/Controllers/UICrowdfundController.cs @@ -588,7 +588,7 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers }); if (wasHtmlModified) { - TempData[WellKnownTempData.ErrorMessage] = StringLocalizer["Only meta tags are allowed in HTML headers. Your HTML code has been cleaned up accordingly."].Value; + TempData[WellKnownTempData.SuccessMessage] = StringLocalizer["Only meta tags are allowed in HTML headers. Your HTML code has been cleaned up accordingly."].Value; } else { diff --git a/BTCPayServer/Plugins/PointOfSale/Controllers/UIPointOfSaleController.cs b/BTCPayServer/Plugins/PointOfSale/Controllers/UIPointOfSaleController.cs index 29830b574..a79eb4034 100644 --- a/BTCPayServer/Plugins/PointOfSale/Controllers/UIPointOfSaleController.cs +++ b/BTCPayServer/Plugins/PointOfSale/Controllers/UIPointOfSaleController.cs @@ -729,7 +729,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers await _appService.UpdateOrCreateApp(app); if (wasHtmlModified) { - TempData[WellKnownTempData.ErrorMessage] = StringLocalizer["Only meta tags are allowed in HTML headers. Your HTML code has been cleaned up accordingly."].Value; + TempData[WellKnownTempData.SuccessMessage] = StringLocalizer["Only meta tags are allowed in HTML headers. Your HTML code has been cleaned up accordingly."].Value; } else { TempData[WellKnownTempData.SuccessMessage] = StringLocalizer["App updated"].Value; } diff --git a/BTCPayServer/Views/Shared/Crowdfund/Public/ViewCrowdfund.cshtml b/BTCPayServer/Views/Shared/Crowdfund/Public/ViewCrowdfund.cshtml index 62a4e2f45..9ecbc7537 100644 --- a/BTCPayServer/Views/Shared/Crowdfund/Public/ViewCrowdfund.cshtml +++ b/BTCPayServer/Views/Shared/Crowdfund/Public/ViewCrowdfund.cshtml @@ -35,8 +35,7 @@ object-fit: scale-down; } - @* Html.Raw OK here since Html has been cleaned before in controller *@ - @Html.Raw(Model.HtmlMetaTags) + @this.Safe.Meta(Model.HtmlMetaTags) diff --git a/BTCPayServer/Views/Shared/PointOfSale/Public/_Layout.cshtml b/BTCPayServer/Views/Shared/PointOfSale/Public/_Layout.cshtml index 433bd37e4..2a0fec927 100644 --- a/BTCPayServer/Views/Shared/PointOfSale/Public/_Layout.cshtml +++ b/BTCPayServer/Views/Shared/PointOfSale/Public/_Layout.cshtml @@ -5,6 +5,7 @@ @inject IWebHostEnvironment WebHostEnvironment @inject SettingsRepository SettingsRepository @inject BTCPayServerEnvironment Env + @model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel @{ ViewData["Title"] = string.IsNullOrEmpty(Model.Title) ? Model.StoreName : Model.Title; @@ -40,8 +41,7 @@ - @* Html.Raw OK here since Html has been cleaned before in controller *@ - @Html.Raw(Model.HtmlMetaTags) + @this.Safe.Meta(Model.HtmlMetaTags) @await RenderSectionAsync("PageHeadContent", false)