btcpayserver/BTCPayServer/Views/Wallets/WalletSettings.cshtml
Andrew Camilleri 4176f3659b
Add QR code scan/show for PSBT + Import wallet via QR (#1931)
* Add PSBT QR code scan/show

This PR introduces support to show and read PSBTs in BC-UR format via animated QR codes.  This allows you to use BTCPay with HW devices such as Cobo Vault and Blue wallet to sign transactions without ever exposing the keys outside of that device.
Spec: https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-005-ur.md
I've also bumped the QR code library we sue as it had a bug with large datasets.

* Reuse same code for all and allow wallet import via QR code scan

* remove unecessary js vendor files

* Allow export wallet from settings via QR

* formatting

* bundle

* fix wallet receive bundle
2020-10-21 14:03:11 +02:00

130 lines
6.4 KiB
Plaintext

@using Newtonsoft.Json
@using System.Text
@using NBitcoin.DataEncoders
@model WalletSettingsViewModel
@{
Layout = "../Shared/_NavLayout.cshtml";
ViewData["Title"] = "Wallet settings";
ViewData.SetActivePageAndTitle(WalletsNavPages.Settings);
}
@if (TempData.HasStatusMessage())
{
<partial name="_StatusMessage" />
}
<h4 class="mb-3">Additional wallet information</h4>
<div class="row">
<div class="col-md-8 col-lg-6">
<form method="post" asp-action="WalletSettings">
<input type="hidden" asp-for="StoreName"/>
<input type="hidden" asp-for="UriScheme"/>
<div class="form-group">
<label asp-for="Label"></label>
<input asp-for="Label" class="form-control"/>
<span asp-validation-for="Label" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DerivationScheme"></label>
<input asp-for="DerivationScheme" class="form-control" readonly/>
<span asp-validation-for="DerivationScheme" class="text-danger"></span>
</div>
@if (!string.IsNullOrEmpty(Model.DerivationSchemeInput) && Model.DerivationSchemeInput != Model.DerivationScheme)
{
<div class="form-group">
<label asp-for="DerivationSchemeInput"></label>
<input asp-for="DerivationSchemeInput" class="form-control" readonly/>
<span asp-validation-for="DerivationSchemeInput" class="text-danger"></span>
</div>
}
@for (int i = 0; i < Model.AccountKeys.Count; i++)
{
<hr class="my-4"/>
<span class="d-flex">
<h4 class="mb-3">Account key @i</h4>
<button type="button" class="btn btn-link only-for-js mb-2 fa fa-qrcode text-decoration-none" data-wallet="@i" title="Show QR"></button></span>
<div class="form-group">
<label asp-for="@Model.AccountKeys[i].AccountKey"></label>
<input asp-for="@Model.AccountKeys[i].AccountKey" class="form-control" readonly/>
<span asp-validation-for="@Model.AccountKeys[i].AccountKey" class="text-danger"></span>
</div>
<div class="form-row">
<div class="form-group col-auto">
<label asp-for="@Model.AccountKeys[i].MasterFingerprint"></label>
<input asp-for="@Model.AccountKeys[i].MasterFingerprint" class="form-control" style="max-width:16ch;"/>
<span asp-validation-for="@Model.AccountKeys[i].MasterFingerprint" class="text-danger"></span>
</div>
<div class="form-group col-auto">
<label asp-for="@Model.AccountKeys[i].AccountKeyPath"></label>
<input asp-for="@Model.AccountKeys[i].AccountKeyPath" class="form-control" style="max-width:16ch;" />
<span asp-validation-for="@Model.AccountKeys[i].AccountKeyPath" class="text-danger"></span>
</div>
</div>
@if (Model.IsMultiSig)
{
<div class="form-check form-check-inline">
<input asp-for="SelectedSigningKey" class="form-check-input" type="radio" value="@Model.AccountKeys[i].AccountKey"/>
<label asp-for="SelectedSigningKey" class="form-check-label"></label>
</div>
}
}
<div class="form-group d-flex mt-3">
<button name="command" type="submit" class="btn btn-primary mr-2" value="save">Save</button>
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="SettingsMenu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Other actions...
</button>
<div class="dropdown-menu" aria-labelledby="SendMenu">
<button name="command" type="submit" class="dropdown-item" value="prune">Prune old transactions from history</button>
@if (Model.NBXSeedAvailable)
{
<button name="command" type="submit" class="dropdown-item" value="view-seed">View seed</button>
}
@if (Model.UriScheme == "bitcoin")
{
<button type="button" class="dropdown-item register-wallet" data-storename="@Model.StoreName" data-scheme="@Model.UriScheme" data-url="@Url.Action("WalletSend", "Wallets", new {walletId = Context.GetRouteValue("walletId"), bip21 = "%s"})">Open this bitcoin wallet on payment links</button>
}
</div>
</div>
</div>
</form>
</div>
</div>
<script src="~/vendor/vuejs/vue.min.js" asp-append-version="true"></script>
<script src="~/vendor/vue-qrcode/vue-qrcode.min.js" asp-append-version="true"></script>
<script src="~/vendor/bc-ur/web-bundle.js" asp-append-version="true"></script>
<script src="~/vendor/vue-qrcode-reader/vue-qrcode-reader.browser.js" asp-append-version="true"></script>
<link href="~/vendor/vue-qrcode-reader/vue-qrcode-reader.css" rel="stylesheet" asp-append-version="true"/>
<partial name="ShowQR"/>
<script>
var wallets = @Safe.Json(Model.AccountKeys.Select(model => Encoders.Hex.EncodeData(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(model)))));
$(document).ready(function(){
var qrApp = initQRShow("Wallet QR", "", "scan-qr-modal");
$("button[data-wallet]").on("click", function (){
var data = $(this).data("wallet");
var wallet = wallets[parseInt(data)];
qrApp.data = wallet;
$("#scan-qr-modal").modal("show");
});
if(navigator.registerProtocolHandler){
$(".register-wallet")
.show()
.on("click", function(){
var store = $(this).data("storename");
var scheme = $(this).data("scheme");
var url = decodeURIComponent($(this).data("url"));
navigator.registerProtocolHandler(scheme, url, "BTCPay Wallet -" + store);
});
}
});
</script>
<style>
.register-wallet{
display: none;
}
</style>