Ask passphrase when appropriate (Fix #1185)

This commit is contained in:
nicolas.dorier
2019-11-22 19:12:30 +09:00
parent a324e2aeaf
commit eef623fb4b
3 changed files with 73 additions and 11 deletions

View File

@@ -8,6 +8,7 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Hwi;
using BTCPayServer.ModelBinders; using BTCPayServer.ModelBinders;
using BTCPayServer.Models; using BTCPayServer.Models;
using BTCPayServer.Models.StoreViewModels; using BTCPayServer.Models.StoreViewModels;
@@ -60,8 +61,27 @@ namespace BTCPayServer.Controllers
Transport = new HwiWebSocketTransport(websocket) Transport = new HwiWebSocketTransport(websocket)
}; };
Hwi.HwiDeviceClient device = null; Hwi.HwiDeviceClient device = null;
HwiEnumerateEntry deviceEntry = null;
HDFingerprint? fingerprint = null; HDFingerprint? fingerprint = null;
string password = null;
int? pin = null;
var websocketHelper = new WebSocketHelper(websocket); var websocketHelper = new WebSocketHelper(websocket);
async Task<bool> RequireMoreInformation()
{
if (deviceEntry.NeedsPinSent is true && pin is null)
{
await websocketHelper.Send("{ \"error\": \"need-pin\"}", cancellationToken);
return true;
}
if (deviceEntry.NeedsPassphraseSent is true && password == null)
{
await websocketHelper.Send("{ \"error\": \"need-passphrase\"}", cancellationToken);
return true;
}
return false;
}
JObject o = null; JObject o = null;
try try
{ {
@@ -70,12 +90,20 @@ namespace BTCPayServer.Controllers
var command = await websocketHelper.NextMessageAsync(cancellationToken); var command = await websocketHelper.NextMessageAsync(cancellationToken);
switch (command) switch (command)
{ {
case "set-passphrase":
device.Password = await websocketHelper.NextMessageAsync(cancellationToken);
password = device.Password;
break;
case "ask-sign": case "ask-sign":
if (device == null) if (device == null)
{ {
await websocketHelper.Send("{ \"error\": \"need-device\"}", cancellationToken); await websocketHelper.Send("{ \"error\": \"need-device\"}", cancellationToken);
continue; continue;
} }
if (await RequireMoreInformation())
{
continue;
}
if (walletId == null) if (walletId == null)
{ {
await websocketHelper.Send("{ \"error\": \"invalid-walletId\"}", cancellationToken); await websocketHelper.Send("{ \"error\": \"invalid-walletId\"}", cancellationToken);
@@ -92,6 +120,11 @@ namespace BTCPayServer.Controllers
await websocketHelper.Send("{ \"error\": \"need-pin\"}", cancellationToken); await websocketHelper.Send("{ \"error\": \"need-pin\"}", cancellationToken);
continue; continue;
} }
catch (Hwi.HwiException ex) when (ex.ErrorCode == Hwi.HwiErrorCode.NoPassword)
{
await websocketHelper.Send("{ \"error\": \"need-passphrase\"}", cancellationToken);
continue;
}
} }
await websocketHelper.Send("{ \"info\": \"ready\"}", cancellationToken); await websocketHelper.Send("{ \"info\": \"ready\"}", cancellationToken);
o = JObject.Parse(await websocketHelper.NextMessageAsync(cancellationToken)); o = JObject.Parse(await websocketHelper.NextMessageAsync(cancellationToken));
@@ -119,6 +152,11 @@ namespace BTCPayServer.Controllers
await websocketHelper.Send("{ \"error\": \"need-pin\"}", cancellationToken); await websocketHelper.Send("{ \"error\": \"need-pin\"}", cancellationToken);
continue; continue;
} }
catch (Hwi.HwiException ex) when (ex.ErrorCode == Hwi.HwiErrorCode.NoPassword)
{
await websocketHelper.Send("{ \"error\": \"need-passphrase\"}", cancellationToken);
continue;
}
catch (Hwi.HwiException) catch (Hwi.HwiException)
{ {
await websocketHelper.Send("{ \"error\": \"user-reject\"}", cancellationToken); await websocketHelper.Send("{ \"error\": \"user-reject\"}", cancellationToken);
@@ -136,11 +174,8 @@ namespace BTCPayServer.Controllers
} }
await device.PromptPinAsync(cancellationToken); await device.PromptPinAsync(cancellationToken);
await websocketHelper.Send("{ \"info\": \"prompted, please input the pin\"}", cancellationToken); await websocketHelper.Send("{ \"info\": \"prompted, please input the pin\"}", cancellationToken);
o = JObject.Parse(await websocketHelper.NextMessageAsync(cancellationToken)); pin = int.Parse(await websocketHelper.NextMessageAsync(cancellationToken), CultureInfo.InvariantCulture);
var pin = (int)o["pinCode"].Value<long>(); if (await device.SendPinAsync(pin.Value, cancellationToken))
var passphrase = o["passphrase"].Value<string>();
device.Password = passphrase;
if (await device.SendPinAsync(pin, cancellationToken))
{ {
await websocketHelper.Send("{ \"info\": \"the pin is correct\"}", cancellationToken); await websocketHelper.Send("{ \"info\": \"the pin is correct\"}", cancellationToken);
} }
@@ -156,6 +191,10 @@ namespace BTCPayServer.Controllers
await websocketHelper.Send("{ \"error\": \"need-device\"}", cancellationToken); await websocketHelper.Send("{ \"error\": \"need-device\"}", cancellationToken);
continue; continue;
} }
if (await RequireMoreInformation())
{
continue;
}
JObject result = new JObject(); JObject result = new JObject();
var factory = network.NBXplorerNetwork.DerivationStrategyFactory; var factory = network.NBXplorerNetwork.DerivationStrategyFactory;
var keyPath = new KeyPath("84'").Derive(network.CoinType).Derive(0, true); var keyPath = new KeyPath("84'").Derive(network.CoinType).Derive(0, true);
@@ -169,6 +208,11 @@ namespace BTCPayServer.Controllers
await websocketHelper.Send("{ \"error\": \"need-pin\"}", cancellationToken); await websocketHelper.Send("{ \"error\": \"need-pin\"}", cancellationToken);
continue; continue;
} }
catch (Hwi.HwiException ex) when (ex.ErrorCode == Hwi.HwiErrorCode.NoPassword)
{
await websocketHelper.Send("{ \"error\": \"need-passphrase\"}", cancellationToken);
continue;
}
if (fingerprint is null) if (fingerprint is null)
{ {
fingerprint = (await device.GetXPubAsync(new KeyPath("44'"), cancellationToken)).ExtPubKey.ParentFingerprint; fingerprint = (await device.GetXPubAsync(new KeyPath("44'"), cancellationToken)).ExtPubKey.ParentFingerprint;
@@ -196,13 +240,18 @@ namespace BTCPayServer.Controllers
await websocketHelper.Send(result.ToString(), cancellationToken); await websocketHelper.Send(result.ToString(), cancellationToken);
break; break;
case "ask-device": case "ask-device":
var devices = (await hwi.EnumerateDevicesAsync(cancellationToken)).ToList(); password = null;
device = devices.FirstOrDefault(); pin = null;
if (device == null) deviceEntry = null;
device = null;
var entries = (await hwi.EnumerateEntriesAsync(cancellationToken)).ToList();
deviceEntry = entries.FirstOrDefault();
if (deviceEntry == null)
{ {
await websocketHelper.Send("{ \"error\": \"no-device\"}", cancellationToken); await websocketHelper.Send("{ \"error\": \"no-device\"}", cancellationToken);
continue; continue;
} }
device = new HwiDeviceClient(hwi, deviceEntry.DeviceSelector, deviceEntry.Model, deviceEntry.Fingerprint);
fingerprint = device.Fingerprint; fingerprint = device.Fingerprint;
JObject json = new JObject(); JObject json = new JObject();
json.Add("model", device.Model.ToString()); json.Add("model", device.Model.ToString());

View File

@@ -41,7 +41,7 @@
<div class="input-group-prepend"> <div class="input-group-prepend">
<label for="Password" class="input-group-text"><span class="input-group-addon fa fa-lock"></span></label> <label for="Password" class="input-group-text"><span class="input-group-addon fa fa-lock"></span></label>
</div> </div>
<input id="Password" type="password" class="form-control" placeholder="Password" /> <input id="Password" type="password" class="form-control" placeholder="Passphrase" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">

View File

@@ -114,6 +114,11 @@ var vaultui = (function () {
if (await self.askForPin()) if (await self.askForPin())
return true; return true;
} }
if (json.error === "need-passphrase") {
handled = true;
if (await self.askForPassphrase())
return true;
}
if (!handled) { if (!handled) {
showError(json); showError(json);
} }
@@ -230,6 +235,15 @@ var vaultui = (function () {
}); });
}; };
this.askForPassphrase = async function () {
if (!await self.ensureConnectedToBackend())
return false;
var passphrase = await self.getUserPassphrase();
self.bridge.socket.send("set-passphrase");
self.bridge.socket.send(passphrase);
return true;
}
/** /**
* @returns {Promise} * @returns {Promise}
*/ */
@@ -246,8 +260,7 @@ var vaultui = (function () {
} }
var pinCode = await self.getUserEnterPin(); var pinCode = await self.getUserEnterPin();
var passphrase = await self.getUserPassphrase(); self.bridge.socket.send(pinCode);
self.bridge.socket.send(JSON.stringify({ pinCode: pinCode, passphrase: passphrase }));
var json = await self.bridge.waitBackendMessage(); var json = await self.bridge.waitBackendMessage();
if (json.hasOwnProperty("error")) { if (json.hasOwnProperty("error")) {
showError(json); showError(json);