From b14b5d3dd446fc949e9eddb48f8f7e2b26232179 Mon Sep 17 00:00:00 2001 From: Fredrick Brennan Date: Sun, 18 Oct 2015 15:42:11 +0800 Subject: [PATCH 1/3] Make seed uncopyable Other wallets, such as Mycelium, do not allow the user to simply copy and paste the seed. This is very useful to assure users follow directions on the next screen, because previously it was easily possible to just copy the seed and paste it on the next screen. The user's wallet would work well for a while like this, but without having the seed written down it's more of a ticking time bomb than a wallet. I recommend pulling this patch as I have read many cases where users do not write the seed down, and I believe that the main cause is lack of friction forcing them to do so. This patch was inspired by reading this Reddit conversation: https://www.reddit.com/r/Bitcoin/comments/3p4bq1/electrum_v25/cw380kg But I'm not a participant in that convo. --- gui/qt/qrtextedit.py | 23 ++++++++++++++++------- gui/qt/seed_dialog.py | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/gui/qt/qrtextedit.py b/gui/qt/qrtextedit.py index 4a90514f9..fd63ad075 100644 --- a/gui/qt/qrtextedit.py +++ b/gui/qt/qrtextedit.py @@ -8,10 +8,25 @@ from util import ButtonsTextEdit class ShowQRTextEdit(ButtonsTextEdit): - def __init__(self, text=None): + def __init__(self, text=None, paranoid=False): ButtonsTextEdit.__init__(self, text) self.setReadOnly(1) self.addButton(":icons/qrcode.png", self.qr_show, _("Show as QR code")) + + if paranoid: + # Paranoid flag forces the user to write down what's in the box, + # like Mycelium does. This is useful since many users just copy + # and paste their code, then when disaster strikes they don't have + # it written down anywhere. + self.setAcceptDrops(False) # No dragging and dropping + # Use custom context menu to remove copy/paste from menu + self.setContextMenuPolicy(Qt.ActionsContextMenu) + self.qaction = QAction(_("Show as QR code"), self) + self.qaction.triggered.connect(self.qr_show) + self.addAction(self.qaction) + # No text selection allowed. + self.setTextInteractionFlags(Qt.NoTextInteraction) + run_hook('show_text_edit', self) def qr_show(self): @@ -22,12 +37,6 @@ class ShowQRTextEdit(ButtonsTextEdit): s = unicode(self.toPlainText()) QRDialog(s).exec_() - def contextMenuEvent(self, e): - m = self.createStandardContextMenu() - m.addAction(_("Show as QR code"), self.qr_show) - m.exec_(e.globalPos()) - - class ScanQRTextEdit(ButtonsTextEdit): def __init__(self, text=""): diff --git a/gui/qt/seed_dialog.py b/gui/qt/seed_dialog.py index b9d5a5375..41fd68519 100644 --- a/gui/qt/seed_dialog.py +++ b/gui/qt/seed_dialog.py @@ -75,7 +75,7 @@ def enter_seed_box(msg, window, sid=None, text=None): seed_e = ScanQRTextEdit() seed_e.setTabChangesFocus(True) else: - seed_e = ShowQRTextEdit(text=text) + seed_e = ShowQRTextEdit(text=text, paranoid=True) seed_e.setMaximumHeight(130) vbox.addWidget(label) grid = QGridLayout() From 88ca99c624774ec8ef46ceef9b1bf36442fe4308 Mon Sep 17 00:00:00 2001 From: Fredrick Brennan Date: Sun, 18 Oct 2015 16:00:28 +0800 Subject: [PATCH 2/3] Fix context menu when paranoid=False --- gui/qt/qrtextedit.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gui/qt/qrtextedit.py b/gui/qt/qrtextedit.py index fd63ad075..392cd6850 100644 --- a/gui/qt/qrtextedit.py +++ b/gui/qt/qrtextedit.py @@ -12,6 +12,7 @@ class ShowQRTextEdit(ButtonsTextEdit): ButtonsTextEdit.__init__(self, text) self.setReadOnly(1) self.addButton(":icons/qrcode.png", self.qr_show, _("Show as QR code")) + self.paranoid = paranoid if paranoid: # Paranoid flag forces the user to write down what's in the box, @@ -37,6 +38,13 @@ class ShowQRTextEdit(ButtonsTextEdit): s = unicode(self.toPlainText()) QRDialog(s).exec_() + def contextMenuEvent(self, e): + if self.paranoid: return + m = self.createStandardContextMenu() + m.addAction(_("Show as QR code"), self.qr_show) + m.exec_(e.globalPos()) + + class ScanQRTextEdit(ButtonsTextEdit): def __init__(self, text=""): From 7685758360a50d5601597560a10ddfe56585ed93 Mon Sep 17 00:00:00 2001 From: Fredrick Brennan Date: Mon, 19 Oct 2015 13:27:15 +0800 Subject: [PATCH 3/3] Make it so uncopyable seed only affects wizard Previously it also affected the menu item Wallet->Seed, which is not the expected or desired behavior. --- gui/qt/installwizard.py | 2 +- gui/qt/seed_dialog.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py index 0118f651d..52ac93f3b 100644 --- a/gui/qt/installwizard.py +++ b/gui/qt/installwizard.py @@ -416,7 +416,7 @@ class InstallWizard(QDialog): return True def show_seed(self, seed, sid): - vbox = seed_dialog.show_seed_box_msg(seed, sid) + vbox = seed_dialog.show_seed_box_msg(seed, sid, paranoid=True) vbox.addLayout(Buttons(CancelButton(self), OkButton(self, _("Next")))) self.set_layout(vbox) return self.exec_() diff --git a/gui/qt/seed_dialog.py b/gui/qt/seed_dialog.py index 41fd68519..d97359edf 100644 --- a/gui/qt/seed_dialog.py +++ b/gui/qt/seed_dialog.py @@ -47,9 +47,9 @@ def icon_filename(sid): return ":icons/seed.png" -def show_seed_box_msg(seedphrase, sid=None): +def show_seed_box_msg(seedphrase, sid=None, paranoid=False): msg = _("Your wallet generation seed is") + ":" - vbox = show_seed_box(msg, seedphrase, sid) + vbox = show_seed_box(msg, seedphrase, sid, paranoid=paranoid) save_msg = _("Please save these %d words on paper (order is important).")%len(seedphrase.split()) + " " msg2 = save_msg + " " \ + _("This seed will allow you to recover your wallet in case of computer failure.") + "
" \ @@ -60,11 +60,11 @@ def show_seed_box_msg(seedphrase, sid=None): vbox.addStretch(1) return vbox -def show_seed_box(msg, seed, sid): - vbox, seed_e = enter_seed_box(msg, None, sid=sid, text=seed) +def show_seed_box(msg, seed, sid, paranoid=False): + vbox, seed_e = enter_seed_box(msg, None, sid=sid, text=seed, paranoid=paranoid) return vbox -def enter_seed_box(msg, window, sid=None, text=None): +def enter_seed_box(msg, window, sid=None, text=None, paranoid=False): vbox = QVBoxLayout() logo = QLabel() logo.setPixmap(QPixmap(icon_filename(sid)).scaledToWidth(56)) @@ -75,7 +75,7 @@ def enter_seed_box(msg, window, sid=None, text=None): seed_e = ScanQRTextEdit() seed_e.setTabChangesFocus(True) else: - seed_e = ShowQRTextEdit(text=text, paranoid=True) + seed_e = ShowQRTextEdit(text=text, paranoid=paranoid) seed_e.setMaximumHeight(130) vbox.addWidget(label) grid = QGridLayout()