Add Label and accountKeyPath to the on chain payment methods (#2166)

This commit is contained in:
Nicolas Dorier 2020-12-28 21:59:01 +09:00 committed by GitHub
parent f64f86fbb6
commit 623347bc48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 132 additions and 5 deletions

View File

@ -1,3 +1,6 @@
using NBitcoin;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models
{
public class OnChainPaymentMethodData
@ -22,6 +25,11 @@ namespace BTCPayServer.Client.Models
/// </summary>
public string DerivationScheme { get; set; }
public string Label { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.KeyPathJsonConverter))]
public RootedKeyPath AccountKeyPath { get; set; }
public OnChainPaymentMethodData()
{
}

View File

@ -1244,9 +1244,14 @@ namespace BTCPayServer.Tests
new OnChainPaymentMethodData() {Default = true, Enabled = true, DerivationScheme = xpub});
Assert.Equal(xpub,method.DerivationScheme);
method = await client.UpdateStoreOnChainPaymentMethod(store.Id, "BTC",
new OnChainPaymentMethodData() { Default = true, Enabled = true, DerivationScheme = xpub, Label = "lol", AccountKeyPath = RootedKeyPath.Parse("01020304/1/2/3") });
method = await client.GetStoreOnChainPaymentMethod(store.Id, "BTC");
Assert.Equal("lol", method.Label);
Assert.Equal(RootedKeyPath.Parse("01020304/1/2/3"), method.AccountKeyPath);
Assert.Equal(xpub,method.DerivationScheme);

View File

@ -10,6 +10,7 @@ using BTCPayServer.Services.Stores;
using BTCPayServer.Services.Wallets;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using NBitcoin;
using NBXplorer.DerivationStrategy;
using StoreData = BTCPayServer.Data.StoreData;
@ -203,6 +204,18 @@ namespace BTCPayServer.Controllers.GreenField
var strategy = DerivationSchemeSettings.Parse(paymentMethodData.DerivationScheme, network);
if (strategy != null)
await wallet.TrackAsync(strategy.AccountDerivation);
strategy.Label = paymentMethodData.Label;
var signing = strategy.GetSigningAccountKeySettings();
if (paymentMethodData.AccountKeyPath is RootedKeyPath r)
{
signing.AccountKeyPath = r.KeyPath;
signing.RootFingerprint = r.MasterFingerprint;
}
else
{
signing.AccountKeyPath = null;
signing.RootFingerprint = null;
}
store.SetSupportedPaymentMethod(id, strategy);
storeBlob.SetExcluded(id, !paymentMethodData.Enabled);
store.SetStoreBlob(storeBlob);
@ -240,7 +253,11 @@ namespace BTCPayServer.Controllers.GreenField
? null
: new OnChainPaymentMethodData(paymentMethod.PaymentId.CryptoCode,
paymentMethod.AccountDerivation.ToString(), !excluded,
defaultPaymentMethod == paymentMethod.PaymentId);
defaultPaymentMethod == paymentMethod.PaymentId)
{
Label = paymentMethod.Label,
AccountKeyPath = paymentMethod.GetSigningAccountKeySettings().GetRootedKeyPath()
};
}
}
}

View File

@ -40,6 +40,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
@ -339,8 +340,16 @@ namespace BTCPayServer.Hosting
logBuilder.AddProvider(new Serilog.Extensions.Logging.SerilogLoggerProvider(Log.Logger));
}
});
services.AddSingleton<IObjectModelValidator, SkippableObjectValidatorProvider>();
services.SkipModelValidation<RootedKeyPath>();
return services;
}
public static void SkipModelValidation<T>(this IServiceCollection services)
{
services.AddSingleton<SkippableObjectValidatorProvider.ISkipValidation, SkippableObjectValidatorProvider.SkipValidationType<T>>();
}
private const long MAX_DEBUG_LOG_FILE_SIZE = 2000000; // If debug log is in use roll it every N MB.
private static void AddBtcPayServerAuthenticationSchemes(this IServiceCollection services)
{

View File

@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Options;
using NBitcoin;
namespace BTCPayServer.Hosting
{
public class SkippableObjectValidatorProvider : ObjectModelValidator
{
public interface ISkipValidation
{
bool SkipValidation(object obj);
}
public class SkipValidationType<T> : ISkipValidation
{
public bool SkipValidation(object obj)
{
return obj is T;
}
}
public SkippableObjectValidatorProvider(
IModelMetadataProvider modelMetadataProvider,
IEnumerable<ISkipValidation> skipValidations,
IOptions<MvcOptions> mvcOptions)
: base(modelMetadataProvider, mvcOptions.Value.ModelValidatorProviders)
{
_mvcOptions = mvcOptions.Value;
SkipValidations = skipValidations.ToList();
}
class OverrideValidationVisitor : ValidationVisitor
{
public OverrideValidationVisitor(IEnumerable<ISkipValidation> skipValidations, ActionContext actionContext, IModelValidatorProvider validatorProvider, ValidatorCache validatorCache, IModelMetadataProvider metadataProvider, ValidationStateDictionary validationState) : base(actionContext, validatorProvider, validatorCache, metadataProvider, validationState)
{
SkipValidations = skipValidations;
}
public IEnumerable<ISkipValidation> SkipValidations { get; }
protected override bool VisitComplexType(IValidationStrategy defaultStrategy)
{
if (SkipValidations.Any(v => v.SkipValidation(Model)))
return true;
return base.VisitComplexType(defaultStrategy);
}
}
public MvcOptions _mvcOptions { get; }
IEnumerable<ISkipValidation> SkipValidations { get; }
public override ValidationVisitor GetValidationVisitor(
ActionContext actionContext,
IModelValidatorProvider validatorProvider,
ValidatorCache validatorCache,
IModelMetadataProvider metadataProvider,
ValidationStateDictionary validationState)
{
var visitor = new OverrideValidationVisitor(
SkipValidations,
actionContext,
validatorProvider,
validatorCache,
metadataProvider,
validationState)
{
MaxValidationDepth = _mvcOptions.MaxValidationDepth,
ValidateComplexTypesIfChildValidationFails = _mvcOptions.ValidateComplexTypesIfChildValidationFails,
};
return visitor;
}
}
}

View File

@ -22,6 +22,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using NBitcoin;
namespace BTCPayServer.Hosting
{
@ -75,7 +76,6 @@ namespace BTCPayServer.Hosting
.ConfigureApiBehaviorOptions(options =>
{
var builtInFactory = options.InvalidModelStateResponseFactory;
options.InvalidModelStateResponseFactory = context =>
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.UnprocessableEntity;

View File

@ -403,7 +403,17 @@
},
"derivationScheme": {
"type": "string",
"description": "The derivation scheme"
"description": "The derivation scheme",
"example": "xpub..."
},
"label": {
"type": "string",
"description": "A label that will be shown in the UI"
},
"accountKeyPath": {
"type": "string",
"description": "The wallet fingerprint followed by the keypath to derive the account key used for signing operation or creating PSBTs",
"example": "abcd82a1/84'/0'/0'"
}
}
},