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
124
135
def __init__(self, server_proxy_object=None, update_hook=None,
125
delete_hook=None, logger=None, **kwargs):
136
delete_hook=None, **kwargs):
126
137
# Called on update
127
138
self.update_hook = update_hook
128
139
# Called on delete
129
140
self.delete_hook = delete_hook
130
141
# Mandos Server proxy object
131
142
self.server_proxy_object = server_proxy_object
135
144
self._update_timer_callback_tag = None
173
181
if flag and self._update_timer_callback_tag is None:
174
182
# Will update the shown timer value every second
175
self._update_timer_callback_tag = (GLib.timeout_add
183
self._update_timer_callback_tag = (
184
GLib.timeout_add(1000,
185
glib_safely(self.update_timer)))
178
186
elif not (flag or self._update_timer_callback_tag is None):
179
187
GLib.source_remove(self._update_timer_callback_tag)
180
188
self._update_timer_callback_tag = None
182
190
def checker_completed(self, exitstatus, condition, command):
183
191
if exitstatus == 0:
184
self.logger('Checker for client {} (command "{}")'
185
' succeeded'.format(self.properties["Name"],
192
log.debug('Checker for client %s (command "%s")'
193
" succeeded", self.properties["Name"], command)
190
197
if os.WIFEXITED(condition):
191
self.logger('Checker for client {} (command "{}") failed'
193
.format(self.properties["Name"], command,
194
os.WEXITSTATUS(condition)))
198
log.info('Checker for client %s (command "%s") failed'
199
" with exit code %d", self.properties["Name"],
200
command, os.WEXITSTATUS(condition))
195
201
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)))
202
log.info('Checker for client %s (command "%s") was'
203
" killed by signal %d", self.properties["Name"],
204
command, os.WTERMSIG(condition))
202
207
def checker_started(self, command):
203
208
"""Server signals that a checker started."""
204
self.logger('Client {} started checker "{}"'
205
.format(self.properties["Name"],
209
log.debug('Client %s started checker "%s"',
210
self.properties["Name"], command)
208
212
def got_secret(self):
209
self.logger('Client {} received its secret'
210
.format(self.properties["Name"]))
213
log.info("Client %s received its secret",
214
self.properties["Name"])
212
216
def need_approval(self, timeout, default):
214
message = 'Client {} needs approval within {} seconds'
218
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"],
220
message = "Client %s will get its secret in %f seconds"
221
log.info(message, self.properties["Name"], timeout/1000)
220
223
def rejected(self, reason):
221
self.logger('Client {} was rejected; reason: {}'
222
.format(self.properties["Name"], reason))
224
log.info("Client %s was rejected; reason: %s",
225
self.properties["Name"], reason)
224
227
def selectable(self):
225
228
"""Make this a "selectable" widget.
279
282
timer = datetime.timedelta(0)
281
284
expires = (datetime.datetime.strptime
282
(expires, '%Y-%m-%dT%H:%M:%S.%f'))
285
(expires, "%Y-%m-%dT%H:%M:%S.%f"))
283
286
timer = max(expires - datetime.datetime.utcnow(),
284
287
datetime.timedelta())
285
message = ('A checker has failed! Time until client'
288
message = ("A checker has failed! Time until client"
287
290
.format(str(timer).rsplit(".", 1)[0]))
288
291
self.using_timer(True)
403
class UserInterface(object):
404
417
"""This is the entire user interface - the whole screen
405
418
with boxes, lists of client widgets, etc.
407
def __init__(self, max_log_length=1000, log_level=1):
420
def __init__(self, max_log_length=1000):
408
421
DBusGMainLoop(set_as_default=True)
410
423
self.screen = urwid.curses_display.Screen()
458
469
self.log_visible = True
459
470
self.log_wrap = "any"
472
self.loghandler = UILogHandler(self)
462
self.log_message_raw(("bold",
463
"Mandos Monitor version " + version))
464
self.log_message_raw(("bold",
475
self.add_log_line(("bold",
476
"Mandos Monitor version " + version))
477
self.add_log_line(("bold", "q: Quit ?: Help"))
467
self.busname = domain + '.Mandos'
479
self.busname = domain + ".Mandos"
468
480
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))
482
def client_not_found(self, key_id, address):
483
log.info("Client with address %s and key ID %s could"
484
" not be found", address, key_id)
475
486
def rebuild(self):
476
487
"""This rebuilds the User Interface.
487
498
self.uilist.append(self.logbox)
488
499
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:
501
def add_log_line(self, markup):
502
502
self.log.append(urwid.Text(markup, wrap=self.log_wrap))
503
503
if self.max_log_length:
504
504
if len(self.log) > self.max_log_length:
505
del self.log[0:len(self.log)-self.max_log_length-1]
505
del self.log[0:(len(self.log) - self.max_log_length)]
506
506
self.logbox.set_focus(len(self.logbox.body.contents)-1,
507
507
coming_from="above")
593
594
mandos_clients = (self.mandos_serv
594
595
.GetAllClientsWithProperties())
595
596
if not mandos_clients:
596
self.log_message_raw(("bold",
597
"Note: Server has no clients."))
597
log.warning("Note: Server has no clients.")
598
598
except dbus.exceptions.DBusException:
599
self.log_message_raw(("bold",
600
"Note: No Mandos server running."))
599
log.warning("Note: No Mandos server running.")
601
600
mandos_clients = dbus.Dictionary()
603
602
(self.mandos_serv
623
622
proxy_object=client_proxy_object,
624
623
properties=client,
625
624
update_hook=self.refresh,
626
delete_hook=self.remove_client,
627
logger=self.log_message),
625
delete_hook=self.remove_client),
631
self._input_callback_tag = (GLib.io_add_watch
629
self._input_callback_tag = (
631
GLib.IOChannel.unix_new(sys.stdin.fileno()),
632
GLib.PRIORITY_DEFAULT, GLib.IO_IN,
633
glib_safely(self.process_input)))
635
634
self.main_loop.run()
636
635
# Main loop has finished, we should close everything now
637
636
GLib.source_remove(self._input_callback_tag)
637
with warnings.catch_warnings():
638
warnings.simplefilter("ignore", BytesWarning)
641
642
self.main_loop.quit()
643
log.removeHandler(self.loghandler)
644
log.propagate = self.orig_log_propagate
643
646
def process_input(self, source, condition):
644
647
keys = self.screen.get_input()
705
707
self.topwidget.set_focus(self.logbox)
708
if self.log_level == 0:
710
self.log_message("Verbose mode: Off")
710
if log.level < logging.INFO:
711
log.setLevel(logging.INFO)
712
log.info("Verbose mode: Off")
713
self.log_message("Verbose mode: On")
714
log.setLevel(logging.NOTSET)
715
log.info("Verbose mode: On")
714
716
# elif (key == "end" or key == "meta >" or key == "G"
715
717
# or key == ">"):
716
718
# pass # xxx end-of-buffer
740
class UILogHandler(logging.Handler):
741
def __init__(self, ui, *args, **kwargs):
743
super(UILogHandler, self).__init__(*args, **kwargs)
745
logging.Formatter("%(asctime)s: %(message)s"))
746
def emit(self, record):
747
msg = self.format(record)
748
if record.levelno > logging.INFO:
750
self.ui.add_log_line(msg)
738
753
ui = UserInterface()
741
756
except KeyboardInterrupt:
743
except Exception as e:
744
ui.log_message(str(e))
757
with warnings.catch_warnings():
758
warnings.filterwarnings("ignore", "", BytesWarning)
761
with warnings.catch_warnings():
762
warnings.filterwarnings("ignore", "", BytesWarning)