mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2026-02-23 15:14:49 +01:00
Save the fingerprint of the root of LedgerWallet, and use it. Simplify HardwareWallet
This commit is contained in:
@@ -43,6 +43,14 @@ namespace BTCPayServer.Controllers
|
||||
return View(vm);
|
||||
}
|
||||
|
||||
class GetXPubs
|
||||
{
|
||||
public BitcoinExtPubKey ExtPubKey { get; set; }
|
||||
public DerivationStrategyBase DerivationScheme { get; set; }
|
||||
public HDFingerprint RootFingerprint { get; set; }
|
||||
public string Source { get; set; }
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("{storeId}/derivations/{cryptoCode}/ledger/ws")]
|
||||
public async Task<IActionResult> AddDerivationSchemeLedger(
|
||||
@@ -73,7 +81,18 @@ namespace BTCPayServer.Controllers
|
||||
var k = KeyPath.Parse(keyPath);
|
||||
if (k.Indexes.Length == 0)
|
||||
throw new FormatException("Invalid key path");
|
||||
var getxpubResult = await hw.GetExtPubKey(network, k, normalOperationTimeout.Token);
|
||||
|
||||
var getxpubResult = new GetXPubs();
|
||||
getxpubResult.ExtPubKey = await hw.GetExtPubKey(network, k, normalOperationTimeout.Token);
|
||||
var segwit = network.NBitcoinNetwork.Consensus.SupportSegwit;
|
||||
var derivation = new DerivationStrategyFactory(network.NBitcoinNetwork).CreateDirectDerivationStrategy(getxpubResult.ExtPubKey, new DerivationStrategyOptions()
|
||||
{
|
||||
P2SH = segwit,
|
||||
Legacy = !segwit
|
||||
});
|
||||
getxpubResult.DerivationScheme = derivation;
|
||||
getxpubResult.RootFingerprint = (await hw.GetExtPubKey(network, new KeyPath(), normalOperationTimeout.Token)).ExtPubKey.PubKey.GetHDFingerPrint();
|
||||
getxpubResult.Source = hw.Device;
|
||||
result = getxpubResult;
|
||||
}
|
||||
}
|
||||
@@ -87,7 +106,7 @@ namespace BTCPayServer.Controllers
|
||||
if (result != null)
|
||||
{
|
||||
UTF8Encoding UTF8NOBOM = new UTF8Encoding(false);
|
||||
var bytes = UTF8NOBOM.GetBytes(JsonConvert.SerializeObject(result, MvcJsonOptions.Value.SerializerSettings));
|
||||
var bytes = UTF8NOBOM.GetBytes(JsonConvert.SerializeObject(result, network.NBXplorerNetwork.JsonSerializerSettings));
|
||||
await webSocket.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true, new CancellationTokenSource(2000).Token);
|
||||
}
|
||||
}
|
||||
@@ -185,6 +204,8 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
strategy = newStrategy;
|
||||
strategy.AccountKeyPath = vm.KeyPath == null ? null : KeyPath.Parse(vm.KeyPath);
|
||||
strategy.RootFingerprint = string.IsNullOrEmpty(vm.RootFingerprint)? (HDFingerprint?)null : new HDFingerprint(NBitcoin.DataEncoders.Encoders.Hex.DecodeData(vm.RootFingerprint));
|
||||
strategy.Source = vm.Source;
|
||||
vm.DerivationScheme = strategy.AccountDerivation.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,9 +560,9 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
|
||||
var strategy = GetDirectDerivationStrategy(derivationSettings.AccountDerivation);
|
||||
// Some deployment have the wallet root key path saved in the store blob
|
||||
// If it does, we only have to make 1 call to the hw to check if it can sign the given strategy,
|
||||
if (derivationSettings.AccountKeyPath == null || !await hw.CanSign(network, strategy, derivationSettings.AccountKeyPath, normalOperationTimeout.Token))
|
||||
|
||||
// Some deployment does not have the AccountKeyPath set, let's fix this...
|
||||
if (derivationSettings.AccountKeyPath == null)
|
||||
{
|
||||
// If the saved wallet key path is not present or incorrect, let's scan the wallet to see if it can sign strategy
|
||||
var foundKeyPath = await hw.FindKeyPath(network, strategy, normalOperationTimeout.Token);
|
||||
@@ -572,7 +572,34 @@ namespace BTCPayServer.Controllers
|
||||
storeData.SetSupportedPaymentMethod(derivationSettings);
|
||||
await Repository.UpdateStore(storeData);
|
||||
}
|
||||
// If it has the AccountKeyPath, let's check if we opened the right ledger
|
||||
else
|
||||
{
|
||||
// Checking if ledger is right with the RootFingerprint is faster as it does not need to make a query to the parent xpub,
|
||||
// but some deployment does not have it, so let's use AccountKeyPath instead
|
||||
if (derivationSettings.RootFingerprint == null)
|
||||
{
|
||||
|
||||
var actualPubKey = await hw.GetExtPubKey(network, derivationSettings.AccountKeyPath, normalOperationTimeout.Token);
|
||||
if (!derivationSettings.AccountDerivation.GetExtPubKeys().Any(p => p.GetPublicKey() == actualPubKey.GetPublicKey()))
|
||||
throw new HardwareWalletException($"This store is not configured to use this ledger");
|
||||
}
|
||||
// We have the root fingerprint, we can check the root from it
|
||||
else
|
||||
{
|
||||
var actualPubKey = await hw.GetExtPubKey(network, new KeyPath(), normalOperationTimeout.Token);
|
||||
if (actualPubKey.GetPublicKey().GetHDFingerPrint() != derivationSettings.RootFingerprint.Value)
|
||||
throw new HardwareWalletException($"This store is not configured to use this ledger");
|
||||
}
|
||||
}
|
||||
|
||||
// Some deployment does not have the RootFingerprint set, let's fix this...
|
||||
if (derivationSettings.RootFingerprint == null)
|
||||
{
|
||||
derivationSettings.RootFingerprint = (await hw.GetExtPubKey(network, new KeyPath(), normalOperationTimeout.Token)).GetPublicKey().GetHDFingerPrint();
|
||||
storeData.SetSupportedPaymentMethod(derivationSettings);
|
||||
await Repository.UpdateStore(storeData);
|
||||
}
|
||||
|
||||
var psbt = await CreatePSBT(network, derivationSettings, model, normalOperationTimeout.Token);
|
||||
signTimeout.CancelAfter(TimeSpan.FromMinutes(5));
|
||||
|
||||
Reference in New Issue
Block a user