@ -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 . h box. 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 ) :
@ -169,12 +186,14 @@ 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> " ] ) )
dialog . show_message ( ' ' . join ( [ _ ( " {} encrypted for Revealer {} _ {} saved as PNG and PDF at: " ) . format ( self . was , self . version , self . code_id ) ,
" <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 . v box. addWidget ( logo )
h box. 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,9 +403,9 @@ class Plugin(BasePlugin):
else :
self . filename = self . wallet_name + ' _ ' + _ ( ' seed ' ) + ' _ '
self . was = self . wallet_name + ' ' + _ ( ' seed ' )
if self . extension :
self . ext_warning ( self . c_dialog )
if self . has_extension :
self . ext_warning ( self . c_dialog )
if not calibration :
self . toPdf ( QImage ( cypherseed ) )