Repository: spesmilo/electrum

Issue:
btchip: exception 'wrong pin' not shown to user
Trying to reset my btchip I noticed the following exception:

```
Traceback (most recent call last):
  File "/mnt/maui/home/nick/bitcoin/electrum/lib/plugins.py", line 51, in run_hook
    r = f(*args)
  File "/mnt/maui/home/nick/bitcoin/electrum/plugins/labels.py", line 66, in load_wallet
    mpk = self.wallet.get_master_public_key()
  File "/mnt/maui/home/nick/bitcoin/electrum/plugins/btchipwallet.py", line 249, in get_master_public_key
    self.mpk = self.get_public_key("44'/0'")
  File "/mnt/maui/home/nick/bitcoin/electrum/plugins/btchipwallet.py", line 219, in get_public_key
    self.get_client() # prompt for the PIN before displaying the dialog if necessary
  File "/mnt/maui/home/nick/bitcoin/electrum/plugins/btchipwallet.py", line 187, in get_client
    raise Exception("Invalid PIN - please unplug the dongle and plug it again before retrying")
Exception: Invalid PIN - please unplug the dongle and plug it again before retrying
```

nothing is shown to the user. It seems from user perspective (not looking at terminal output) the PIN was entered correctly (wallet loads).



Discussion:
What's the exact scenario for this ?

To reproduce (I just did this to make sure)
- replug the device
- start electrum, open a btchip-based wallet (I used --wallet switch on cmdline)
- electrum prompts for PIN, enter wrong PIN
- => observe no popup or any other feedback that the PIN was wrong, only the 'Invalid PIN' exception on console which is not helpful to a normal user

For some reason, electrum doesn't prompt me for a PIN when I do that. I get prompted when I want to sign a transaction or a message, but then get the correct error message.

Try replugging the device before opening electrum (or before opening the wallet).

If you don't do that, often this error occures instead of prompting for PIN:

```
Traceback (most recent call last):
  File "/mnt/maui/home/nick/bitcoin/electrum/lib/plugins.py", line 51, in run_hook
    r = f(*args)
  File "/mnt/maui/home/nick/bitcoin/electrum/plugins/labels.py", line 66, in load_wallet
    mpk = self.wallet.get_master_public_key()
  File "/mnt/maui/home/nick/bitcoin/electrum/plugins/btchipwallet.py", line 255, in get_master_public_key
    self.mpk = self.get_public_key("44'/0'")
  File "/mnt/maui/home/nick/bitcoin/electrum/plugins/btchipwallet.py", line 225, in get_public_key
    self.get_client() # prompt for the PIN before displaying the dialog if necessary
  File "/mnt/maui/home/nick/bitcoin/electrum/plugins/btchipwallet.py", line 202, in get_client
    raise Exception("Could not connect to your BTChip dongle. Please verify access permissions, PIN, or unplug the dongle and plug it again")
Exception: Could not connect to your BTChip dongle. Please verify access permissions, PIN, or unplug the dongle and plug it again
```

Maybe this is what happens in your case?

Note that this error differs from the initially reported one, which occurs when entering the wrong PIN

I'll update reproduction recipe in previous post (adding first step: 'replug')

Just had an idea: maybe you need to enable the labels plugin for this to occur? Notice labels.py in the stacktrace.

EDIT: yes, I think that's it. I disabled labels plugin and now I'm not even prompted for PIN when opening btchip wallet.


Resolving patch:
diff --git a/plugins/btchipwallet.py b/plugins/btchipwallet.py
--- a/plugins/btchipwallet.py
+++ b/plugins/btchipwallet.py
@@ -113,8 +113,9 @@ def give_error(self, message, clear_client = False):
             QMessageBox.warning(QDialog(), _('Warning'), _(message), _('OK'))
         else:
             self.signing = False
-        if clear_client:
+        if clear_client and self.client is not None:
             self.client.bad = True
+            self.device_checked = False
         raise Exception(message)                
 
     def get_action(self):
@@ -251,9 +252,15 @@ def get_public_key(self, bip32_path):
         return EncodeBase58Check(xpub)
 
     def get_master_public_key(self):
-        if not self.mpk:
-            self.mpk = self.get_public_key("44'/0'")
-        return self.mpk
+        try:
+            if not self.mpk:
+                self.get_client() # prompt for the PIN if necessary
+                if not self.check_proper_device():
+                    self.give_error('Wrong device or password')        
+                self.mpk = self.get_public_key("44'/0'")
+            return self.mpk
+        except Exception, e:
+            self.give_error(e, True)        
 
     def i4b(self, x):
         return pack('>I', x)
@@ -283,6 +290,7 @@ def sign_message(self, address, message, password):
                     raise Exception('Aborted by user')
                 pin = pin.encode()
                 self.client.bad = True
+                self.device_checked = False
                 self.get_client(True)
             signature = self.get_client().signMessageSign(pin)
         except Exception, e:
@@ -381,6 +389,7 @@ def sign_transaction(self, tx, keypairs, password):
                         raise Exception('Aborted by user')
                     pin = pin.encode()
                     self.client.bad = True
+                    self.device_checked = False
                     self.get_client(True)
                     waitDialog.start("Signing ...")
                 else:


Test patch: