diff --git a/BTCPayServer/Controllers/AppsController.Crowdfund.cs b/BTCPayServer/Controllers/AppsController.Crowdfund.cs index ff20089f5..5727ee368 100644 --- a/BTCPayServer/Controllers/AppsController.Crowdfund.cs +++ b/BTCPayServer/Controllers/AppsController.Crowdfund.cs @@ -71,7 +71,7 @@ namespace BTCPayServer.Controllers try { - _AppService.Parse(vm.PerksTemplate, vm.TargetCurrency).ToString(); + vm.PerksTemplate = _AppService.SerializeTemplate(_AppService.Parse(vm.PerksTemplate, vm.TargetCurrency)); } catch { diff --git a/BTCPayServer/Controllers/AppsController.PointOfSale.cs b/BTCPayServer/Controllers/AppsController.PointOfSale.cs index 7d76c780c..6830c2fc8 100644 --- a/BTCPayServer/Controllers/AppsController.PointOfSale.cs +++ b/BTCPayServer/Controllers/AppsController.PointOfSale.cs @@ -165,7 +165,7 @@ namespace BTCPayServer.Controllers ModelState.AddModelError(nameof(vm.Currency), "Invalid currency"); try { - _AppService.Parse(vm.Template, vm.Currency); + vm.Template = _AppService.SerializeTemplate(_AppService.Parse(vm.Template, vm.Currency)); } catch { diff --git a/BTCPayServer/Services/Apps/AppService.cs b/BTCPayServer/Services/Apps/AppService.cs index a4ae7783b..431d26d97 100644 --- a/BTCPayServer/Services/Apps/AppService.cs +++ b/BTCPayServer/Services/Apps/AppService.cs @@ -18,6 +18,7 @@ using NBitcoin; using NBitcoin.DataEncoders; using Newtonsoft.Json.Linq; using NUglify.Helpers; +using YamlDotNet.Core; using YamlDotNet.RepresentationModel; using YamlDotNet.Serialization; using static BTCPayServer.Models.AppViewModels.ViewCrowdfundViewModel; @@ -279,7 +280,10 @@ namespace BTCPayServer.Services.Apps itemNode.Add("price", new YamlScalarNode(item.Price.Value.ToStringInvariant())); if (!string.IsNullOrEmpty(item.Description)) { - itemNode.Add("description", new YamlScalarNode(item.Description)); + itemNode.Add("description", new YamlScalarNode(item.Description) + { + Style = ScalarStyle.DoubleQuoted + }); } if (!string.IsNullOrEmpty(item.Image)) { @@ -290,6 +294,16 @@ namespace BTCPayServer.Services.Apps { itemNode.Add("inventory", new YamlScalarNode(item.Inventory.ToString())); } + + if (!string.IsNullOrEmpty(item.BuyButtonText)) + { + itemNode.Add("buyButtonText", new YamlScalarNode(item.BuyButtonText)); + } + + if (item.PaymentMethods?.Any() is true) + { + itemNode.Add("payment_methods", new YamlSequenceNode(item.PaymentMethods.Select(s=> new YamlScalarNode(s)))); + } mappingNode.Add(item.Id, itemNode); } @@ -306,7 +320,7 @@ namespace BTCPayServer.Services.Apps var root = (YamlMappingNode)stream.Documents[0].RootNode; return root .Children - .Select(kv => new PosHolder { Key = (kv.Key as YamlScalarNode)?.Value, Value = kv.Value as YamlMappingNode }) + .Select(kv => new PosHolder(_HtmlSanitizer) { Key = _HtmlSanitizer.Sanitize((kv.Key as YamlScalarNode)?.Value), Value = kv.Value as YamlMappingNode }) .Where(kv => kv.Value != null) .Select(c => new ViewPointOfSaleViewModel.Item() { @@ -385,6 +399,13 @@ namespace BTCPayServer.Services.Apps private class PosHolder { + private readonly HtmlSanitizer _htmlSanitizer; + + public PosHolder(HtmlSanitizer htmlSanitizer) + { + _htmlSanitizer = htmlSanitizer; + } + public string Key { get; set; } public YamlMappingNode Value { get; set; } @@ -399,7 +420,8 @@ namespace BTCPayServer.Services.Apps public string GetDetailString(string field) { - return GetDetail(field).FirstOrDefault()?.Value?.Value; + var raw = GetDetail(field).FirstOrDefault()?.Value?.Value; + return raw is null ? null : _htmlSanitizer.Sanitize(raw); } public string[] GetDetailStringList(string field) { @@ -407,7 +429,7 @@ namespace BTCPayServer.Services.Apps { return null; } - return sequenceNode.Children.Select(node => (node as YamlScalarNode)?.Value).Where(s => s != null).ToArray(); + return sequenceNode.Children.Select(node => (node as YamlScalarNode)?.Value).Where(s => s != null).Select(s=> _htmlSanitizer.Sanitize(s)).ToArray(); } } private class PosScalar diff --git a/BTCPayServer/Views/Apps/TemplateEditor.cshtml b/BTCPayServer/Views/Apps/TemplateEditor.cshtml index 054d32e4d..b6f50e9ff 100644 --- a/BTCPayServer/Views/Apps/TemplateEditor.cshtml +++ b/BTCPayServer/Views/Apps/TemplateEditor.cshtml @@ -211,6 +211,13 @@ $(function() { } if (productProperty.indexOf('description:') !== -1) { description =productProperty.replace('description:', '').trim(); + if (description.startsWith('"') && description.endsWith('"')){ + description = description.substr(1, description.length-2); + } + description = description + .replaceAll("
", "\n") + .replaceAll("
", "\n") + .replaceAll('\\"', '"') } if (productProperty.indexOf('image:') !== -1) { image = productProperty.replace('image:', '').trim(); @@ -236,7 +243,7 @@ $(function() { title: title, price: price, image: image || null, - description: description || '', + description: description || '', custom: custom === "true", buyButtonText: buyButtonText, inventory: isNaN(inventory)? null: inventory, @@ -266,7 +273,7 @@ $(function() { ' title: ' + title + '\n'; if (description) { - template += ' description: ' + description + '\n'; + template += ' description: "' + description.replaceAll("\n", "
").replaceAll('"', '\\"') + '"\n'; } if (image) { template += ' image: ' + image + '\n'; diff --git a/BTCPayServer/Views/AppsPublic/PointOfSale/Cart.cshtml b/BTCPayServer/Views/AppsPublic/PointOfSale/Cart.cshtml index fb0465b67..4c5ad2290 100644 --- a/BTCPayServer/Views/AppsPublic/PointOfSale/Cart.cshtml +++ b/BTCPayServer/Views/AppsPublic/PointOfSale/Cart.cshtml @@ -248,7 +248,7 @@
@item.Title
@if (!String.IsNullOrWhiteSpace(description)) { -

@description

+

@Safe.Raw(description))

}