Browse Source

Merge pull request #4916 from tiagotrs/master

revealer: new interface
closes #4540 
closes #4676
3.3.3.1
ghost43 6 years ago
committed by GitHub
parent
commit
5fd83722d8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      electrum/gui/qt/seed_dialog.py
  2. 8
      electrum/plugins/revealer/__init__.py
  3. 184
      electrum/plugins/revealer/qt.py

4
electrum/gui/qt/seed_dialog.py

@ -26,8 +26,6 @@
from electrum.i18n import _
from electrum.mnemonic import Mnemonic
import electrum.old_mnemonic
from electrum.plugin import run_hook
from .util import *
from .qrtextedit import ShowQRTextEdit, ScanQRTextEdit
@ -207,6 +205,4 @@ class SeedDialog(WindowModalDialog):
title = _("Your wallet generation seed is:")
slayout = SeedLayout(title=title, seed=seed, msg=True, passphrase=passphrase)
vbox.addLayout(slayout)
has_extension = True if passphrase else False
run_hook('set_seed', seed, has_extension, slayout.seed_e)
vbox.addLayout(Buttons(CloseButton(self)))

8
electrum/plugins/revealer/__init__.py

@ -1,13 +1,9 @@
from electrum.i18n import _
fullname = _('Revealer')
fullname = _('Revealer Backup Utility')
description = ''.join(["<br/>",
"<b>"+_("Do you have something to hide ?")+"</b>", '<br/>', '<br/>',
_("Revealer is a seed phrase back-up solution. It allows you to create a cold, analog, multi-factor backup of your wallet seeds, or of any arbitrary secret."), '<br/>', '<br/>',
_("Using a Revealer is better than writing your seed phrases on paper: a revealer is invulnerable to physical access and allows creation of trustless redundancy."), '<br/>', '<br/>',
_("This plug-in allows you to generate a pdf file of your secret phrase encrypted visually for your physical Revealer. You can print it trustlessly - it can only be decrypted optically with your Revealer."), '<br/>', '<br/>',
_("The plug-in also allows you to generate a digital Revealer file and print it yourself on a transparent overhead foil."), '<br/>', '<br/>',
_("Once activated you can access the plug-in through the icon at the seed dialog."), '<br/>', '<br/>',
_("This plug-in allows you to create a visually encrypted backup of your wallet seeds, or of custom alphanumeric secrets."), '<br/>', '<br/>',
_("For more information, visit"),
" <a href=\"https://revealer.cc\">https://revealer.cc</a>", '<br/>', '<br/>',
])

184
electrum/plugins/revealer/qt.py

@ -1,19 +1,12 @@
'''
Revealer
So you have something to hide?
plug-in for the electrum wallet.
Features:
- Deep Cold multi-factor backup solution
- Safety - One time pad security
- Redundancy - Trustless printing & distribution
- Encrypt your seedphrase or any secret you want for your revealer
- Based on crypto by legendary cryptographers Naor and Shamir
Do you have something to hide?
Secret backup plug-in for the electrum wallet.
Tiago Romagnani Silveira, 2017
'''
import os
@ -28,14 +21,17 @@ from PyQt5.QtPrintSupport import QPrinter
from electrum.plugin import BasePlugin, hook
from electrum.i18n import _
from electrum.util import to_bytes, make_dir
from electrum.util import to_bytes, make_dir, InvalidPassword, UserCancelled
from electrum.gui.qt.util import *
from electrum.gui.qt.qrtextedit import ScanQRTextEdit
from electrum.gui.qt.main_window import StatusBarButton
from .hmac_drbg import DRBG
class Plugin(BasePlugin):
MAX_PLAINTEXT_LEN = 189 # chars
def __init__(self, parent, config, name):
BasePlugin.__init__(self, parent, config, name)
self.base_dir = config.electrum_path()+'/revealer/'
@ -57,11 +53,13 @@ class Plugin(BasePlugin):
self.rawnoise = False
make_dir(self.base_dir)
self.extension = False
@hook
def set_seed(self, seed, has_extension, parent):
self.cseed = seed.upper()
self.has_extension = has_extension
parent.addButton(':icons/revealer.png', partial(self.setup_dialog, parent), "Revealer"+_(" secret backup utility"))
def create_status_bar(self, parent):
b = StatusBarButton(QIcon(':icons/revealer.png'), "Revealer "+_("secret backup utility"),
partial(self.setup_dialog, parent))
parent.addPermanentWidget(b)
def requires_settings(self):
return True
@ -69,39 +67,67 @@ class Plugin(BasePlugin):
def settings_widget(self, window):
return EnterButton(_('Printer Calibration'), partial(self.calibration_dialog, window))
def password_dialog(self, msg=None, parent=None):
from electrum.gui.qt.password_dialog import PasswordDialog
parent = parent or self
d = PasswordDialog(parent, msg)
return d.run()
def get_seed(self):
password = None
if self.wallet.has_keystore_encryption():
password = self.password_dialog(parent=self.d.parent())
if not password:
raise UserCancelled()
keystore = self.wallet.get_keystore()
if not keystore or not keystore.has_seed():
return
self.extension = bool(keystore.get_passphrase(password))
return keystore.get_seed(password)
def setup_dialog(self, window):
self.update_wallet_name(window.parent().parent().wallet)
self.wallet = window.parent().wallet
self.update_wallet_name(self.wallet)
self.user_input = False
self.noise_seed = False
self.d = WindowModalDialog(window, "Revealer")
self.d.setMinimumWidth(420)
vbox = QVBoxLayout(self.d)
vbox.addSpacing(21)
self.d = WindowModalDialog(window, "Setup Dialog")
self.d.setMinimumWidth(500)
self.d.setMinimumHeight(210)
self.d.setMaximumHeight(320)
self.d.setContentsMargins(11,11,1,1)
self.hbox = QHBoxLayout(self.d)
vbox = QVBoxLayout()
logo = QLabel()
vbox.addWidget(logo)
self.hbox.addWidget(logo)
logo.setPixmap(QPixmap(':icons/revealer.png'))
logo.setAlignment(Qt.AlignCenter)
vbox.addSpacing(42)
logo.setAlignment(Qt.AlignLeft)
self.hbox.addSpacing(16)
vbox.addWidget(WWLabel("<b>"+_("Revealer Secret Backup Plugin")+"</b><br>"
+_("To encrypt your backup, first we need to load some noise.")+"<br/>"))
vbox.addSpacing(7)
bcreate = QPushButton(_("Create a new Revealer"))
bcreate.setMaximumWidth(181)
bcreate.setDefault(True)
vbox.addWidget(bcreate, Qt.AlignCenter)
self.load_noise = ScanQRTextEdit()
self.load_noise.setTabChangesFocus(True)
self.load_noise.textChanged.connect(self.on_edit)
self.load_noise.setMaximumHeight(33)
vbox.addWidget(WWLabel("<b>"+_("Enter your physical revealer code:")+"<b>"))
self.hbox.addLayout(vbox)
vbox.addWidget(WWLabel(_("or type a existing revealer code below and click 'next':")))
vbox.addWidget(self.load_noise)
vbox.addSpacing(11)
vbox.addSpacing(3)
self.next_button = QPushButton(_("Next"), self.d)
self.next_button.setDefault(True)
self.next_button.setEnabled(False)
vbox.addLayout(Buttons(self.next_button))
self.next_button.clicked.connect(self.d.close)
self.next_button.clicked.connect(partial(self.cypherseed_dialog, window))
vbox.addSpacing(21)
vbox.addWidget(WWLabel(_("or, alternatively: ")))
bcreate = QPushButton(_("Create a digital Revealer"))
vbox.addWidget(
QLabel("<b>" + _("Warning") + "</b>: " + _("Each revealer should be used only once.")
+"<br>"+_("more information at <a href=\"https://revealer.cc/faq\">https://revealer.cc/faq</a>")))
def mk_digital():
try:
@ -112,15 +138,6 @@ class Plugin(BasePlugin):
self.cypherseed_dialog(window)
bcreate.clicked.connect(mk_digital)
vbox.addWidget(bcreate)
vbox.addSpacing(11)
vbox.addWidget(QLabel(''.join([ "<b>"+_("WARNING")+ "</b>:" + _("Printing a revealer and encrypted seed"), '<br/>',
_("on the same printer is not trustless towards the printer."), '<br/>',
])))
vbox.addSpacing(11)
vbox.addLayout(Buttons(CloseButton(self.d)))
return bool(self.d.exec_())
def get_noise(self):
@ -170,11 +187,13 @@ class Plugin(BasePlugin):
def bcrypt(self, dialog):
self.rawnoise = False
dialog.show_message(''.join([_("{} encrypted for Revealer {}_{} saved as PNG and PDF at: ").format(self.was, self.version, self.code_id),
"<br/>","<b>", self.base_dir+ self.filename+self.version+"_"+self.code_id,"</b>"]))
"<b>", self.base_dir+ self.filename+self.version+"_"+self.code_id,"</b>", "<br/>",
"<br/>", "<b>", _("Always check you backups.") ]))
dialog.close()
def ext_warning(self, dialog):
dialog.show_message(''.join(["<b>",_("Warning: "), "</b>", _("your seed extension will not be included in the encrypted backup.")]))
dialog.show_message(''.join(["<b>",_("Warning"), ": </b>",
_("your seed extension will <b>not</b> be included in the encrypted backup.")]))
dialog.close()
def bdone(self, dialog):
@ -185,11 +204,11 @@ class Plugin(BasePlugin):
def customtxt_limits(self):
txt = self.text.text()
self.max_chars.setVisible(False)
self.char_count.setText("("+str(len(txt))+"/216)")
self.char_count.setText(f"({len(txt)}/{self.MAX_PLAINTEXT_LEN})")
if len(txt)>0:
self.ctext.setEnabled(True)
if len(txt) > 216:
self.text.setPlainText(self.text.toPlainText()[:216])
if len(txt) > self.MAX_PLAINTEXT_LEN:
self.text.setPlainText(txt[:self.MAX_PLAINTEXT_LEN])
self.max_chars.setVisible(True)
def t(self):
@ -198,57 +217,51 @@ class Plugin(BasePlugin):
def cypherseed_dialog(self, window):
d = WindowModalDialog(window, "Revealer")
d.setMinimumWidth(420)
d = WindowModalDialog(window, "Encryption Dialog")
d.setMinimumWidth(500)
d.setMinimumHeight(210)
d.setMaximumHeight(450)
d.setContentsMargins(11, 11, 1, 1)
self.c_dialog = d
self.vbox = QVBoxLayout(d)
self.vbox.addSpacing(21)
hbox = QHBoxLayout(d)
self.vbox = QVBoxLayout()
logo = QLabel()
self.vbox.addWidget(logo)
hbox.addWidget(logo)
logo.setPixmap(QPixmap(':icons/revealer.png'))
logo.setAlignment(Qt.AlignCenter)
self.vbox.addSpacing(42)
logo.setAlignment(Qt.AlignLeft)
hbox.addSpacing(16)
self.vbox.addWidget(WWLabel("<b>" + _("Revealer Secret Backup Plugin") + "</b><br>"
+ _("Ready to encrypt for revealer {}").format(self.version+'_'+self.code_id )))
self.vbox.addSpacing(11)
hbox.addLayout(self.vbox)
grid = QGridLayout()
self.vbox.addLayout(grid)
cprint = QPushButton(_("Generate encrypted seed backup"))
cprint = QPushButton(_("Encrypt {}'s seed").format(self.wallet_name))
cprint.setMaximumWidth(250)
cprint.clicked.connect(partial(self.seed_img, True))
self.vbox.addWidget(cprint)
self.vbox.addSpacing(14)
self.vbox.addWidget(WWLabel(_("OR type any secret below:")))
self.vbox.addSpacing(1)
self.vbox.addWidget(WWLabel("<b>"+_("OR")+"</b> "+_("type a custom alphanumerical secret below:")))
self.text = ScanQRTextEdit()
self.text.setTabChangesFocus(True)
self.text.setMaximumHeight(70)
self.text.textChanged.connect(self.customtxt_limits)
self.vbox.addWidget(self.text)
self.char_count = WWLabel("")
self.char_count.setAlignment(Qt.AlignRight)
self.vbox.addWidget(self.char_count)
self.max_chars = WWLabel("<font color='red'>" + _("This version supports a maximum of 216 characters.")+"</font>")
self.max_chars = WWLabel("<font color='red'>"
+ _("This version supports a maximum of {} characters.").format(self.MAX_PLAINTEXT_LEN)
+"</font>")
self.vbox.addWidget(self.max_chars)
self.max_chars.setVisible(False)
self.ctext = QPushButton(_("Generate custom secret encrypted backup"))
self.ctext = QPushButton(_("Encrypt custom secret"))
self.ctext.clicked.connect(self.t)
self.vbox.addWidget(self.ctext)
self.ctext.setEnabled(False)
self.vbox.addSpacing(11)
self.vbox.addWidget(
QLabel(''.join(["<b>" + _("WARNING") + "</b>: " + _("Revealer is a one-time-pad and should be used only once."), '<br/>',
_("Multiple secrets encrypted for the same Revealer can be attacked."), '<br/>',
])))
self.vbox.addSpacing(11)
self.vbox.addSpacing(21)
self.vbox.addLayout(Buttons(CloseButton(d)))
return bool(d.exec_())
@ -259,11 +272,18 @@ class Plugin(BasePlugin):
def seed_img(self, is_seed = True):
if not self.cseed and self.txt == False:
return
if is_seed:
txt = self.cseed
try:
cseed = self.get_seed()
except UserCancelled:
return
except InvalidPassword as e:
self.d.show_error(str(e))
return
if not cseed:
self.d.show_message(_("This wallet has no seed"))
return
txt = cseed.upper()
else:
txt = self.txt.upper()
@ -282,7 +302,7 @@ class Plugin(BasePlugin):
else:
fontsize = 12
linespace = 10
max_letters = 23
max_letters = 21
max_lines = 9
max_words = int(max_letters/4)
@ -383,10 +403,10 @@ class Plugin(BasePlugin):
else:
self.filename = self.wallet_name+'_'+ _('seed')+'_'
self.was = self.wallet_name +' ' + _('seed')
if self.has_extension:
if self.extension:
self.ext_warning(self.c_dialog)
if not calibration:
self.toPdf(QImage(cypherseed))
QDesktopServices.openUrl (QUrl.fromLocalFile(os.path.abspath(self.base_dir+self.filename+self.version+'_'+self.code_id+'.pdf')))

Loading…
Cancel
Save