49
51
if sys.version_info.major == 2:
54
# Show warnings by default
55
if not sys.warnoptions:
56
warnings.simplefilter("default")
58
log = logging.getLogger(os.path.basename(sys.argv[0]))
59
logging.basicConfig(level="NOTSET", # Show all messages
60
format="%(message)s") # Show basic log messages
62
logging.captureWarnings(True) # Show warnings via the logging system
64
locale.setlocale(locale.LC_ALL, "")
66
logging.getLogger("dbus.proxies").setLevel(logging.CRITICAL)
67
logging.getLogger("urwid").setLevel(logging.INFO)
54
locale.setlocale(locale.LC_ALL, '')
56
logging.getLogger('dbus.proxies').setLevel(logging.CRITICAL)
69
58
# Some useful constants
70
domain = "se.recompile"
71
server_interface = domain + ".Mandos"
72
client_interface = domain + ".Mandos.Client"
59
domain = 'se.recompile'
60
server_interface = domain + '.Mandos'
61
client_interface = domain + '.Mandos.Client'
76
65
dbus.OBJECT_MANAGER_IFACE
128
117
self.property_changed_match.remove()
131
class MandosClientWidget(MandosClientPropertyCache, urwid.Widget):
120
class MandosClientWidget(urwid.FlowWidget, MandosClientPropertyCache):
132
121
"""A Mandos Client which is visible on the screen.
135
_sizing = frozenset(["flow"])
137
124
def __init__(self, server_proxy_object=None, update_hook=None,
138
delete_hook=None, **kwargs):
125
delete_hook=None, logger=None, **kwargs):
139
126
# Called on update
140
127
self.update_hook = update_hook
141
128
# Called on delete
142
129
self.delete_hook = delete_hook
143
130
# Mandos Server proxy object
144
131
self.server_proxy_object = server_proxy_object
146
135
self._update_timer_callback_tag = None
183
173
if flag and self._update_timer_callback_tag is None:
184
174
# Will update the shown timer value every second
185
self._update_timer_callback_tag = (
186
GLib.timeout_add(1000,
187
glib_safely(self.update_timer)))
175
self._update_timer_callback_tag = (GLib.timeout_add
188
178
elif not (flag or self._update_timer_callback_tag is None):
189
179
GLib.source_remove(self._update_timer_callback_tag)
190
180
self._update_timer_callback_tag = None
192
182
def checker_completed(self, exitstatus, condition, command):
193
183
if exitstatus == 0:
194
log.debug('Checker for client %s (command "%s")'
195
" succeeded", self.properties["Name"], command)
184
self.logger('Checker for client {} (command "{}")'
185
' succeeded'.format(self.properties["Name"],
199
190
if os.WIFEXITED(condition):
200
log.info('Checker for client %s (command "%s") failed'
201
" with exit code %d", self.properties["Name"],
202
command, os.WEXITSTATUS(condition))
191
self.logger('Checker for client {} (command "{}") failed'
193
.format(self.properties["Name"], command,
194
os.WEXITSTATUS(condition)))
203
195
elif os.WIFSIGNALED(condition):
204
log.info('Checker for client %s (command "%s") was'
205
" killed by signal %d", self.properties["Name"],
206
command, os.WTERMSIG(condition))
196
self.logger('Checker for client {} (command "{}") was'
197
' killed by signal {}'
198
.format(self.properties["Name"], command,
199
os.WTERMSIG(condition)))
209
202
def checker_started(self, command):
210
203
"""Server signals that a checker started."""
211
log.debug('Client %s started checker "%s"',
212
self.properties["Name"], command)
204
self.logger('Client {} started checker "{}"'
205
.format(self.properties["Name"],
214
208
def got_secret(self):
215
log.info("Client %s received its secret",
216
self.properties["Name"])
209
self.logger('Client {} received its secret'
210
.format(self.properties["Name"]))
218
212
def need_approval(self, timeout, default):
220
message = "Client %s needs approval within %f seconds"
214
message = 'Client {} needs approval within {} seconds'
222
message = "Client %s will get its secret in %f seconds"
223
log.info(message, self.properties["Name"], timeout/1000)
216
message = 'Client {} will get its secret in {} seconds'
217
self.logger(message.format(self.properties["Name"],
225
220
def rejected(self, reason):
226
log.info("Client %s was rejected; reason: %s",
227
self.properties["Name"], reason)
221
self.logger('Client {} was rejected; reason: {}'
222
.format(self.properties["Name"], reason))
229
224
def selectable(self):
230
225
"""Make this a "selectable" widget.
231
This overrides the method from urwid.Widget."""
226
This overrides the method from urwid.FlowWidget."""
234
229
def rows(self, maxcolrow, focus=False):
235
230
"""How many rows this widget will occupy might depend on
236
231
whether we have focus or not.
237
This overrides the method from urwid.Widget"""
232
This overrides the method from urwid.FlowWidget"""
238
233
return self.current_widget(focus).rows(maxcolrow, focus=focus)
240
235
def current_widget(self, focus=False):
333
328
def render(self, maxcolrow, focus=False):
334
329
"""Render differently if we have focus.
335
This overrides the method from urwid.Widget"""
330
This overrides the method from urwid.FlowWidget"""
336
331
return self.current_widget(focus).render(maxcolrow,
339
334
def keypress(self, maxcolrow, key):
341
This overrides the method from urwid.Widget"""
336
This overrides the method from urwid.FlowWidget"""
343
338
self.proxy.Set(client_interface, "Enabled",
344
339
dbus.Boolean(True), ignore_reply=True,
471
458
self.log_visible = True
472
459
self.log_wrap = "any"
474
self.loghandler = UILogHandler(self)
477
self.add_log_line(("bold",
478
"Mandos Monitor version " + version))
479
self.add_log_line(("bold", "q: Quit ?: Help"))
462
self.log_message_raw(("bold",
463
"Mandos Monitor version " + version))
464
self.log_message_raw(("bold",
481
self.busname = domain + ".Mandos"
467
self.busname = domain + '.Mandos'
482
468
self.main_loop = GLib.MainLoop()
484
def client_not_found(self, key_id, address):
485
log.info("Client with address %s and key ID %s could"
486
" not be found", address, key_id)
470
def client_not_found(self, fingerprint, address):
471
self.log_message("Client with address {} and fingerprint {}"
472
" could not be found"
473
.format(address, fingerprint))
488
475
def rebuild(self):
489
476
"""This rebuilds the User Interface.
500
487
self.uilist.append(self.logbox)
501
488
self.topwidget = urwid.Pile(self.uilist)
503
def add_log_line(self, markup):
490
def log_message(self, message, level=1):
491
"""Log message formatted with timestamp"""
492
if level < self.log_level:
494
timestamp = datetime.datetime.now().isoformat()
495
self.log_message_raw("{}: {}".format(timestamp, message),
498
def log_message_raw(self, markup, level=1):
499
"""Add a log message to the log buffer."""
500
if level < self.log_level:
504
502
self.log.append(urwid.Text(markup, wrap=self.log_wrap))
505
503
if self.max_log_length:
506
504
if len(self.log) > self.max_log_length:
507
del self.log[0:(len(self.log) - self.max_log_length)]
505
del self.log[0:len(self.log)-self.max_log_length-1]
508
506
self.logbox.set_focus(len(self.logbox.body.contents)-1,
509
507
coming_from="above")
624
623
proxy_object=client_proxy_object,
625
624
properties=client,
626
625
update_hook=self.refresh,
627
delete_hook=self.remove_client),
626
delete_hook=self.remove_client,
627
logger=self.log_message),
631
self._input_callback_tag = (
633
GLib.IOChannel.unix_new(sys.stdin.fileno()),
634
GLib.PRIORITY_DEFAULT, GLib.IO_IN,
635
glib_safely(self.process_input)))
631
self._input_callback_tag = (GLib.io_add_watch
636
635
self.main_loop.run()
637
636
# Main loop has finished, we should close everything now
638
637
GLib.source_remove(self._input_callback_tag)
639
with warnings.catch_warnings():
640
warnings.simplefilter("ignore", BytesWarning)
644
641
self.main_loop.quit()
645
log.removeHandler(self.loghandler)
646
log.propagate = self.orig_log_propagate
648
643
def process_input(self, source, condition):
649
644
keys = self.screen.get_input()
742
class UILogHandler(logging.Handler):
743
def __init__(self, ui, *args, **kwargs):
745
super(UILogHandler, self).__init__(*args, **kwargs)
747
logging.Formatter("%(asctime)s: %(message)s"))
748
def emit(self, record):
749
msg = self.format(record)
750
if record.levelno > logging.INFO:
752
self.ui.add_log_line(msg)
755
738
ui = UserInterface()
758
741
except KeyboardInterrupt:
759
with warnings.catch_warnings():
760
warnings.filterwarnings("ignore", "", BytesWarning)
763
with warnings.catch_warnings():
764
warnings.filterwarnings("ignore", "", BytesWarning)
743
except Exception as e:
744
ui.log_message(str(e))