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