mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
do not crash invoice if wellknown metadata keys used with different e… (#2448)
* do not crash invoice if wellknown metadata keys used with different expected types * fix * add bits from alt PR
This commit is contained in:
@@ -2366,7 +2366,9 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
("{ invalidjson file here}",
|
("{ invalidjson file here}",
|
||||||
new Dictionary<string, object>() {{String.Empty, "{ invalidjson file here}"}})
|
new Dictionary<string, object>() {{String.Empty, "{ invalidjson file here}"}})
|
||||||
}
|
},
|
||||||
|
// Duplicate keys should not crash things
|
||||||
|
{("{ \"key\": true, \"key\": true}", new Dictionary<string, object>() {{"key", "True"}})}
|
||||||
};
|
};
|
||||||
|
|
||||||
testCases.ForEach(tuple =>
|
testCases.ForEach(tuple =>
|
||||||
|
|||||||
@@ -903,21 +903,20 @@ namespace BTCPayServer.Controllers
|
|||||||
var jObject = JObject.Parse(posData);
|
var jObject = JObject.Parse(posData);
|
||||||
foreach (var item in jObject)
|
foreach (var item in jObject)
|
||||||
{
|
{
|
||||||
|
|
||||||
switch (item.Value.Type)
|
switch (item.Value.Type)
|
||||||
{
|
{
|
||||||
case JTokenType.Array:
|
case JTokenType.Array:
|
||||||
var items = item.Value.AsEnumerable().ToList();
|
var items = item.Value.AsEnumerable().ToList();
|
||||||
for (var i = 0; i < items.Count; i++)
|
for (var i = 0; i < items.Count; i++)
|
||||||
{
|
{
|
||||||
result.Add($"{item.Key}[{i}]", ParsePosData(items[i].ToString()));
|
result.TryAdd($"{item.Key}[{i}]", ParsePosData(items[i].ToString()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case JTokenType.Object:
|
case JTokenType.Object:
|
||||||
result.Add(item.Key, ParsePosData(item.Value.ToString()));
|
result.TryAdd(item.Key, ParsePosData(item.Value.ToString()));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result.Add(item.Key, item.Value.ToString());
|
result.TryAdd(item.Key, item.Value.ToString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -925,7 +924,7 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
result.Add(string.Empty, posData);
|
result.TryAdd(string.Empty, posData);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using System.IO;
|
|||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices.ComTypes;
|
|
||||||
using BTCPayServer.Abstractions.Contracts;
|
using BTCPayServer.Abstractions.Contracts;
|
||||||
using BTCPayServer.Configuration;
|
using BTCPayServer.Configuration;
|
||||||
using McMaster.NETCore.Plugins;
|
using McMaster.NETCore.Plugins;
|
||||||
@@ -28,7 +27,7 @@ namespace BTCPayServer.Plugins
|
|||||||
|
|
||||||
public static bool IsExceptionByPlugin(Exception exception)
|
public static bool IsExceptionByPlugin(Exception exception)
|
||||||
{
|
{
|
||||||
return _pluginAssemblies.Any(assembly => assembly.FullName.Contains(exception.Source, StringComparison.OrdinalIgnoreCase));
|
return _pluginAssemblies.Any(assembly => assembly?.FullName?.Contains(exception.Source!, StringComparison.OrdinalIgnoreCase) is true);
|
||||||
}
|
}
|
||||||
public static IMvcBuilder AddPlugins(this IMvcBuilder mvcBuilder, IServiceCollection serviceCollection,
|
public static IMvcBuilder AddPlugins(this IMvcBuilder mvcBuilder, IServiceCollection serviceCollection,
|
||||||
IConfiguration config, ILoggerFactory loggerFactory)
|
IConfiguration config, ILoggerFactory loggerFactory)
|
||||||
|
|||||||
@@ -30,70 +30,136 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
seria.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
seria.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
||||||
MetadataSerializer = seria;
|
MetadataSerializer = seria;
|
||||||
}
|
}
|
||||||
public string OrderId { get; set; }
|
|
||||||
[JsonProperty(PropertyName = "buyerName")]
|
[JsonIgnore]
|
||||||
public string BuyerName { get; set; }
|
public string OrderId
|
||||||
[JsonProperty(PropertyName = "buyerEmail")]
|
{
|
||||||
public string BuyerEmail { get; set; }
|
get => GetMetadata<string>("orderId");
|
||||||
[JsonProperty(PropertyName = "buyerCountry")]
|
set => SetMetadata("orderId", value);
|
||||||
public string BuyerCountry { get; set; }
|
}
|
||||||
[JsonProperty(PropertyName = "buyerZip")]
|
[JsonIgnore]
|
||||||
public string BuyerZip { get; set; }
|
public string BuyerName{
|
||||||
[JsonProperty(PropertyName = "buyerState")]
|
get => GetMetadata<string>("buyerName");
|
||||||
public string BuyerState { get; set; }
|
set => SetMetadata("buyerName", value);
|
||||||
[JsonProperty(PropertyName = "buyerCity")]
|
}
|
||||||
public string BuyerCity { get; set; }
|
[JsonIgnore]
|
||||||
[JsonProperty(PropertyName = "buyerAddress2")]
|
public string BuyerEmail {
|
||||||
public string BuyerAddress2 { get; set; }
|
get => GetMetadata<string>("buyerEmail");
|
||||||
[JsonProperty(PropertyName = "buyerAddress1")]
|
set => SetMetadata("buyerEmail", value);
|
||||||
public string BuyerAddress1 { get; set; }
|
}
|
||||||
|
[JsonIgnore]
|
||||||
[JsonProperty(PropertyName = "buyerPhone")]
|
public string BuyerCountry {
|
||||||
public string BuyerPhone { get; set; }
|
get => GetMetadata<string>("buyerCountry");
|
||||||
|
set => SetMetadata("buyerCountry", value);
|
||||||
[JsonProperty(PropertyName = "itemDesc")]
|
}
|
||||||
public string ItemDesc { get; set; }
|
[JsonIgnore]
|
||||||
[JsonProperty(PropertyName = "itemCode")]
|
public string BuyerZip {
|
||||||
public string ItemCode { get; set; }
|
get => GetMetadata<string>("buyerZip");
|
||||||
[JsonProperty(PropertyName = "physical")]
|
set => SetMetadata("buyerZip", value);
|
||||||
public bool? Physical { get; set; }
|
}
|
||||||
|
[JsonIgnore]
|
||||||
[JsonProperty(PropertyName = "taxIncluded", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
public string BuyerState{
|
||||||
public decimal? TaxIncluded { get; set; }
|
get => GetMetadata<string>("buyerState");
|
||||||
|
set => SetMetadata("buyerState", value);
|
||||||
|
}
|
||||||
|
[JsonIgnore]
|
||||||
|
public string BuyerCity {
|
||||||
|
get => GetMetadata<string>("buyerCity");
|
||||||
|
set => SetMetadata("buyerCity", value);
|
||||||
|
}
|
||||||
|
[JsonIgnore]
|
||||||
|
public string BuyerAddress2{
|
||||||
|
get => GetMetadata<string>("buyerAddress2");
|
||||||
|
set => SetMetadata("buyerAddress2", value);
|
||||||
|
}
|
||||||
|
[JsonIgnore]
|
||||||
|
public string BuyerAddress1 {
|
||||||
|
get => GetMetadata<string>("buyerAddress1");
|
||||||
|
set => SetMetadata("buyerAddress1", value);
|
||||||
|
}
|
||||||
|
[JsonIgnore]
|
||||||
|
public string BuyerPhone {
|
||||||
|
get => GetMetadata<string>("buyerPhone");
|
||||||
|
set => SetMetadata("buyerPhone", value);
|
||||||
|
}
|
||||||
|
[JsonIgnore]
|
||||||
|
public string ItemDesc {
|
||||||
|
get => GetMetadata<string>("itemDesc");
|
||||||
|
set => SetMetadata("itemDesc", value);
|
||||||
|
}
|
||||||
|
[JsonIgnore]
|
||||||
|
public string ItemCode{
|
||||||
|
get => GetMetadata<string>("itemCode");
|
||||||
|
set => SetMetadata("itemCode", value);
|
||||||
|
}
|
||||||
|
[JsonIgnore]
|
||||||
|
public bool? Physical {
|
||||||
|
get => GetMetadata<bool?>("physical");
|
||||||
|
set => SetMetadata("physical", value);
|
||||||
|
}
|
||||||
|
[JsonIgnore]
|
||||||
|
public decimal? TaxIncluded {
|
||||||
|
get => GetMetadata<decimal?>("taxIncluded");
|
||||||
|
set => SetMetadata("taxIncluded", value);
|
||||||
|
}
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public string PosData
|
public string PosData
|
||||||
{
|
{
|
||||||
get
|
get => GetMetadata<string>("posData");
|
||||||
{
|
set => SetMetadata("posData", value);
|
||||||
return PosRawData?.ToString();
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value is null)
|
|
||||||
{
|
|
||||||
PosRawData = JValue.CreateNull();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PosRawData = JToken.Parse(value);
|
|
||||||
}
|
|
||||||
catch (Exception )
|
|
||||||
{
|
|
||||||
PosRawData = JToken.FromObject(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "posData")]
|
|
||||||
public JToken PosRawData { get; set; }
|
|
||||||
[JsonExtensionData]
|
[JsonExtensionData]
|
||||||
public IDictionary<string, JToken> AdditionalData { get; set; }
|
public IDictionary<string, JToken> AdditionalData { get; set; }
|
||||||
|
|
||||||
|
public T GetMetadata<T>(string propName)
|
||||||
|
{
|
||||||
|
if (AdditionalData == null || !(AdditionalData.TryGetValue(propName, out var jt) is true)) return default;
|
||||||
|
if (jt.Type == JTokenType.Null)
|
||||||
|
return default;
|
||||||
|
if (typeof(T) == typeof(string))
|
||||||
|
{
|
||||||
|
return (T)(object)jt.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return jt.Value<T>();
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void SetMetadata<T>(string propName, T value)
|
||||||
|
{
|
||||||
|
JToken data;
|
||||||
|
if (value is null)
|
||||||
|
{
|
||||||
|
AdditionalData?.Remove(propName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (value is string s)
|
||||||
|
{
|
||||||
|
data = JToken.Parse(s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = JToken.FromObject(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception )
|
||||||
|
{
|
||||||
|
data = JToken.FromObject(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdditionalData ??= new Dictionary<string, JToken>();
|
||||||
|
AdditionalData.AddOrReplace(propName, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static InvoiceMetadata FromJObject(JObject jObject)
|
public static InvoiceMetadata FromJObject(JObject jObject)
|
||||||
{
|
{
|
||||||
return jObject.ToObject<InvoiceMetadata>(MetadataSerializer);
|
return jObject.ToObject<InvoiceMetadata>(MetadataSerializer);
|
||||||
|
|||||||
Reference in New Issue
Block a user