From 7793c5e5dfa4b9f67075665417bebd398d306969 Mon Sep 17 00:00:00 2001 From: Nicolas Dorier Date: Wed, 15 May 2024 09:18:20 +0900 Subject: [PATCH] Allow user to input a passphrase for Trezor v1 (Fix #5794) (#5980) --- BTCPayServer/Controllers/UIVaultController.cs | 52 ++++++++++++------- .../Views/Shared/VaultElements.cshtml | 6 ++- .../ImportWallet/ConfirmAddresses.cshtml | 5 +- .../UIStores/ImportWallet/Hardware.cshtml | 4 +- 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/BTCPayServer/Controllers/UIVaultController.cs b/BTCPayServer/Controllers/UIVaultController.cs index 9907616fb..a39839a69 100644 --- a/BTCPayServer/Controllers/UIVaultController.cs +++ b/BTCPayServer/Controllers/UIVaultController.cs @@ -60,7 +60,11 @@ namespace BTCPayServer.Controllers HDFingerprint? fingerprint = null; string password = null; var websocketHelper = new WebSocketHelper(websocket); - + async Task FetchFingerprint() + { + fingerprint = (await device.GetXPubAsync(new KeyPath("44'"), cancellationToken)).ExtPubKey.ParentFingerprint; + device = new HwiDeviceClient(hwi, DeviceSelectors.FromFingerprint(fingerprint.Value), deviceEntry.Model, fingerprint) { Password = password }; + } async Task RequireDeviceUnlocking() { if (deviceEntry == null) @@ -91,6 +95,13 @@ namespace BTCPayServer.Controllers return true; } } + if (IsTrezorOne(deviceEntry) && password is null) + { + fingerprint = null; // There will be a new fingerprint + device = new HwiDeviceClient(hwi, DeviceSelectors.FromDeviceType("trezor", deviceEntry.Path), deviceEntry.Model, null); + await websocketHelper.Send("{ \"error\": \"need-passphrase\"}", cancellationToken); + return true; + } return false; } @@ -118,7 +129,7 @@ namespace BTCPayServer.Controllers } if (fingerprint is null) { - fingerprint = (await device.GetXPubAsync(new KeyPath("44'"), cancellationToken)).ExtPubKey.ParentFingerprint; + await FetchFingerprint(); } await websocketHelper.Send("{ \"info\": \"ready\"}", cancellationToken); o = JObject.Parse(await websocketHelper.NextMessageAsync(cancellationToken)); @@ -211,14 +222,26 @@ namespace BTCPayServer.Controllers var factory = network.NBXplorerNetwork.DerivationStrategyFactory; if (fingerprint is null) { - fingerprint = (await device.GetXPubAsync(new KeyPath("44'"), cancellationToken)).ExtPubKey.ParentFingerprint; + await FetchFingerprint(); } result["fingerprint"] = fingerprint.Value.ToString(); DerivationStrategyBase strategy = null; - KeyPath keyPath = null; - BitcoinExtPubKey xpub = null; + KeyPath keyPath = (addressType switch + { + "taproot" => new KeyPath("86'"), + "segwit" => new KeyPath("84'"), + "segwitWrapped" => new KeyPath("49'"), + "legacy" => new KeyPath("44'"), + _ => null + })?.Derive(network.CoinType).Derive(accountNumber, true); + if (keyPath is null) + { + await websocketHelper.Send("{ \"error\": \"invalid-addresstype\"}", cancellationToken); + continue; + } + BitcoinExtPubKey xpub = await device.GetXPubAsync(keyPath); if (!network.NBitcoinNetwork.Consensus.SupportSegwit && addressType != "legacy") { await websocketHelper.Send("{ \"error\": \"segwit-notsupported\"}", cancellationToken); @@ -232,8 +255,6 @@ namespace BTCPayServer.Controllers } if (addressType == "taproot") { - keyPath = new KeyPath("86'").Derive(network.CoinType).Derive(accountNumber, true); - xpub = await device.GetXPubAsync(keyPath); strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions() { ScriptPubKeyType = ScriptPubKeyType.TaprootBIP86 @@ -241,8 +262,6 @@ namespace BTCPayServer.Controllers } else if (addressType == "segwit") { - keyPath = new KeyPath("84'").Derive(network.CoinType).Derive(accountNumber, true); - xpub = await device.GetXPubAsync(keyPath); strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions() { ScriptPubKeyType = ScriptPubKeyType.Segwit @@ -250,8 +269,6 @@ namespace BTCPayServer.Controllers } else if (addressType == "segwitWrapped") { - keyPath = new KeyPath("49'").Derive(network.CoinType).Derive(accountNumber, true); - xpub = await device.GetXPubAsync(keyPath); strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions() { ScriptPubKeyType = ScriptPubKeyType.SegwitP2SH @@ -259,18 +276,12 @@ namespace BTCPayServer.Controllers } else if (addressType == "legacy") { - keyPath = new KeyPath("44'").Derive(network.CoinType).Derive(accountNumber, true); - xpub = await device.GetXPubAsync(keyPath); strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions() { ScriptPubKeyType = ScriptPubKeyType.Legacy }); } - else - { - await websocketHelper.Send("{ \"error\": \"invalid-addresstype\"}", cancellationToken); - continue; - } + result.Add(new JProperty("strategy", strategy.ToString())); result.Add(new JProperty("accountKey", xpub.ToString())); result.Add(new JProperty("keyPath", keyPath.ToString())); @@ -315,7 +326,6 @@ askdevice: fingerprint = device.Fingerprint; JObject json = new JObject(); json.Add("model", model); - json.Add("fingerprint", device.Fingerprint?.ToString()); await websocketHelper.Send(json.ToString(), cancellationToken); break; } @@ -386,6 +396,10 @@ askdevice: { return deviceEntry.Model.Contains("Trezor_T", StringComparison.OrdinalIgnoreCase); } + private static bool IsTrezorOne(HwiEnumerateEntry deviceEntry) + { + return deviceEntry.Model.Contains("trezor_1", StringComparison.OrdinalIgnoreCase); + } public StoreData CurrentStore { diff --git a/BTCPayServer/Views/Shared/VaultElements.cshtml b/BTCPayServer/Views/Shared/VaultElements.cshtml index 58904f7b7..6d6e39d15 100644 --- a/BTCPayServer/Views/Shared/VaultElements.cshtml +++ b/BTCPayServer/Views/Shared/VaultElements.cshtml @@ -41,8 +41,10 @@