mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 14:34:23 +01:00
@@ -60,7 +60,11 @@ namespace BTCPayServer.Controllers
|
|||||||
HDFingerprint? fingerprint = null;
|
HDFingerprint? fingerprint = null;
|
||||||
string password = null;
|
string password = null;
|
||||||
var websocketHelper = new WebSocketHelper(websocket);
|
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()
|
async Task<bool> RequireDeviceUnlocking()
|
||||||
{
|
{
|
||||||
if (deviceEntry == null)
|
if (deviceEntry == null)
|
||||||
@@ -91,6 +95,13 @@ namespace BTCPayServer.Controllers
|
|||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +129,7 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
if (fingerprint is null)
|
if (fingerprint is null)
|
||||||
{
|
{
|
||||||
fingerprint = (await device.GetXPubAsync(new KeyPath("44'"), cancellationToken)).ExtPubKey.ParentFingerprint;
|
await FetchFingerprint();
|
||||||
}
|
}
|
||||||
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));
|
||||||
@@ -211,14 +222,26 @@ namespace BTCPayServer.Controllers
|
|||||||
var factory = network.NBXplorerNetwork.DerivationStrategyFactory;
|
var factory = network.NBXplorerNetwork.DerivationStrategyFactory;
|
||||||
if (fingerprint is null)
|
if (fingerprint is null)
|
||||||
{
|
{
|
||||||
fingerprint = (await device.GetXPubAsync(new KeyPath("44'"), cancellationToken)).ExtPubKey.ParentFingerprint;
|
await FetchFingerprint();
|
||||||
}
|
}
|
||||||
result["fingerprint"] = fingerprint.Value.ToString();
|
result["fingerprint"] = fingerprint.Value.ToString();
|
||||||
|
|
||||||
DerivationStrategyBase strategy = null;
|
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")
|
if (!network.NBitcoinNetwork.Consensus.SupportSegwit && addressType != "legacy")
|
||||||
{
|
{
|
||||||
await websocketHelper.Send("{ \"error\": \"segwit-notsupported\"}", cancellationToken);
|
await websocketHelper.Send("{ \"error\": \"segwit-notsupported\"}", cancellationToken);
|
||||||
@@ -232,8 +255,6 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
if (addressType == "taproot")
|
if (addressType == "taproot")
|
||||||
{
|
{
|
||||||
keyPath = new KeyPath("86'").Derive(network.CoinType).Derive(accountNumber, true);
|
|
||||||
xpub = await device.GetXPubAsync(keyPath);
|
|
||||||
strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions()
|
strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions()
|
||||||
{
|
{
|
||||||
ScriptPubKeyType = ScriptPubKeyType.TaprootBIP86
|
ScriptPubKeyType = ScriptPubKeyType.TaprootBIP86
|
||||||
@@ -241,8 +262,6 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
else if (addressType == "segwit")
|
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()
|
strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions()
|
||||||
{
|
{
|
||||||
ScriptPubKeyType = ScriptPubKeyType.Segwit
|
ScriptPubKeyType = ScriptPubKeyType.Segwit
|
||||||
@@ -250,8 +269,6 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
else if (addressType == "segwitWrapped")
|
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()
|
strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions()
|
||||||
{
|
{
|
||||||
ScriptPubKeyType = ScriptPubKeyType.SegwitP2SH
|
ScriptPubKeyType = ScriptPubKeyType.SegwitP2SH
|
||||||
@@ -259,18 +276,12 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
else if (addressType == "legacy")
|
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()
|
strategy = factory.CreateDirectDerivationStrategy(xpub, new DerivationStrategyOptions()
|
||||||
{
|
{
|
||||||
ScriptPubKeyType = ScriptPubKeyType.Legacy
|
ScriptPubKeyType = ScriptPubKeyType.Legacy
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
await websocketHelper.Send("{ \"error\": \"invalid-addresstype\"}", cancellationToken);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
result.Add(new JProperty("strategy", strategy.ToString()));
|
result.Add(new JProperty("strategy", strategy.ToString()));
|
||||||
result.Add(new JProperty("accountKey", xpub.ToString()));
|
result.Add(new JProperty("accountKey", xpub.ToString()));
|
||||||
result.Add(new JProperty("keyPath", keyPath.ToString()));
|
result.Add(new JProperty("keyPath", keyPath.ToString()));
|
||||||
@@ -315,7 +326,6 @@ askdevice:
|
|||||||
fingerprint = device.Fingerprint;
|
fingerprint = device.Fingerprint;
|
||||||
JObject json = new JObject();
|
JObject json = new JObject();
|
||||||
json.Add("model", model);
|
json.Add("model", model);
|
||||||
json.Add("fingerprint", device.Fingerprint?.ToString());
|
|
||||||
await websocketHelper.Send(json.ToString(), cancellationToken);
|
await websocketHelper.Send(json.ToString(), cancellationToken);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -386,6 +396,10 @@ askdevice:
|
|||||||
{
|
{
|
||||||
return deviceEntry.Model.Contains("Trezor_T", StringComparison.OrdinalIgnoreCase);
|
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
|
public StoreData CurrentStore
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,8 +41,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="passphrase-input" class="mt-4" style="display: none;">
|
<div id="passphrase-input" class="mt-4" style="display: none;">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="Password" class="input-group-text"><span class="input-group-addon fa fa-lock"></span></label>
|
<div class="input-group">
|
||||||
<input id="Password" type="password" class="form-control" placeholder="Passphrase" />
|
<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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div id="btcpayservervault" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="btcpayservervault" aria-hidden="true"></div>
|
<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">
|
<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 => {
|
document.querySelectorAll("[data-address]").forEach(link => {
|
||||||
link.addEventListener("click", async event => {
|
link.addEventListener("click", async event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const $link = event.currentTarget;
|
const $link = event.currentTarget;
|
||||||
const address = JSON.parse($link.dataset.address);
|
const address = JSON.parse($link.dataset.address);
|
||||||
const rootedKeyPath = JSON.parse($link.dataset.rootedKeyPath);
|
const rootedKeyPath = JSON.parse($link.dataset.rootedKeyPath);
|
||||||
@@ -132,8 +132,9 @@
|
|||||||
vaultUI.closeBridge();
|
vaultUI.closeBridge();
|
||||||
});
|
});
|
||||||
|
|
||||||
while (!await vaultUI.askForDevice()) {}
|
$$modal.modal("show");
|
||||||
|
|
||||||
|
while (!await vaultUI.askForDevice()) {}
|
||||||
await vaultUI.askForDisplayAddress(rootedKeyPath);
|
await vaultUI.askForDisplayAddress(rootedKeyPath);
|
||||||
|
|
||||||
$$modal.modal("hide");
|
$$modal.modal("hide");
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model WalletSetupViewModel
|
@model WalletSetupViewModel
|
||||||
@{
|
@{
|
||||||
Layout = "_LayoutWalletSetup";
|
Layout = "_LayoutWalletSetup";
|
||||||
ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Connect your hardware wallet", Context.GetStoreData().Id);
|
ViewData.SetActivePage(StoreNavPages.OnchainSettings, "Connect your hardware wallet", Context.GetStoreData().Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Navbar {
|
@section Navbar {
|
||||||
|
|||||||
Reference in New Issue
Block a user