Allow user to input a passphrase for Trezor v1 (Fix #5794) (#5980)

This commit is contained in:
Nicolas Dorier 2024-05-15 09:18:20 +09:00 committed by GitHub
parent 69e0ae76c7
commit 7793c5e5df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 42 additions and 25 deletions

View file

@ -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<bool> 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
{

View file

@ -41,8 +41,10 @@
</div>
<div id="passphrase-input" class="mt-4" style="display: none;">
<div class="form-group">
<label for="Password" class="input-group-text"><span class="input-group-addon fa fa-lock"></span></label>
<input id="Password" type="password" class="form-control" placeholder="Passphrase" />
<div class="input-group">
<label for="Password" class="input-group-text"><span class="input-group-addon fa fa-lock"></span></label>
<input id="Password" type="password" class="form-control" placeholder="Passphrase (Leave empty if there isn't any passphrase)" />
</div>
</div>
<div class="form-group">
<div class="input-group">

View file

@ -47,6 +47,7 @@
</form>
</div>
</template>
<div id="btcpayservervault" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="btcpayservervault" aria-hidden="true"></div>
<form method="post" asp-controller="UIStores" asp-action="UpdateWallet" asp-route-storeId="@Model.StoreId" asp-route-cryptoCode="@Model.CryptoCode">
@ -111,7 +112,6 @@
document.querySelectorAll("[data-address]").forEach(link => {
link.addEventListener("click", async event => {
event.preventDefault();
const $link = event.currentTarget;
const address = JSON.parse($link.dataset.address);
const rootedKeyPath = JSON.parse($link.dataset.rootedKeyPath);
@ -132,8 +132,9 @@
vaultUI.closeBridge();
});
while (!await vaultUI.askForDevice()) {}
$$modal.modal("show");
while (!await vaultUI.askForDevice()) {}
await vaultUI.askForDisplayAddress(rootedKeyPath);
$$modal.modal("hide");

View file

@ -1,7 +1,7 @@
@model WalletSetupViewModel
@{
Layout = "_LayoutWalletSetup";
ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Connect your hardware wallet", Context.GetStoreData().Id);
Layout = "_LayoutWalletSetup";
ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Connect your hardware wallet", Context.GetStoreData().Id);
}
@section Navbar {