Skip to content

Commit 78112d5

Browse files
author
8go
committed
port to PyQt5, runs on Py2.7 and 3.4+, more modular
1 parent 6aaffb4 commit 78112d5

18 files changed

+2098
-1307
lines changed

Makefile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
UI_GENERATED := \
2+
ui_trezor_chooser_dialog.py \
3+
ui_trezor_pin_dialog.py \
24
ui_trezor_passphrase_dialog.py \
35
ui_dialog.py \
4-
ui_enter_pin_dialog.py \
5-
ui_trezor_chooser_dialog.py \
66
#end of UI_GENERATED
77

88
all: $(UI_GENERATED)
99

1010
ui_%.py: %.ui
11-
pyuic4 -o $@ $<
11+
pyuic5 -o $@ $<
1212

1313
clean:
14-
rm -rf $(UI_GENERATED)
14+
rm -f $(UI_GENERATED)
15+
rm -rf __pycache__
16+
rm -f *.pyc

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
`TrezorSymmetricFileEncryption` is a small, simple tool that
1010
allows you to symmetrically encrypt and decrypt files.
1111

12-
Note that it is software, currently in alpha stage.
13-
1412
# Features
1513

1614
* Trezor convenience

TrezorSymmetricFileEncryption.py

Lines changed: 75 additions & 230 deletions
Original file line numberDiff line numberDiff line change
@@ -16,190 +16,27 @@
1616

1717
import sys
1818
import 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

3224
import basics
25+
import settings
3326
import 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("\nKeyboard 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("\nKeyboard 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

Comments
 (0)