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 @@
@description
+@Safe.Raw(description))
}