mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 14:04:26 +01:00
Merge pull request #2575 from NicolasDorier/refactor/wallet-cleanup
Cleanup some old code in wallet setup
This commit is contained in:
@@ -954,28 +954,6 @@ normal:
|
|||||||
|
|
||||||
result = testnetParser.Parse(tpub);
|
result = testnetParser.Parse(tpub);
|
||||||
Assert.Equal(tpub, result.ToString());
|
Assert.Equal(tpub, result.ToString());
|
||||||
testnetParser.HintScriptPubKey = BitcoinAddress
|
|
||||||
.Create("tb1q4s33amqm8l7a07zdxcunqnn3gcsjcfz3xc573l", testnetParser.Network).ScriptPubKey;
|
|
||||||
result = testnetParser.Parse(tpub);
|
|
||||||
Assert.Equal(tpub, result.ToString());
|
|
||||||
|
|
||||||
testnetParser.HintScriptPubKey = BitcoinAddress
|
|
||||||
.Create("2N2humNio3YTApSfY6VztQ9hQwDnhDvaqFQ", testnetParser.Network).ScriptPubKey;
|
|
||||||
result = testnetParser.Parse(tpub);
|
|
||||||
Assert.Equal($"{tpub}-[p2sh]", result.ToString());
|
|
||||||
|
|
||||||
testnetParser.HintScriptPubKey = BitcoinAddress
|
|
||||||
.Create("mwD8bHS65cdgUf6rZUUSoVhi3wNQFu1Nfi", testnetParser.Network).ScriptPubKey;
|
|
||||||
result = testnetParser.Parse(tpub);
|
|
||||||
Assert.Equal($"{tpub}-[legacy]", result.ToString());
|
|
||||||
|
|
||||||
testnetParser.HintScriptPubKey = BitcoinAddress
|
|
||||||
.Create("2N2humNio3YTApSfY6VztQ9hQwDnhDvaqFQ", testnetParser.Network).ScriptPubKey;
|
|
||||||
result = testnetParser.Parse($"{tpub}-[legacy]");
|
|
||||||
Assert.Equal($"{tpub}-[p2sh]", result.ToString());
|
|
||||||
|
|
||||||
result = testnetParser.Parse(tpub);
|
|
||||||
Assert.Equal($"{tpub}-[p2sh]", result.ToString());
|
|
||||||
|
|
||||||
var regtestParser = new DerivationSchemeParser(regtestNetworkProvider.GetNetwork<BTCPayNetwork>("BTC"));
|
var regtestParser = new DerivationSchemeParser(regtestNetworkProvider.GetNetwork<BTCPayNetwork>("BTC"));
|
||||||
var parsed =
|
var parsed =
|
||||||
|
|||||||
@@ -179,30 +179,18 @@ namespace BTCPayServer.Tests
|
|||||||
if (StoreId is null)
|
if (StoreId is null)
|
||||||
await CreateStoreAsync();
|
await CreateStoreAsync();
|
||||||
SupportedNetwork = parent.NetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode);
|
SupportedNetwork = parent.NetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode);
|
||||||
var store = parent.PayTester.GetController<StoresController>(UserId, StoreId);
|
var store = parent.PayTester.GetController<StoresController>(UserId, StoreId, true);
|
||||||
GenerateWalletResponseV = await parent.ExplorerClient.GenerateWalletAsync(new GenerateWalletRequest()
|
|
||||||
|
var generateRequest = new GenerateWalletRequest()
|
||||||
{
|
{
|
||||||
ScriptPubKeyType = segwit,
|
ScriptPubKeyType = segwit,
|
||||||
SavePrivateKeys = importKeysToNBX,
|
SavePrivateKeys = importKeysToNBX,
|
||||||
ImportKeysToRPC = importsKeysToBitcoinCore
|
ImportKeysToRPC = importsKeysToBitcoinCore
|
||||||
});
|
};
|
||||||
await store.UpdateWallet(
|
|
||||||
new WalletSetupViewModel
|
await store.GenerateWallet(StoreId, cryptoCode, WalletSetupMethod.HotWallet, generateRequest);
|
||||||
{
|
Assert.NotNull(store.GenerateWalletResponse);
|
||||||
StoreId = StoreId,
|
GenerateWalletResponseV = store.GenerateWalletResponse;
|
||||||
Method = importKeysToNBX ? WalletSetupMethod.HotWallet : WalletSetupMethod.WatchOnly,
|
|
||||||
Enabled = true,
|
|
||||||
CryptoCode = cryptoCode,
|
|
||||||
Network = SupportedNetwork,
|
|
||||||
RootFingerprint = GenerateWalletResponseV.AccountKeyPath.MasterFingerprint.ToString(),
|
|
||||||
RootKeyPath = SupportedNetwork.GetRootKeyPath(),
|
|
||||||
Source = "NBXplorer",
|
|
||||||
AccountKey = GenerateWalletResponseV.AccountHDKey.Neuter().ToWif(),
|
|
||||||
DerivationSchemeFormat = "BTCPay",
|
|
||||||
KeyPath = GenerateWalletResponseV.AccountKeyPath.KeyPath.ToString(),
|
|
||||||
DerivationScheme = DerivationScheme.ToString(),
|
|
||||||
Confirmation = true
|
|
||||||
});
|
|
||||||
return new WalletId(StoreId, cryptoCode);
|
return new WalletId(StoreId, cryptoCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Abstractions.Extensions;
|
using BTCPayServer.Abstractions.Extensions;
|
||||||
using BTCPayServer.Abstractions.Models;
|
using BTCPayServer.Abstractions.Models;
|
||||||
@@ -11,9 +12,11 @@ using BTCPayServer.Models;
|
|||||||
using BTCPayServer.Models.StoreViewModels;
|
using BTCPayServer.Models.StoreViewModels;
|
||||||
using BTCPayServer.Payments;
|
using BTCPayServer.Payments;
|
||||||
using BTCPayServer.Services;
|
using BTCPayServer.Services;
|
||||||
|
using ExchangeSharp;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||||
using NBitcoin;
|
using NBitcoin;
|
||||||
using NBXplorer;
|
using NBXplorer;
|
||||||
using NBXplorer.DerivationStrategy;
|
using NBXplorer.DerivationStrategy;
|
||||||
@@ -85,15 +88,6 @@ namespace BTCPayServer.Controllers
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(vm.Config))
|
|
||||||
{
|
|
||||||
if (!DerivationSchemeSettings.TryParseFromJson(vm.Config, network, out strategy))
|
|
||||||
{
|
|
||||||
ModelState.AddModelError(nameof(vm.Config), "Config file was not in the correct format");
|
|
||||||
return View(vm.ViewName, vm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vm.WalletFile != null)
|
if (vm.WalletFile != null)
|
||||||
{
|
{
|
||||||
if (!DerivationSchemeSettings.TryParseFromWalletFile(await ReadAllText(vm.WalletFile), network, out strategy))
|
if (!DerivationSchemeSettings.TryParseFromWalletFile(await ReadAllText(vm.WalletFile), network, out strategy))
|
||||||
@@ -114,16 +108,13 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var newStrategy = ParseDerivationStrategy(vm.DerivationScheme, null, network);
|
strategy = ParseDerivationStrategy(vm.DerivationScheme, network);
|
||||||
if (newStrategy.AccountDerivation != strategy?.AccountDerivation)
|
strategy.Source = "ManualDerivationScheme";
|
||||||
{
|
if (!string.IsNullOrEmpty(vm.AccountKey))
|
||||||
var accountKey = string.IsNullOrEmpty(vm.AccountKey)
|
|
||||||
? null
|
|
||||||
: new BitcoinExtPubKey(vm.AccountKey, network.NBitcoinNetwork);
|
|
||||||
if (accountKey != null)
|
|
||||||
{
|
{
|
||||||
|
var accountKey = new BitcoinExtPubKey(vm.AccountKey, network.NBitcoinNetwork);
|
||||||
var accountSettings =
|
var accountSettings =
|
||||||
newStrategy.AccountKeySettings.FirstOrDefault(a => a.AccountKey == accountKey);
|
strategy.AccountKeySettings.FirstOrDefault(a => a.AccountKey == accountKey);
|
||||||
if (accountSettings != null)
|
if (accountSettings != null)
|
||||||
{
|
{
|
||||||
accountSettings.AccountKeyPath =
|
accountSettings.AccountKeyPath =
|
||||||
@@ -134,11 +125,8 @@ namespace BTCPayServer.Controllers
|
|||||||
NBitcoin.DataEncoders.Encoders.Hex.DecodeData(vm.RootFingerprint));
|
NBitcoin.DataEncoders.Encoders.Hex.DecodeData(vm.RootFingerprint));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strategy = newStrategy;
|
|
||||||
strategy.Source = vm.Source;
|
|
||||||
vm.DerivationScheme = strategy.AccountDerivation.ToString();
|
vm.DerivationScheme = strategy.AccountDerivation.ToString();
|
||||||
}
|
ModelState.Remove(nameof(vm.DerivationScheme));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -146,34 +134,33 @@ namespace BTCPayServer.Controllers
|
|||||||
return View(vm.ViewName, vm);
|
return View(vm.ViewName, vm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (!string.IsNullOrEmpty(vm.Config))
|
||||||
|
{
|
||||||
|
if (!DerivationSchemeSettings.TryParseFromJson(UnprotectString(vm.Config), network, out strategy))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(vm.Config), "Config file was not in the correct format");
|
||||||
|
return View(vm.ViewName, vm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strategy is null)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(vm.DerivationScheme), "Please provide your extended public key");
|
ModelState.AddModelError(nameof(vm.DerivationScheme), "Please provide your extended public key");
|
||||||
return View(vm.ViewName, vm);
|
return View(vm.ViewName, vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
var oldConfig = vm.Config;
|
vm.Config = ProtectString(strategy.ToJson());
|
||||||
vm.Config = strategy?.ToJson();
|
ModelState.Remove(nameof(vm.Config));
|
||||||
var configChanged = oldConfig != vm.Config;
|
|
||||||
PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike);
|
PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike);
|
||||||
var storeBlob = store.GetStoreBlob();
|
var storeBlob = store.GetStoreBlob();
|
||||||
var willBeExcluded = !vm.Enabled;
|
if (vm.Confirmation)
|
||||||
|
|
||||||
var showAddress = // Show addresses if:
|
|
||||||
// - If the user is testing the hint address in confirmation screen
|
|
||||||
(vm.Confirmation && !string.IsNullOrWhiteSpace(vm.HintAddress)) ||
|
|
||||||
// - The user is clicking on continue after changing the config
|
|
||||||
(!vm.Confirmation && configChanged);
|
|
||||||
|
|
||||||
showAddress = showAddress && strategy != null;
|
|
||||||
if (!showAddress)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (strategy != null)
|
|
||||||
await wallet.TrackAsync(strategy.AccountDerivation);
|
await wallet.TrackAsync(strategy.AccountDerivation);
|
||||||
store.SetSupportedPaymentMethod(paymentMethodId, strategy);
|
store.SetSupportedPaymentMethod(paymentMethodId, strategy);
|
||||||
storeBlob.SetExcluded(paymentMethodId, willBeExcluded);
|
storeBlob.SetExcluded(paymentMethodId, false);
|
||||||
storeBlob.Hints.Wallet = false;
|
storeBlob.Hints.Wallet = false;
|
||||||
store.SetStoreBlob(storeBlob);
|
store.SetStoreBlob(storeBlob);
|
||||||
}
|
}
|
||||||
@@ -191,43 +178,16 @@ namespace BTCPayServer.Controllers
|
|||||||
// This is success case when derivation scheme is added to the store
|
// This is success case when derivation scheme is added to the store
|
||||||
return RedirectToAction(nameof(UpdateStore), new { storeId = vm.StoreId });
|
return RedirectToAction(nameof(UpdateStore), new { storeId = vm.StoreId });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(vm.HintAddress))
|
|
||||||
{
|
|
||||||
BitcoinAddress address;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
address = BitcoinAddress.Create(vm.HintAddress, network.NBitcoinNetwork);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
ModelState.AddModelError(nameof(vm.HintAddress), "Invalid hint address");
|
|
||||||
return ConfirmAddresses(vm, strategy);
|
return ConfirmAddresses(vm, strategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
private string ProtectString(string str)
|
||||||
{
|
{
|
||||||
var newStrategy = ParseDerivationStrategy(vm.DerivationScheme, address.ScriptPubKey, network);
|
return Convert.ToBase64String(DataProtector.Protect(Encoding.UTF8.GetBytes(str)));
|
||||||
if (newStrategy.AccountDerivation != strategy.AccountDerivation)
|
}
|
||||||
|
private string UnprotectString(string str)
|
||||||
{
|
{
|
||||||
strategy.AccountDerivation = newStrategy.AccountDerivation;
|
return Encoding.UTF8.GetString(DataProtector.Unprotect(Convert.FromBase64String(str)));
|
||||||
strategy.AccountOriginal = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
ModelState.AddModelError(nameof(vm.HintAddress), "Impossible to find a match with this address. Are you sure the wallet and address provided are correct and from the same source?");
|
|
||||||
return ConfirmAddresses(vm, strategy);
|
|
||||||
}
|
|
||||||
|
|
||||||
vm.HintAddress = "";
|
|
||||||
TempData[WellKnownTempData.SuccessMessage] =
|
|
||||||
"Address successfully found, please verify that the rest is correct and click on \"Confirm\"";
|
|
||||||
ModelState.Remove(nameof(vm.HintAddress));
|
|
||||||
ModelState.Remove(nameof(vm.DerivationScheme));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ConfirmAddresses(vm, strategy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{storeId}/onchain/{cryptoCode}/generate/{method?}")]
|
[HttpGet("{storeId}/onchain/{cryptoCode}/generate/{method?}")]
|
||||||
@@ -246,14 +206,6 @@ namespace BTCPayServer.Controllers
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
var derivation = GetExistingDerivationStrategy(vm.CryptoCode, store);
|
|
||||||
if (derivation != null)
|
|
||||||
{
|
|
||||||
vm.DerivationScheme = derivation.AccountDerivation.ToString();
|
|
||||||
vm.Config = derivation.ToJson();
|
|
||||||
}
|
|
||||||
|
|
||||||
vm.Enabled = !store.GetStoreBlob().IsExcluded(new PaymentMethodId(vm.CryptoCode, PaymentTypes.BTCLike));
|
|
||||||
vm.CanUseHotWallet = hotWallet;
|
vm.CanUseHotWallet = hotWallet;
|
||||||
vm.CanUseRPCImport = rpcImport;
|
vm.CanUseRPCImport = rpcImport;
|
||||||
vm.RootKeyPath = network.GetRootKeyPath();
|
vm.RootKeyPath = network.GetRootKeyPath();
|
||||||
@@ -270,7 +222,7 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
return View(vm.ViewName, vm);
|
return View(vm.ViewName, vm);
|
||||||
}
|
}
|
||||||
|
internal GenerateWalletResponse GenerateWalletResponse;
|
||||||
[HttpPost("{storeId}/onchain/{cryptoCode}/generate/{method}")]
|
[HttpPost("{storeId}/onchain/{cryptoCode}/generate/{method}")]
|
||||||
public async Task<IActionResult> GenerateWallet(string storeId, string cryptoCode, WalletSetupMethod method, GenerateWalletRequest request)
|
public async Task<IActionResult> GenerateWallet(string storeId, string cryptoCode, WalletSetupMethod method, GenerateWalletRequest request)
|
||||||
{
|
{
|
||||||
@@ -288,6 +240,7 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
var client = _ExplorerProvider.GetExplorerClient(cryptoCode);
|
var client = _ExplorerProvider.GetExplorerClient(cryptoCode);
|
||||||
var isImport = method == WalletSetupMethod.Seed;
|
var isImport = method == WalletSetupMethod.Seed;
|
||||||
|
|
||||||
var vm = new WalletSetupViewModel
|
var vm = new WalletSetupViewModel
|
||||||
{
|
{
|
||||||
StoreId = storeId,
|
StoreId = storeId,
|
||||||
@@ -297,8 +250,8 @@ namespace BTCPayServer.Controllers
|
|||||||
Confirmation = string.IsNullOrEmpty(request.ExistingMnemonic),
|
Confirmation = string.IsNullOrEmpty(request.ExistingMnemonic),
|
||||||
Network = network,
|
Network = network,
|
||||||
RootKeyPath = network.GetRootKeyPath(),
|
RootKeyPath = network.GetRootKeyPath(),
|
||||||
Enabled = !store.GetStoreBlob().IsExcluded(new PaymentMethodId(cryptoCode, PaymentTypes.BTCLike)),
|
Source = isImport ? "SeedImported" : "NBXplorerGenerated",
|
||||||
Source = "NBXplorer",
|
IsHotWallet = isImport ? request.SavePrivateKeys : method == WalletSetupMethod.HotWallet,
|
||||||
DerivationSchemeFormat = "BTCPay",
|
DerivationSchemeFormat = "BTCPay",
|
||||||
CanUseHotWallet = true,
|
CanUseHotWallet = true,
|
||||||
CanUseRPCImport = rpcImport
|
CanUseRPCImport = rpcImport
|
||||||
@@ -329,11 +282,26 @@ namespace BTCPayServer.Controllers
|
|||||||
return View(vm.ViewName, vm);
|
return View(vm.ViewName, vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var derivationSchemeSettings = new DerivationSchemeSettings(response.DerivationScheme, network);
|
||||||
|
if (method == WalletSetupMethod.Seed)
|
||||||
|
{
|
||||||
|
derivationSchemeSettings.Source = "ImportedSeed";
|
||||||
|
derivationSchemeSettings.IsHotWallet = request.SavePrivateKeys;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
derivationSchemeSettings.Source = "NBXplorerGenerated";
|
||||||
|
derivationSchemeSettings.IsHotWallet = method == WalletSetupMethod.HotWallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
var accountSettings = derivationSchemeSettings.GetSigningAccountKeySettings();
|
||||||
|
accountSettings.AccountKeyPath = response.AccountKeyPath.KeyPath;
|
||||||
|
accountSettings.RootFingerprint = response.AccountKeyPath.MasterFingerprint;
|
||||||
|
derivationSchemeSettings.AccountOriginal = response.DerivationScheme.ToString();
|
||||||
|
|
||||||
// Set wallet properties from generate response
|
// Set wallet properties from generate response
|
||||||
vm.RootFingerprint = response.AccountKeyPath.MasterFingerprint.ToString();
|
vm.Config = ProtectString(derivationSchemeSettings.ToJson());
|
||||||
vm.DerivationScheme = response.DerivationScheme.ToString();
|
|
||||||
vm.AccountKey = response.AccountHDKey.Neuter().ToWif();
|
|
||||||
vm.KeyPath = response.AccountKeyPath.KeyPath.ToString();
|
|
||||||
|
|
||||||
var result = await UpdateWallet(vm);
|
var result = await UpdateWallet(vm);
|
||||||
|
|
||||||
@@ -355,6 +323,10 @@ namespace BTCPayServer.Controllers
|
|||||||
IsStored = request.SavePrivateKeys,
|
IsStored = request.SavePrivateKeys,
|
||||||
ReturnUrl = Url.Action(nameof(GenerateWalletConfirm), new { storeId, cryptoCode })
|
ReturnUrl = Url.Action(nameof(GenerateWalletConfirm), new { storeId, cryptoCode })
|
||||||
};
|
};
|
||||||
|
if (this._BTCPayEnv.IsDeveloping)
|
||||||
|
{
|
||||||
|
GenerateWalletResponse = response;
|
||||||
|
}
|
||||||
return this.RedirectToRecoverySeedBackup(seedVm);
|
return this.RedirectToRecoverySeedBackup(seedVm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,8 +380,7 @@ namespace BTCPayServer.Controllers
|
|||||||
vm.RootFingerprint = derivation.GetSigningAccountKeySettings().RootFingerprint.ToString();
|
vm.RootFingerprint = derivation.GetSigningAccountKeySettings().RootFingerprint.ToString();
|
||||||
vm.DerivationScheme = derivation.AccountDerivation.ToString();
|
vm.DerivationScheme = derivation.AccountDerivation.ToString();
|
||||||
vm.KeyPath = derivation.GetSigningAccountKeySettings().AccountKeyPath?.ToString();
|
vm.KeyPath = derivation.GetSigningAccountKeySettings().AccountKeyPath?.ToString();
|
||||||
vm.Config = derivation.ToJson();
|
vm.Config = ProtectString(derivation.ToJson());
|
||||||
vm.Enabled = !store.GetStoreBlob().IsExcluded(new PaymentMethodId(vm.CryptoCode, PaymentTypes.BTCLike));
|
|
||||||
vm.IsHotWallet = isHotWallet;
|
vm.IsHotWallet = isHotWallet;
|
||||||
|
|
||||||
return View(vm);
|
return View(vm);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ using BTCPayServer.Services.Stores;
|
|||||||
using BTCPayServer.Services.Wallets;
|
using BTCPayServer.Services.Wallets;
|
||||||
using BundlerMinifier.TagHelpers;
|
using BundlerMinifier.TagHelpers;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
@@ -69,7 +70,8 @@ namespace BTCPayServer.Controllers
|
|||||||
AppService appService,
|
AppService appService,
|
||||||
IWebHostEnvironment webHostEnvironment,
|
IWebHostEnvironment webHostEnvironment,
|
||||||
WebhookNotificationManager webhookNotificationManager,
|
WebhookNotificationManager webhookNotificationManager,
|
||||||
IOptions<LightningNetworkOptions> lightningNetworkOptions)
|
IOptions<LightningNetworkOptions> lightningNetworkOptions,
|
||||||
|
IDataProtectionProvider dataProtector)
|
||||||
{
|
{
|
||||||
_RateFactory = rateFactory;
|
_RateFactory = rateFactory;
|
||||||
_Repo = repo;
|
_Repo = repo;
|
||||||
@@ -85,6 +87,7 @@ namespace BTCPayServer.Controllers
|
|||||||
_appService = appService;
|
_appService = appService;
|
||||||
_webHostEnvironment = webHostEnvironment;
|
_webHostEnvironment = webHostEnvironment;
|
||||||
_lightningNetworkOptions = lightningNetworkOptions;
|
_lightningNetworkOptions = lightningNetworkOptions;
|
||||||
|
DataProtector = dataProtector.CreateProtector("ConfigProtector");
|
||||||
WebhookNotificationManager = webhookNotificationManager;
|
WebhookNotificationManager = webhookNotificationManager;
|
||||||
_EventAggregator = eventAggregator;
|
_EventAggregator = eventAggregator;
|
||||||
_NetworkProvider = networkProvider;
|
_NetworkProvider = networkProvider;
|
||||||
@@ -689,10 +692,9 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DerivationSchemeSettings ParseDerivationStrategy(string derivationScheme, Script hint, BTCPayNetwork network)
|
private DerivationSchemeSettings ParseDerivationStrategy(string derivationScheme, BTCPayNetwork network)
|
||||||
{
|
{
|
||||||
var parser = new DerivationSchemeParser(network);
|
var parser = new DerivationSchemeParser(network);
|
||||||
parser.HintScriptPubKey = hint;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var derivationSchemeSettings = new DerivationSchemeSettings();
|
var derivationSchemeSettings = new DerivationSchemeSettings();
|
||||||
@@ -827,6 +829,7 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
public string GeneratedPairingCode { get; set; }
|
public string GeneratedPairingCode { get; set; }
|
||||||
public WebhookNotificationManager WebhookNotificationManager { get; }
|
public WebhookNotificationManager WebhookNotificationManager { get; }
|
||||||
|
public IDataProtector DataProtector { get; }
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{storeId}/Tokens/Create")]
|
[Route("{storeId}/Tokens/Create")]
|
||||||
|
|||||||
@@ -1088,7 +1088,9 @@ namespace BTCPayServer.Controllers
|
|||||||
DerivationScheme = derivationSchemeSettings.AccountDerivation.ToString(),
|
DerivationScheme = derivationSchemeSettings.AccountDerivation.ToString(),
|
||||||
DerivationSchemeInput = derivationSchemeSettings.AccountOriginal,
|
DerivationSchemeInput = derivationSchemeSettings.AccountOriginal,
|
||||||
SelectedSigningKey = derivationSchemeSettings.SigningKey.ToString(),
|
SelectedSigningKey = derivationSchemeSettings.SigningKey.ToString(),
|
||||||
NBXSeedAvailable = await CanUseHotWallet() && !string.IsNullOrEmpty(await ExplorerClientProvider.GetExplorerClient(walletId.CryptoCode)
|
NBXSeedAvailable = derivationSchemeSettings.IsHotWallet &&
|
||||||
|
await CanUseHotWallet() &&
|
||||||
|
!string.IsNullOrEmpty(await ExplorerClientProvider.GetExplorerClient(walletId.CryptoCode)
|
||||||
.GetMetadataAsync<string>(GetDerivationSchemeSettings(walletId).AccountDerivation,
|
.GetMetadataAsync<string>(GetDerivationSchemeSettings(walletId).AccountDerivation,
|
||||||
WellknownMetadataKeys.MasterHDKey))
|
WellknownMetadataKeys.MasterHDKey))
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ namespace BTCPayServer
|
|||||||
|
|
||||||
public Network Network => BtcPayNetwork.NBitcoinNetwork;
|
public Network Network => BtcPayNetwork.NBitcoinNetwork;
|
||||||
|
|
||||||
public Script HintScriptPubKey { get; set; }
|
|
||||||
|
|
||||||
public DerivationSchemeParser(BTCPayNetwork expectedNetwork)
|
public DerivationSchemeParser(BTCPayNetwork expectedNetwork)
|
||||||
{
|
{
|
||||||
if (expectedNetwork == null)
|
if (expectedNetwork == null)
|
||||||
@@ -131,19 +129,6 @@ namespace BTCPayServer
|
|||||||
|
|
||||||
HashSet<string> hintedLabels = new HashSet<string>();
|
HashSet<string> hintedLabels = new HashSet<string>();
|
||||||
|
|
||||||
var hintDestination = HintScriptPubKey?.GetDestination();
|
|
||||||
if (hintDestination != null)
|
|
||||||
{
|
|
||||||
if (hintDestination is KeyId)
|
|
||||||
{
|
|
||||||
hintedLabels.Add("legacy");
|
|
||||||
}
|
|
||||||
if (hintDestination is ScriptId)
|
|
||||||
{
|
|
||||||
hintedLabels.Add("p2sh");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Network.Consensus.SupportSegwit)
|
if (!Network.Consensus.SupportSegwit)
|
||||||
{
|
{
|
||||||
hintedLabels.Add("legacy");
|
hintedLabels.Add("legacy");
|
||||||
@@ -152,8 +137,7 @@ namespace BTCPayServer
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(str);
|
return BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(str);
|
||||||
return FindMatch(hintedLabels, result);
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -205,22 +189,13 @@ namespace BTCPayServer
|
|||||||
catch { continue; }
|
catch { continue; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hintDestination != null)
|
|
||||||
{
|
|
||||||
if (hintDestination is WitKeyId)
|
|
||||||
{
|
|
||||||
hintedLabels.Remove("legacy");
|
|
||||||
hintedLabels.Remove("p2sh");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
str = string.Join('-', parts.Where(p => !IsLabel(p)));
|
str = string.Join('-', parts.Where(p => !IsLabel(p)));
|
||||||
foreach (var label in hintedLabels)
|
foreach (var label in hintedLabels)
|
||||||
{
|
{
|
||||||
str = $"{str}-[{label}]";
|
str = $"{str}-[{label}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
return FindMatch(hintedLabels, BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(str));
|
return BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BitcoinExtPubKey GetBitcoinExtPubKeyByNetwork(Network network, byte[] data)
|
public static BitcoinExtPubKey GetBitcoinExtPubKeyByNetwork(Network network, byte[] data)
|
||||||
@@ -235,27 +210,6 @@ namespace BTCPayServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DerivationStrategyBase FindMatch(HashSet<string> hintLabels, DerivationStrategyBase result)
|
|
||||||
{
|
|
||||||
var firstKeyPath = new KeyPath("0/0");
|
|
||||||
if (HintScriptPubKey == null)
|
|
||||||
return result;
|
|
||||||
if (HintScriptPubKey == result.GetDerivation(firstKeyPath).ScriptPubKey)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
if (result is MultisigDerivationStrategy)
|
|
||||||
hintLabels.Add("keeporder");
|
|
||||||
|
|
||||||
var resultNoLabels = result.ToString();
|
|
||||||
resultNoLabels = string.Join('-', resultNoLabels.Split('-').Where(p => !IsLabel(p)));
|
|
||||||
foreach (var labels in ItemCombinations(hintLabels.ToList()))
|
|
||||||
{
|
|
||||||
var hinted = BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(resultNoLabels + '-' + string.Join('-', labels.Select(l => $"[{l}]").ToArray()));
|
|
||||||
if (HintScriptPubKey == hinted.GetDerivation(firstKeyPath).ScriptPubKey)
|
|
||||||
return hinted;
|
|
||||||
}
|
|
||||||
throw new FormatException("Could not find any match");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsLabel(string v)
|
private static bool IsLabel(string v)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -276,8 +276,8 @@ namespace BTCPayServer
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public BTCPayNetwork Network { get; set; }
|
public BTCPayNetwork Network { get; set; }
|
||||||
public string Source { get; set; }
|
public string Source { get; set; }
|
||||||
[JsonIgnore]
|
|
||||||
public bool IsHotWallet => Source == "NBXplorer";
|
public bool IsHotWallet { get; set; }
|
||||||
|
|
||||||
[Obsolete("Use GetSigningAccountKeySettings().AccountKeyPath instead")]
|
[Obsolete("Use GetSigningAccountKeySettings().AccountKeyPath instead")]
|
||||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||||
|
|||||||
@@ -128,6 +128,12 @@ namespace BTCPayServer.Hosting
|
|||||||
settings.MigrateU2FToFIDO2 = true;
|
settings.MigrateU2FToFIDO2 = true;
|
||||||
await _Settings.UpdateSetting(settings);
|
await _Settings.UpdateSetting(settings);
|
||||||
}
|
}
|
||||||
|
if (!settings.MigrateHotwalletProperty)
|
||||||
|
{
|
||||||
|
await MigrateHotwalletProperty();
|
||||||
|
settings.MigrateHotwalletProperty = true;
|
||||||
|
await _Settings.UpdateSetting(settings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -136,6 +142,20 @@ namespace BTCPayServer.Hosting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task MigrateHotwalletProperty()
|
||||||
|
{
|
||||||
|
await using var ctx = _DBContextFactory.CreateContext();
|
||||||
|
foreach (var store in await ctx.Stores.AsQueryable().ToArrayAsync())
|
||||||
|
{
|
||||||
|
foreach (var paymentMethod in store.GetSupportedPaymentMethods(_NetworkProvider).OfType<DerivationSchemeSettings>())
|
||||||
|
{
|
||||||
|
paymentMethod.IsHotWallet = paymentMethod.Source == "NBXplorer";
|
||||||
|
paymentMethod.Source = "NBXplorerGenerated";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task MigrateU2FToFIDO2()
|
private async Task MigrateU2FToFIDO2()
|
||||||
{
|
{
|
||||||
await using var ctx = _DBContextFactory.CreateContext();
|
await using var ctx = _DBContextFactory.CreateContext();
|
||||||
|
|||||||
@@ -20,10 +20,7 @@ namespace BTCPayServer.Models.StoreViewModels
|
|||||||
public string KeyPath { get; set; }
|
public string KeyPath { get; set; }
|
||||||
[Display(Name = "Root fingerprint")]
|
[Display(Name = "Root fingerprint")]
|
||||||
public string RootFingerprint { get; set; }
|
public string RootFingerprint { get; set; }
|
||||||
[Display(Name = "Hint address")]
|
|
||||||
public string HintAddress { get; set; }
|
|
||||||
public bool Confirmation { get; set; }
|
public bool Confirmation { get; set; }
|
||||||
public bool Enabled { get; set; } = true;
|
|
||||||
|
|
||||||
public KeyPath RootKeyPath { get; set; }
|
public KeyPath RootKeyPath { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ namespace BTCPayServer.Services
|
|||||||
{
|
{
|
||||||
public class MigrationSettings
|
public class MigrationSettings
|
||||||
{
|
{
|
||||||
|
public bool MigrateHotwalletProperty { get; set; }
|
||||||
public bool MigrateU2FToFIDO2{ get; set; }
|
public bool MigrateU2FToFIDO2{ get; set; }
|
||||||
public bool UnreachableStoreCheck { get; set; }
|
public bool UnreachableStoreCheck { get; set; }
|
||||||
public bool DeprecatedLightningConnectionStringCheck { get; set; }
|
public bool DeprecatedLightningConnectionStringCheck { get; set; }
|
||||||
|
|||||||
@@ -50,7 +50,6 @@
|
|||||||
<input asp-for="Config" type="hidden"/>
|
<input asp-for="Config" type="hidden"/>
|
||||||
<input asp-for="Confirmation" type="hidden"/>
|
<input asp-for="Confirmation" type="hidden"/>
|
||||||
<input asp-for="DerivationScheme" type="hidden"/>
|
<input asp-for="DerivationScheme" type="hidden"/>
|
||||||
<input asp-for="Enabled" type="hidden"/>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<table class="table table-sm table-responsive-md">
|
<table class="table table-sm table-responsive-md">
|
||||||
@@ -83,21 +82,6 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-center mb-4">
|
|
||||||
<button class="btn btn-link" type="button" data-bs-toggle="collapse" data-bs-target="#wrong-addresses" aria-expanded="false" aria-controls="wrong-addresses">
|
|
||||||
Wrong addresses?
|
|
||||||
</button>
|
|
||||||
<div id="wrong-addresses" class="collapse @(ViewContext.ModelState.IsValid ? "" : "show")">
|
|
||||||
<div class="pb-1">
|
|
||||||
<div class="form-group">
|
|
||||||
<label asp-for="HintAddress" class="form-label">Help us to find the correct settings by telling us the first address of your wallet.</label>
|
|
||||||
<input asp-for="HintAddress" class="form-control"/>
|
|
||||||
<span asp-validation-for="HintAddress" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<button name="command" type="submit" class="btn btn-primary" value="save" id="Confirm">Confirm</button>
|
<button name="command" type="submit" class="btn btn-primary" value="save" id="Confirm">Confirm</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user