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
484
def client_not_found(self, key_id, address):
471
self.log_message("Client with address {} and key ID {} could"
472
" not be found".format(address, key_id))
485
log.info("Client with address %s and key ID %s could"
486
" not be found", address, key_id)
474
488
def rebuild(self):
475
489
"""This rebuilds the User Interface.
486
500
self.uilist.append(self.logbox)
487
501
self.topwidget = urwid.Pile(self.uilist)
489
def log_message(self, message, level=1):
490
"""Log message formatted with timestamp"""
491
if level < self.log_level:
493
timestamp = datetime.datetime.now().isoformat()
494
self.log_message_raw("{}: {}".format(timestamp, message),
497
def log_message_raw(self, markup, level=1):
498
"""Add a log message to the log buffer."""
499
if level < self.log_level:
503
def add_log_line(self, markup):
501
504
self.log.append(urwid.Text(markup, wrap=self.log_wrap))
502
505
if self.max_log_length:
503
506
if len(self.log) > self.max_log_length:
504
del self.log[0:len(self.log)-self.max_log_length-1]
507
del self.log[0:(len(self.log) - self.max_log_length)]
505
508
self.logbox.set_focus(len(self.logbox.body.contents)-1,
506
509
coming_from="above")
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)
740
755
ui = UserInterface()
743
758
except KeyboardInterrupt:
745
except Exception as e:
746
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)