Allow import of coldcard wallet

This commit is contained in:
Kukks 2019-05-08 20:37:37 +02:00 committed by Nicolas Dorier
parent 0b6dfe0fd3
commit 538eb66672
5 changed files with 105 additions and 27 deletions

View file

@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Data;
using BTCPayServer.Models;
using BTCPayServer.Models.StoreViewModels;
using BTCPayServer.Payments;
using BTCPayServer.Services;
@ -111,10 +113,13 @@ namespace BTCPayServer.Controllers
.FirstOrDefault(d => d.PaymentId == id);
return existing;
}
[HttpPost]
[Route("{storeId}/derivations/{cryptoCode}")]
public async Task<IActionResult> AddDerivationScheme(string storeId, DerivationSchemeViewModel vm, string cryptoCode)
public async Task<IActionResult> AddDerivationScheme(string storeId, DerivationSchemeViewModel vm,
string cryptoCode)
{
vm.CryptoCode = cryptoCode;
var store = HttpContext.GetStoreData();
@ -126,45 +131,70 @@ namespace BTCPayServer.Controllers
{
return NotFound();
}
vm.RootKeyPath = network.GetRootKeyPath();
DerivationSchemeSettings strategy = null;
PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike);
var exisingStrategy = store.GetSupportedPaymentMethods(_NetworkProvider)
.Where(c => c.PaymentId == paymentMethodId)
.OfType<DerivationSchemeSettings>()
.Select(c => c.AccountDerivation.ToString())
.FirstOrDefault();
var wallet = _WalletProvider.GetWallet(network);
if (wallet == null)
{
return NotFound();
}
PaymentMethodId paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike);
var exisingStrategy = store.GetSupportedPaymentMethods(_NetworkProvider)
.Where(c => c.PaymentId == paymentMethodId)
.OfType<DerivationSchemeSettings>()
.Select(c => c.AccountDerivation.ToString())
.FirstOrDefault();
DerivationSchemeSettings strategy = null;
try
if (vm.ColdcardPublicFile != null)
{
if (!string.IsNullOrEmpty(vm.DerivationScheme))
using (var stream = new StreamReader(vm.ColdcardPublicFile.OpenReadStream()))
{
strategy = ParseDerivationStrategy(vm.DerivationScheme, null, network);
vm.DerivationScheme = strategy.ToString();
var fileContent = await stream.ReadToEndAsync();
if (
!DerivationSchemeSettings.TryParseFromColdcard(fileContent, network, out strategy))
{
vm.StatusMessage = new StatusMessageModel()
{
Severity = StatusMessageModel.StatusSeverity.Error,
Message = "Coldcard public file was not in the correct format"
}.ToString();
vm.Confirmation = false;
return View(vm);
}
}
}
catch
else
{
ModelState.AddModelError(nameof(vm.DerivationScheme), "Invalid Derivation Scheme");
vm.Confirmation = false;
return View(vm);
try
{
if (!string.IsNullOrEmpty(vm.DerivationScheme))
{
strategy = ParseDerivationStrategy(vm.DerivationScheme, null, network);
vm.DerivationScheme = strategy.ToString();
}
}
catch
{
ModelState.AddModelError(nameof(vm.DerivationScheme), "Invalid Derivation Scheme");
vm.Confirmation = false;
return View(vm);
}
}
var storeBlob = store.GetStoreBlob();
var wasExcluded = storeBlob.GetExcludedPaymentMethods().Match(paymentMethodId);
var willBeExcluded = !vm.Enabled;
var showAddress = // Show addresses if:
// - If the user is testing the hint address in confirmation screen
(vm.Confirmation && !string.IsNullOrWhiteSpace(vm.HintAddress)) ||
// - The user is setting a new derivation scheme
(!vm.Confirmation && strategy != null && exisingStrategy != strategy.AccountDerivation.ToString()) ||
// - The user is clicking on continue without changing anything
(!vm.Confirmation && willBeExcluded == wasExcluded);
// - If the user is testing the hint address in confirmation screen
(vm.Confirmation && !string.IsNullOrWhiteSpace(vm.HintAddress)) ||
// - The user is setting a new derivation scheme
(!vm.Confirmation && strategy != null && exisingStrategy != strategy.AccountDerivation.ToString()) ||
// - The user is clicking on continue without changing anything
(!vm.Confirmation && willBeExcluded == wasExcluded);
showAddress = showAddress && strategy != null;
if (!showAddress)
@ -186,7 +216,7 @@ namespace BTCPayServer.Controllers
await _Repo.UpdateStore(store);
StatusMessage = $"Derivation scheme for {network.CryptoCode} has been modified.";
return RedirectToAction(nameof(UpdateStore), new { storeId = storeId });
return RedirectToAction(nameof(UpdateStore), new {storeId = storeId});
}
else if (!string.IsNullOrEmpty(vm.HintAddress))
{
@ -210,13 +240,17 @@ namespace BTCPayServer.Controllers
ModelState.AddModelError(nameof(vm.HintAddress), "Impossible to find a match with this address");
return ShowAddresses(vm, strategy);
}
vm.HintAddress = "";
vm.StatusMessage = "Address successfully found, please verify that the rest is correct and click on \"Confirm\"";
vm.StatusMessage =
"Address successfully found, please verify that the rest is correct and click on \"Confirm\"";
ModelState.Remove(nameof(vm.HintAddress));
ModelState.Remove(nameof(vm.DerivationScheme));
}
return ShowAddresses(vm, strategy);
}
private IActionResult ShowAddresses(DerivationSchemeViewModel vm, DerivationSchemeSettings strategy)
{

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Rendering;
using NBitcoin;
@ -32,5 +33,8 @@ namespace BTCPayServer.Models.StoreViewModels
public string StatusMessage { get; internal set; }
public KeyPath RootKeyPath { get; set; }
[Display(Name = "Coldcard Wallet File")]
public IFormFile ColdcardPublicFile{ get; set; }
}
}

View file

@ -14,6 +14,33 @@
</div>
<div class="row">
<div class="col-md-8">
<div class="modal fade" id="coldcardimport" tabindex="-1" role="dialog" aria-labelledby="coldcardimport" aria-hidden="true">
<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">Import Coldcard Wallet</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>You may import your Coldcard wallet by exporting the public details from <kbd>Advanced->MicroSD Card->Electrum Wallet</kbd> and uploading it here.</p>
<div class="form-group">
<label asp-for="ColdcardPublicFile"></label>
<input type="file" class="form-control-file" asp-for="ColdcardPublicFile" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
<form method="post">
@if (!Model.Confirmation)
{
@ -36,9 +63,12 @@
<p id="no-ledger-info" class="form-text text-muted" style="display: none;">
No ledger wallet detected. If you own one, use chrome, open the app, and refresh this page.
</p>
<div id="ledger-info" class="form-text text-muted" style="display: none;">
<div id="ledger-info" class="form-text text-muted display-when-ledger-connected" >
<span>A ledger wallet is detected, which account do you want to use? No need to paste manually xpub if your ledger device was detected. Just select derivation scheme from the list bellow and xpub will automatically populate.</span>
<div class="dropdown">
</div>
<div class="d-flex">
<div class="dropdown display-when-ledger-connected mr-2">
<button class="btn btn-primary dropdown-toggle" type="button" id="ledgerAccountsDropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Select ledger wallet account
</button>
@ -49,7 +79,13 @@
}
</div>
</div>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#coldcardimport">
Import Coldcard wallet
</button>
</div>
</div>
<div class="form-group">
<span>BTCPay format memo</span>

View file

@ -24,7 +24,7 @@
$("#ledger-loading").css("display", id === "ledger-loading" ? "block" : "none");
$("#no-ledger-info").css("display", id === "no-ledger-info" ? "block" : "none");
$("#ledger-validate").css("display", id === "ledger-validate" ? "block" : "none");
$("#ledger-info").css("display", id === "ledger-info" ? "block" : "none");
$(".display-when-ledger-connected").css("display", id === "ledger-info" ? "block" : "none");
}
function Write(prefix, type, message) {
if (type === "error") {

View file

@ -19,3 +19,7 @@
.only-for-js, .input-group-clear{
display: none;
}
.display-when-ledger-connected{
display: none;
}