Skip to content

Commit 11f42a9

Browse files
Merge pull request #234 from ben-kaufman/toggle-passphrase
Support HWI toggle_passphrase
2 parents ca32341 + 3a939ad commit 11f42a9

File tree

8 files changed

+86
-19
lines changed

8 files changed

+86
-19
lines changed

src/cryptoadvance/specter/device.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def __init__(self, name, alias, device_type, keys, fullpath, manager):
1919
self.sd_card_support = False
2020
self.qr_code_support = False
2121
self.hwi_support = False
22+
self.supports_hwi_toggle_passphrase = False
2223
self.supports_hwi_multisig_display_address = False
2324

2425
def create_psbts(self, base64_psbt, wallet):

src/cryptoadvance/specter/devices/keepkey.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ def __init__(self, name, alias, device_type, keys, fullpath, manager):
55
HWIDevice.__init__(self, name, alias, 'keepkey', keys, fullpath, manager)
66
self.sd_card_support = False
77
self.qr_code_support = False
8+
self.supports_hwi_toggle_passphrase = True
89
self.supports_hwi_multisig_display_address = True

src/cryptoadvance/specter/devices/trezor.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ def __init__(self, name, alias, device_type, keys, fullpath, manager):
55
HWIDevice.__init__(self, name, alias, 'trezor', keys, fullpath, manager)
66
self.sd_card_support = False
77
self.qr_code_support = False
8+
self.supports_hwi_toggle_passphrase = True
89
self.supports_hwi_multisig_display_address = True

src/cryptoadvance/specter/hwi_rpc.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def __init__(self):
1919
self.exposed_rpc = {
2020
"enumerate": self.enumerate,
2121
"detect_device": self.detect_device,
22+
"toggle_passphrase": self.toggle_passphrase,
2223
"prompt_pin": self.prompt_pin,
2324
"send_pin": self.send_pin,
2425
"extract_xpubs": self.extract_xpubs,
@@ -60,6 +61,14 @@ def detect_device(self, device_type=None, path=None, fingerprint=None, rescan_de
6061
if len(res) > 0:
6162
return res[0]
6263

64+
@locked(hwilock)
65+
def toggle_passphrase(self, device_type=None, path=None, passphrase='', chain=''):
66+
if device_type == "keepkey" or device_type == "trezor":
67+
client = self._get_client(device_type=device_type, path=path, passphrase=passphrase, chain=chain)
68+
return hwi_commands.toggle_passphrase(client)
69+
else:
70+
raise Exception("Invalid HWI device type %s, toggle_passphrase is only supported for Trezor and Keepkey devices" % device_type)
71+
6372
@locked(hwilock)
6473
def prompt_pin(self, device_type=None, path=None, passphrase='', chain=''):
6574
if device_type == "keepkey" or device_type == "trezor":

src/cryptoadvance/specter/static/hwi.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ class HWIBridge {
4545
return await this.fetch("detect_device",
4646
{ device_type: type, rescan_devices: rescan });
4747
}
48+
49+
async togglePassphrase(device) {
50+
/**
51+
Tells the server to send the 'togglepassphrase' command to the device.
52+
KeepKey and Trezor only.
53+
**/
54+
return await this.fetch('toggle_passphrase', {
55+
device_type: device.type,
56+
path: device.path
57+
});
58+
}
59+
4860
async promptPin(device, passphrase="") {
4961
/**
5062
Tells the server to send the 'promptpin' command to the device.

src/cryptoadvance/specter/templates/device/device.jinja

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{% extends "base.jinja" %}
22
{% block main %}
3+
{% include "includes/hwi/hwi.jinja" %}
34
<h1>{{ device.name }}</h1>
45
<form action="./" method="POST">
56
<div class="row">
@@ -48,12 +49,16 @@
4849
</div>
4950
<div class="spacer"></div>
5051
<div class="row">
52+
{% if device.supports_hwi_toggle_passphrase %}
53+
<button type="button" class="btn centered" onclick="togglePassphrase()">Toggle device passphrase</button>
54+
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;
55+
{% endif %}
5156
{% if device.device_type != 'bitcoincore' %}
5257
<form action="./" method="POST">
5358
<button id="add_keys" type="submit" name="action" value="add_keys" class="btn centered">Add more keys</button>
5459
</form>
55-
{% endif %}
5660
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;
61+
{% endif %}
5762
<form action="./" method="POST">
5863
<button type="submit" name="action" value="forget" class="btn danger centered">Forget the device</button>
5964
</form>
@@ -95,5 +100,37 @@
95100
}
96101
}, false);
97102
});
103+
104+
async function togglePassphrase(){
105+
let devices = await enumerate('{{ device.device_type }}');
106+
if(devices == null || devices.length == 0){
107+
return;
108+
}
109+
let device = await selectDevice(devices, '');
110+
showHWIProgress("Processing...", `Keep your ${capitalize(device.type)} connected.`);
111+
let result = null;
112+
try {
113+
result = await hwi.togglePassphrase(device);
114+
} catch (error) {
115+
handleHWIError(error);
116+
return null;
117+
}
118+
if(!overlayIsActive()){
119+
showNotification("HWI is ready again", 10000);
120+
// no need to proceed at all
121+
return null;
122+
}
123+
hidePageOverlay();
124+
if (device.type == "keepkey") {
125+
result = await enterPin(device, false);
126+
if(result == null){
127+
return null;
128+
}
129+
if(!('success' in result) || !result.success){
130+
throw "Failed to unlock device! Invalid PIN code?";
131+
}
132+
}
133+
showNotification("{{ device.name }} passphrase toggled successfuly", 5000)
134+
}
98135
</script>
99136
{% endblock %}

src/cryptoadvance/specter/templates/includes/hwi/components/pin.jinja

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,24 @@
77
</div>
88

99
<script type="text/javascript">
10-
async function enterPin(device){
11-
showHWIProgress("Processing...", `Keep your ${capitalize(device.type)} connected.`);
10+
async function enterPin(device, promptPin=true){
1211
let result = null;
13-
try {
14-
result = await hwi.promptPin(device);
15-
} catch (error) {
16-
handleHWIError(error);
17-
return null;
18-
}
19-
console.log(result);
20-
if(!overlayIsActive()){
21-
showNotification("HWI is ready again", 10000);
22-
// no need to proceed at all
23-
return null;
12+
if (promptPin) {
13+
showHWIProgress("Awaiting Confirmation...", `Please confirm the action on your ${capitalize(device.type)} device.`);
14+
try {
15+
result = await hwi.promptPin(device);
16+
} catch (error) {
17+
handleHWIError(error);
18+
return null;
19+
}
20+
console.log(result);
21+
if(!overlayIsActive()){
22+
showNotification("HWI is ready again", 10000);
23+
// no need to proceed at all
24+
return null;
25+
}
26+
hidePageOverlay();
2427
}
25-
hidePageOverlay();
2628
2729
let el = document.getElementById("hwi_pin_container");
2830
let stars = document.getElementById("hwi_pin_stars");

src/cryptoadvance/specter/templates/includes/hwi/components/select_device.jinja

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
</div>
66

77
<script type="text/javascript">
8-
async function selectDevice(devices){
8+
async function selectDevice(devices, passphrase=null){
99
/**
1010
Spawns a window and asks user for a device.
1111
Retuns null if user closed the window.
@@ -42,9 +42,9 @@
4242
}
4343
}
4444
hidePageOverlay();
45-
let passphrase = null;
45+
4646
try{
47-
passphrase = await unlockDevice(selectedDevice);
47+
passphrase = await unlockDevice(selectedDevice, passphrase);
4848
}catch(error){
4949
handleHWIError(error);
5050
return null;
@@ -59,7 +59,8 @@
5959
console.log(selectedDevice);
6060
return selectedDevice;
6161
}
62-
async function unlockDevice(device){
62+
63+
async function unlockDevice(device, passphrase=null){
6364
if('needs_pin_sent' in device && device.needs_pin_sent){
6465
let result = await enterPin(device);
6566
if(result == null){
@@ -70,6 +71,9 @@
7071
}
7172
device.needs_pin_sent = false;
7273
}
74+
if(passphrase!=null){
75+
return passphrase;
76+
}
7377
if('needs_passphrase_sent' in device && device.needs_passphrase_sent){
7478
console.log("need password...");
7579
let passphrase = await enterPassphrase(device);

0 commit comments

Comments
 (0)