mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-01-19 05:33:31 +01:00
Can display address on device at confirmation screen
This commit is contained in:
parent
93f490f570
commit
540cb912f3
@ -337,8 +337,10 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var keyPath = deposit.GetKeyPath((uint)i);
|
||||
var rootedKeyPath = vm.GetAccountKeypath()?.Derive(keyPath);
|
||||
var address = line.Derive((uint)i);
|
||||
vm.AddressSamples.Add((deposit.GetKeyPath((uint)i).ToString(), address.ScriptPubKey.GetDestinationAddress(strategy.Network.NBitcoinNetwork).ToString()));
|
||||
vm.AddressSamples.Add((keyPath.ToString(), address.ScriptPubKey.GetDestinationAddress(strategy.Network.NBitcoinNetwork).ToString(), rootedKeyPath));
|
||||
}
|
||||
}
|
||||
vm.Confirmation = true;
|
||||
|
@ -168,6 +168,15 @@ namespace BTCPayServer.Controllers
|
||||
o.Add("psbt", psbt.ToBase64());
|
||||
await websocketHelper.Send(o.ToString(), cancellationToken);
|
||||
break;
|
||||
case "display-address":
|
||||
if (await RequireDeviceUnlocking())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var k = RootedKeyPath.Parse(await websocketHelper.NextMessageAsync(cancellationToken));
|
||||
await device.DisplayAddressAsync(GetScriptPubKeyType(k), k.KeyPath, cancellationToken);
|
||||
await websocketHelper.Send("{ \"info\": \"ok\"}", cancellationToken);
|
||||
break;
|
||||
case "ask-pin":
|
||||
if (device == null)
|
||||
{
|
||||
@ -324,6 +333,18 @@ askdevice:
|
||||
return new EmptyResult();
|
||||
}
|
||||
|
||||
private ScriptPubKeyType GetScriptPubKeyType(RootedKeyPath keyPath)
|
||||
{
|
||||
var path = keyPath.KeyPath.ToString();
|
||||
if (path.StartsWith("84'", StringComparison.OrdinalIgnoreCase))
|
||||
return ScriptPubKeyType.Segwit;
|
||||
if (path.StartsWith("49'", StringComparison.OrdinalIgnoreCase))
|
||||
return ScriptPubKeyType.SegwitP2SH;
|
||||
if (path.StartsWith("44'", StringComparison.OrdinalIgnoreCase))
|
||||
return ScriptPubKeyType.Legacy;
|
||||
throw new NotSupportedException("Unsupported keypath");
|
||||
}
|
||||
|
||||
private bool SameSelector(DeviceSelector a, DeviceSelector b)
|
||||
{
|
||||
var aargs = new List<string>();
|
||||
|
@ -19,10 +19,10 @@ namespace BTCPayServer.Models.StoreViewModels
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<(string KeyPath, string Address)> AddressSamples
|
||||
public List<(string KeyPath, string Address, RootedKeyPath RootedKeyPath)> AddressSamples
|
||||
{
|
||||
get; set;
|
||||
} = new List<(string KeyPath, string Address)>();
|
||||
} = new List<(string KeyPath, string Address, RootedKeyPath RootedKeyPath)>();
|
||||
|
||||
public string CryptoCode { get; set; }
|
||||
public string KeyPath { get; set; }
|
||||
@ -41,5 +41,16 @@ namespace BTCPayServer.Models.StoreViewModels
|
||||
public string DerivationSchemeFormat { get; set; }
|
||||
public string AccountKey { get; set; }
|
||||
public BTCPayNetwork Network { get; set; }
|
||||
|
||||
public RootedKeyPath GetAccountKeypath()
|
||||
{
|
||||
if (KeyPath != null && RootFingerprint != null &&
|
||||
NBitcoin.KeyPath.TryParse(KeyPath, out var p) &&
|
||||
HDFingerprint.TryParse(RootFingerprint, out var fp))
|
||||
{
|
||||
return new RootedKeyPath(fp, p);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
@section HeadScripts {
|
||||
<style type="text/css">
|
||||
|
||||
.hw-fields {
|
||||
display: none;
|
||||
}
|
||||
@ -18,12 +19,42 @@
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="btcpayservervault" tabindex="-1" role="dialog" aria-labelledby="btcpayservervault" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<partial name="VaultElements" />
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div id="WebsocketPath" style="display:none;">@Url.Action("VaultBridgeConnection", "Vault", new { cryptoCode = Model.CryptoCode })</div>
|
||||
@if (!Model.Confirmation)
|
||||
{
|
||||
<partial name="AddDerivationSchemes_HardwareWalletDialogs" model="@Model" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<template id="btcpayservervault_template">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form class="modal-content" form method="post" enctype="multipart/form-data">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Address verification</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Confirm on the device that you see address <b id="displayedAddress"></b></p>
|
||||
<div class="form-group">
|
||||
<div id="vaultPlaceholder"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button id="vault-confirm" class="btn btn-primary" style="display:none;"></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
}
|
||||
<form method="post">
|
||||
|
||||
<input id="Config" asp-for="Config" type="hidden" />
|
||||
@ -50,8 +81,9 @@
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<button class="dropdown-item" type="button">... Coldcard (air gap)</button>
|
||||
<button class="dropdown-item check-for-ledger" type="button">... Ledger Wallet</button>
|
||||
@if (Model.CryptoCode == "BTC") {
|
||||
<button class="dropdown-item check-for-vault" type="button">... the vault (preview)</button>
|
||||
@if (Model.CryptoCode == "BTC")
|
||||
{
|
||||
<button class="dropdown-item check-for-vault" type="button">... the vault (preview)</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@ -133,6 +165,10 @@
|
||||
<tr>
|
||||
<th>Key path</th>
|
||||
<th>Address</th>
|
||||
@if (Model.Source == "Vault")
|
||||
{
|
||||
<th>Actions</th>
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -141,6 +177,10 @@
|
||||
<tr>
|
||||
<td>@sample.KeyPath</td>
|
||||
<td>@sample.Address</td>
|
||||
@if (Model.Source == "Vault")
|
||||
{
|
||||
<td><a class="showaddress" href="#" onclick='showAddress(@Safe.Json(sample.RootedKeyPath.ToString()), @Safe.Json(sample.Address)); return false;'>Show on device</a></td>
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
|
@ -80,8 +80,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="WebsocketPath" style="display:none;">@Url.Action("VaultBridgeConnection", "Vault", new { cryptoCode = Model.CryptoCode })</div>
|
||||
|
||||
<template id="btcpayservervault_template">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form class="modal-content" form method="post" enctype="multipart/form-data">
|
||||
@ -123,7 +121,3 @@
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
<div class="modal fade" id="btcpayservervault" tabindex="-1" role="dialog" aria-labelledby="btcpayservervault" aria-hidden="true">
|
||||
|
||||
</div>
|
||||
<partial name="VaultElements" />
|
||||
|
@ -87,6 +87,42 @@
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function getVaultUI() {
|
||||
var websocketPath = $("#WebsocketPath").text();
|
||||
var loc = window.location, ws_uri;
|
||||
if (loc.protocol === "https:") {
|
||||
ws_uri = "wss:";
|
||||
} else {
|
||||
ws_uri = "ws:";
|
||||
}
|
||||
ws_uri += "//" + loc.host;
|
||||
ws_uri += websocketPath;
|
||||
return new vaultui.VaultBridgeUI(ws_uri);
|
||||
}
|
||||
|
||||
function showModal() {
|
||||
var html = $("#btcpayservervault_template").html();
|
||||
$("#btcpayservervault").html(html);
|
||||
html = $("#VaultConnection").html();
|
||||
$("#vaultPlaceholder").html(html);
|
||||
$('#btcpayservervault').modal();
|
||||
}
|
||||
|
||||
async function showAddress(rootedKeyPath, address) {
|
||||
$(".showaddress").addClass("disabled");
|
||||
showModal();
|
||||
$("#btcpayservervault #displayedAddress").text(address);
|
||||
var vaultUI = getVaultUI();
|
||||
$('#btcpayservervault').on('hidden.bs.modal', function () {
|
||||
vaultUI.closeBridge();
|
||||
$(".showaddress").removeClass("disabled");
|
||||
});
|
||||
if (await vaultUI.askForDevice())
|
||||
await vaultUI.askForDisplayAddress(rootedKeyPath);
|
||||
$('#btcpayservervault').modal("hide");
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
var ledgerInit = false;
|
||||
$(".check-for-ledger").on("click", function () {
|
||||
@ -102,16 +138,6 @@ $(document).ready(function () {
|
||||
$("#" + id).css("display", "block");
|
||||
}
|
||||
|
||||
var websocketPath = $("#WebsocketPath").text();
|
||||
var loc = window.location, ws_uri;
|
||||
if (loc.protocol === "https:") {
|
||||
ws_uri = "wss:";
|
||||
} else {
|
||||
ws_uri = "ws:";
|
||||
}
|
||||
ws_uri += "//" + loc.host;
|
||||
ws_uri += websocketPath;
|
||||
|
||||
function displayXPubs(xpub) {
|
||||
$("#DerivationScheme").val(xpub.strategy);
|
||||
$("#RootFingerprint").val(xpub.fingerprint);
|
||||
@ -124,12 +150,8 @@ $(document).ready(function () {
|
||||
}
|
||||
|
||||
$(".check-for-vault").on("click", async function () {
|
||||
var html = $("#btcpayservervault_template").html();
|
||||
$("#btcpayservervault").html(html);
|
||||
html = $("#VaultConnection").html();
|
||||
$("#vaultPlaceholder").html(html);
|
||||
$('#btcpayservervault').modal();
|
||||
var vaultUI = new vaultui.VaultBridgeUI(ws_uri);
|
||||
var vaultUI = getVaultUI();
|
||||
showModal();
|
||||
$('#btcpayservervault').on('hidden.bs.modal', function () {
|
||||
vaultUI.closeBridge();
|
||||
});
|
||||
|
@ -49,6 +49,7 @@ var vaultui = (function () {
|
||||
needPassphrase: new VaultFeedback("?", "Enter the passphrase.", "vault-feedback3", "need-passphrase"),
|
||||
needPassphraseOnDevice: new VaultFeedback("?", "Please, enter the passphrase on the device.", "vault-feedback3", "need-passphrase-on-device"),
|
||||
signingTransaction: new VaultFeedback("?", "Please review and confirm the transaction on your device...", "vault-feedback3", "ask-signing"),
|
||||
reviewAddress: new VaultFeedback("?", "Please review the address on your device...", "vault-feedback3", "ask-signing"),
|
||||
signingRejected: new VaultFeedback("failed", "The user refused to sign the transaction", "vault-feedback3", "user-reject"),
|
||||
};
|
||||
|
||||
@ -175,6 +176,20 @@ var vaultui = (function () {
|
||||
}
|
||||
return true;
|
||||
};
|
||||
this.askForDisplayAddress = async function (rootedKeyPath) {
|
||||
if (!await self.ensureConnectedToBackend())
|
||||
return false;
|
||||
show(VaultFeedbacks.reviewAddress);
|
||||
self.bridge.socket.send("display-address");
|
||||
self.bridge.socket.send(rootedKeyPath);
|
||||
var json = await self.bridge.waitBackendMessage();
|
||||
if (json.hasOwnProperty("error")) {
|
||||
if (await needRetry(json))
|
||||
return await self.askForDisplayAddress(rootedKeyPath);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
this.askForDevice = async function () {
|
||||
if (!await self.ensureConnectedToBackend())
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user