1616
1717import sys
1818import logging
19- import getpass
2019
21- from PyQt4 import QtGui
20+ from PyQt5 . QtWidgets import QApplication # for the clipboard and window
2221
23- from trezorlib .client import BaseClient , ProtocolMixin # CallException, PinException
24- from trezorlib .transport import ConnectionError
25- from trezorlib .transport_hid import HidTransport
26- from trezorlib import messages_pb2 as proto
27-
28- import file_map
29-
30- from dialogs import TrezorPassphraseDialog , Dialog , EnterPinDialog , TrezorChooserDialog
22+ from dialogs import Dialog
3123
3224import basics
25+ import settings
3326import processing
27+ from trezor_app_specific import FileMap
28+ import trezor_app_generic
3429
30+ """
31+ The file with the main function.
3532
36- class QtTrezorMixin (object ):
37- """
38- Mixin for input of Trezor PIN and passhprases.
39- Works via both, terminal as well as PyQt GUI
40- """
41-
42- def __init__ (self , * args , ** kwargs ):
43- super (QtTrezorMixin , self ).__init__ (* args , ** kwargs )
44- self .passphrase = None
45- self .readpinfromstdin = None
46- self .readpassphrasefromstdin = None
47-
48- def callback_ButtonRequest (self , msg ):
49- return proto .ButtonAck ()
50-
51- def callback_PassphraseRequest (self , msg ):
52- if self .passphrase is not None :
53- return proto .PassphraseAck (passphrase = str (self .passphrase ))
54-
55- if self .readpassphrasefromstdin :
56- # read passphrase from stdin
57- try :
58- passphrase = getpass .getpass ("Please enter passphrase: " )
59- passphrase = str (passphrase )
60- except KeyboardInterrupt :
61- sys .stderr .write ("\n Keyboard interrupt: passphrase not read. Aborting.\n " )
62- sys .exit (3 )
63- except Exception as e :
64- sys .stderr .write ("Critical error: Passphrase not read. Aborting. (%s)" % e )
65- sys .exit (3 )
66- else :
67- dialog = TrezorPassphraseDialog ()
68- if not dialog .exec_ ():
69- sys .exit (3 )
70- else :
71- passphrase = dialog .passphraseEdit .text ()
72- passphrase = str (passphrase )
73-
74- return proto .PassphraseAck (passphrase = passphrase )
75-
76- def callback_PinMatrixRequest (self , msg ):
77- if self .readpinfromstdin :
78- # read PIN from stdin
79- print (" 7 8 9" )
80- print (" 4 5 6" )
81- print (" 1 2 3" )
82- try :
83- pin = getpass .getpass ("Please enter PIN: " )
84- except KeyboardInterrupt :
85- sys .stderr .write ("\n Keyboard interrupt: PIN not read. Aborting.\n " )
86- sys .exit (7 )
87- except Exception as e :
88- sys .stderr .write ("Critical error: PIN not read. Aborting. (%s)" % e )
89- sys .exit (7 )
90- else :
91- dialog = EnterPinDialog ()
92- if not dialog .exec_ ():
93- sys .exit (7 )
94- pin = dialog .pin ()
95-
96- return proto .PinMatrixAck (pin = pin )
97-
98- def prefillPassphrase (self , passphrase ):
99- """
100- Instead of asking for passphrase, use this one
101- """
102- if passphrase is not None :
103- self .passphrase = passphrase .decode ("utf-8" )
104- else :
105- self .passphrase = None
33+ Code should work on both Python 2.7 as well as 3.4.
34+ Requires PyQt5.
35+ (Old version supported PyQt4.)
36+ """
10637
107- def prefillReadpinfromstdin (self , readpinfromstdin = False ):
108- """
109- Specify if PIN should be read from stdin instead of from GUI
110- @param readpinfromstdin: True to force it to read from stdin, False otherwise
111- @type readpinfromstdin: C{bool}
112- """
113- self .readpinfromstdin = readpinfromstdin
11438
115- def prefillReadpassphrasefromstdin (self , readpassphrasefromstdin = False ):
116- """
117- Specify if passphrase should be read from stdin instead of from GUI
118- @param readpassphrasefromstdin: True to force it to read from stdin, False otherwise
119- @type readpassphrasefromstdin: C{bool}
120- """
121- self .readpassphrasefromstdin = readpassphrasefromstdin
122-
123-
124- class QtTrezorClient (ProtocolMixin , QtTrezorMixin , BaseClient ):
125- """
126- Trezor client with Qt input methods
127- """
128- pass
129-
130-
131- class TrezorChooser (object ):
132- """Class for working with Trezor device via HID"""
133-
134- def __init__ (self ):
135- pass
136-
137- def getDevice (self ):
138- """
139- Get one from available devices. Widget will be shown if more
140- devices are available.
141- """
142- devices = self .enumerateHIDDevices ()
143-
144- if not devices :
145- return None
146-
147- transport = self .chooseDevice (devices )
148- client = QtTrezorClient (transport )
149-
150- return client
151-
152- def enumerateHIDDevices (self ):
153- """Returns Trezor HID devices"""
154- devices = HidTransport .enumerate ()
155-
156- return devices
157-
158- def chooseDevice (self , devices ):
159- """
160- Choose device from enumerated list. If there's only one Trezor,
161- that will be chosen.
162-
163- If there are multiple Trezors, diplays a widget with list
164- of Trezor devices to choose from.
165-
166- @returns HidTransport object of selected device
167- """
168- if not len (devices ):
169- raise RuntimeError ("No Trezor connected!" )
170-
171- if len (devices ) == 1 :
172- try :
173- return HidTransport (devices [0 ])
174- except IOError :
175- raise RuntimeError ("Trezor is currently in use" )
176-
177- # maps deviceId string to device label
178- deviceMap = {}
179- for device in devices :
180- try :
181- transport = HidTransport (device )
182- client = QtTrezorClient (transport )
183- label = client .features .label and client .features .label or "<no label>"
184- client .close ()
185-
186- deviceMap [device [0 ]] = label
187- except IOError :
188- # device in use, do not offer as choice
189- continue
190-
191- if not deviceMap :
192- raise RuntimeError ("All connected Trezors are in use!" )
193-
194- dialog = TrezorChooserDialog (deviceMap )
195- if not dialog .exec_ ():
196- sys .exit (9 )
197-
198- deviceStr = dialog .chosenDeviceStr ()
199- return HidTransport ([deviceStr , None ])
200-
201-
202- def showGui (trezor , settings , fileMap , logger ):
39+ def showGui (trezor , dialog , settings ):
20340 """
20441 Initialize, ask for encrypt/decrypt options,
20542 ask for files to be decrypted/encrypted,
@@ -212,66 +49,74 @@ def showGui(trezor, settings, fileMap, logger):
21249 @param settings: Settings object to store command line arguments or
21350 items selected in GUI
21451 """
215- dialog = Dialog (trezor , settings , fileMap , logger )
216- settings .settings2Gui (dialog , trezor )
217- processing .reportLogging ("Trezor label: %s" % trezor .features .label , logging .INFO ,
218- "Trezor IO" , settings , logger , dialog )
52+ settings .settings2Gui (dialog )
21953 if not dialog .exec_ ():
220- processing .reportLogging ("Shutting down due to user request "
221- "(Done/Quit was called)." , logging .DEBUG ,
222- "GUI IO" , settings , logger , None )
223- sys .exit (4 ) # Esc or exception
224- settings .gui2Settings (dialog , trezor )
225-
226-
227- # root
228-
229- logging .basicConfig (stream = sys .stderr , level = basics .LOGGINGLEVEL )
230- logger = logging .getLogger ('tsfe' )
231-
232- app = QtGui .QApplication (sys .argv )
54+ # Esc or exception or Quit/Close/Done
55+ settings .mlogger .log ("Shutting down due to user request "
56+ "(Done/Quit was called)." , logging .DEBUG , "GUI IO" )
57+ # sys.exit(4)
58+ settings .gui2Settings (dialog )
23359
234- settings = processing .Settings (logger ) # initialize settings
235- # parse command line
236- processing .parseArgs (sys .argv [1 :], settings , logger )
23760
238- try :
239- trezorChooser = TrezorChooser ()
240- trezor = trezorChooser .getDevice ()
241- except (ConnectionError , RuntimeError ) as e :
242- processing .reportLogging ("Connection to Trezor failed: %s" % e .message ,
243- logging .CRITICAL , "Trezor Error" , settings , logger )
244- sys .exit (1 )
245-
246- if trezor is None :
247- processing .reportLogging ("No available Trezor found, quitting." ,
248- logging .CRITICAL , "Trezor Error" , settings , logger )
249- sys .exit (1 )
250-
251- trezor .clear_session ()
252- trezor .prefillReadpinfromstdin (settings .RArg )
253- trezor .prefillReadpassphrasefromstdin (settings .AArg )
254- trezor .prefillPassphrase (settings .PArg )
255-
256- fileMap = file_map .FileMap (trezor , logger )
257-
258- # if everything is specified in the command line then do not call the GUI
259- if ((settings .PArg is None ) or (len (settings .inputFiles ) <= 0 )) and (not settings .TArg ):
260- # something was not specified, so we call the GUI
261- showGui (trezor , settings , fileMap , logger )
262- else :
263- processing .reportLogging ("Trezor label: %s" % trezor .features .label , logging .INFO ,
264- "Trezor IO" , settings , logger , None )
265- processing .reportLogging ("Everything was specified or --terminal was set, "
266- "hence the GUI will not be called." , logging .INFO ,
267- "Trezor IO" , settings , logger , None )
61+ def useTerminal (fileMap , settings ):
26862 if settings .WArg :
269- processing . reportLogging ("The option `--wipe` is set. In case of "
63+ settings . mlogger . log ("The option `--wipe` is set. In case of "
27064 "encryption, the original plaintext files will "
27165 "be shredded after encryption. In case of decryption, "
27266 "the encrypted files will be shredded after decryption. "
27367 "Abort if you are uncertain or don't understand." , logging .WARNING ,
274- "Dangerous arguments" , settings , logger , None )
275-
276- processing .processAll (trezor , settings , fileMap , logger , dialog = None )
277- sys .exit (0 )
68+ "Dangerous arguments" )
69+ processing .processAll (fileMap , settings , dialog = None )
70+
71+
72+ def main ():
73+ app = QApplication (sys .argv )
74+ if app is None : # just to get rid f the linter warning on above line
75+ print ("Critical error: Qt cannot be initialized." )
76+ sets = settings .Settings () # initialize settings
77+ # parse command line
78+ args = settings .Args (sets )
79+ args .parseArgs (sys .argv [1 :])
80+
81+ trezor = trezor_app_generic .setupTrezor (sets .TArg , sets .mlogger )
82+ # trezor.clear_session() ## not needed
83+ trezor .prefillReadpinfromstdin (sets .RArg )
84+ trezor .prefillReadpassphrasefromstdin (sets .AArg )
85+ if sets .PArg is None :
86+ trezor .prefillPassphrase (u'' )
87+ else :
88+ trezor .prefillPassphrase (sets .PArg )
89+
90+ # if everything is specified in the command line then do not call the GUI
91+ if ((sets .PArg is None ) or (len (sets .inputFiles ) <= 0 )) and (not sets .TArg ):
92+ dialog = Dialog (trezor , sets )
93+ sets .mlogger .setQtextbrowser (dialog .textBrowser )
94+ sets .mlogger .setQtextheader (dialog .descrHeader ())
95+ sets .mlogger .setQtextcontent (dialog .descrContent ())
96+ sets .mlogger .setQtexttrailer (dialog .descrTrailer ())
97+ else :
98+ sets .mlogger .log ("Everything was specified or --terminal was set, "
99+ "hence the GUI will not be called." , logging .INFO , u"Arguments" )
100+
101+ sets .mlogger .log ("Trezor label: %s" % trezor .features .label ,
102+ logging .INFO , "Trezor IO" )
103+ sets .mlogger .log ("For each operation click 'Confirm' on Trezor "
104+ "to give permission." , logging .INFO , "Trezor IO" )
105+
106+ fileMap = FileMap (trezor , sets )
107+
108+ if ((sets .PArg is None ) or (len (sets .inputFiles ) <= 0 )) and (not sets .TArg ):
109+ # something was not specified, so we call the GUI
110+ # or user wants GUI, so we call the GUI
111+ dialog .setFileMap (fileMap )
112+ dialog .setVersion (basics .VERSION_STR )
113+ showGui (trezor , dialog , sets )
114+ else :
115+ useTerminal (fileMap , sets )
116+ # cleanup
117+ sets .mlogger .log ("Cleaning up before shutting down." , logging .DEBUG , "Info" )
118+ trezor .close ()
119+
120+
121+ if __name__ == '__main__' :
122+ main ()
0 commit comments