Save the fingerprint of the root of LedgerWallet, and use it. Simplify HardwareWallet

This commit is contained in:
nicolas.dorier
2019-05-10 01:05:37 +09:00
parent e504163bc7
commit 01e5b319d1
6 changed files with 73 additions and 34 deletions

View File

@@ -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();
}
}

View File

@@ -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));