103
102
super(MandosClientPropertyCache, self).__init__(**kwargs)
105
def properties_changed(self, interface, properties, invalidated):
106
"""This is called whenever we get a PropertiesChanged signal
107
It updates the changed properties in the "properties" dict.
104
def _property_changed(self, property, value):
105
"""Helper which takes positional arguments"""
106
return self.property_changed(property=property, value=value)
108
def property_changed(self, property=None, value=None):
109
"""This is called whenever we get a PropertyChanged signal
110
It updates the changed property in the "properties" dict.
109
112
# Update properties dict with new value
110
if interface == client_interface:
111
self.properties.update(properties)
113
self.properties[property] = value
113
115
def delete(self):
114
116
self.property_changed_match.remove()
170
172
if flag and self._update_timer_callback_tag is None:
171
173
# Will update the shown timer value every second
172
self._update_timer_callback_tag = (GLib.timeout_add
174
self._update_timer_callback_tag = (gobject.timeout_add
174
176
self.update_timer))
175
177
elif not (flag or self._update_timer_callback_tag is None):
176
GLib.source_remove(self._update_timer_callback_tag)
178
gobject.source_remove(self._update_timer_callback_tag)
177
179
self._update_timer_callback_tag = None
179
181
def checker_completed(self, exitstatus, condition, command):
180
182
if exitstatus == 0:
181
self.logger('Checker for client {} (command "{}")'
182
' succeeded'.format(self.properties["Name"],
187
186
if os.WIFEXITED(condition):
188
self.logger('Checker for client {} (command "{}") failed'
187
self.logger('Checker for client {0} (command "{1}")'
188
' failed with exit code {2}'
190
189
.format(self.properties["Name"], command,
191
190
os.WEXITSTATUS(condition)))
192
191
elif os.WIFSIGNALED(condition):
193
self.logger('Checker for client {} (command "{}") was'
194
' killed by signal {}'
192
self.logger('Checker for client {0} (command "{1}") was'
193
' killed by signal {2}'
195
194
.format(self.properties["Name"], command,
196
195
os.WTERMSIG(condition)))
196
elif os.WCOREDUMP(condition):
197
self.logger('Checker for client {0} (command "{1}")'
199
.format(self.properties["Name"], command))
201
self.logger('Checker for client {0} completed'
203
.format(self.properties["Name"]))
199
206
def checker_started(self, command):
200
"""Server signals that a checker started."""
201
self.logger('Client {} started checker "{}"'
202
.format(self.properties["Name"],
207
"""Server signals that a checker started. This could be useful
208
to log in the future. """
209
#self.logger('Client {0} started checker "{1}"'
210
# .format(self.properties["Name"],
205
214
def got_secret(self):
206
self.logger('Client {} received its secret'
215
self.logger('Client {0} received its secret'
207
216
.format(self.properties["Name"]))
209
218
def need_approval(self, timeout, default):
211
message = 'Client {} needs approval within {} seconds'
220
message = 'Client {0} needs approval within {1} seconds'
213
message = 'Client {} will get its secret in {} seconds'
222
message = 'Client {0} will get its secret in {1} seconds'
214
223
self.logger(message.format(self.properties["Name"],
217
226
def rejected(self, reason):
218
self.logger('Client {} was rejected; reason: {}'
227
self.logger('Client {0} was rejected; reason: {1}'
219
228
.format(self.properties["Name"], reason))
221
230
def selectable(self):
266
275
timer = datetime.timedelta()
267
276
if self.properties["ApprovedByDefault"]:
268
message = "Approval in {}. (d)eny?"
277
message = "Approval in {0}. (d)eny?"
270
message = "Denial in {}. (a)pprove?"
279
message = "Denial in {0}. (a)pprove?"
271
280
message = message.format(str(timer).rsplit(".", 1)[0])
272
281
self.using_timer(True)
273
282
elif self.properties["LastCheckerStatus"] != 0:
281
290
timer = max(expires - datetime.datetime.utcnow(),
282
291
datetime.timedelta())
283
292
message = ('A checker has failed! Time until client'
293
' gets disabled: {0}'
285
294
.format(str(timer).rsplit(".", 1)[0]))
286
295
self.using_timer(True)
288
297
message = "enabled"
289
298
self.using_timer(False)
290
self._text = "{}{}".format(base, message)
299
self._text = "{0}{1}".format(base, message)
292
301
if not urwid.supports_unicode():
293
302
self._text = self._text.encode("ascii", "replace")
306
315
self.update_hook()
308
317
def update_timer(self):
309
"""called by GLib. Will indefinitely loop until
310
GLib.source_remove() on tag is called
318
"""called by gobject. Will indefinitely loop until
319
gobject.source_remove() on tag is called"""
313
321
return True # Keep calling this
315
323
def delete(self, **kwargs):
316
324
if self._update_timer_callback_tag is not None:
317
GLib.source_remove(self._update_timer_callback_tag)
325
gobject.source_remove(self._update_timer_callback_tag)
318
326
self._update_timer_callback_tag = None
319
327
for match in self.match_objects:
334
342
This overrides the method from urwid.FlowWidget"""
336
self.proxy.Set(client_interface, "Enabled",
337
dbus.Boolean(True), ignore_reply = True,
338
dbus_interface = dbus.PROPERTIES_IFACE)
344
self.proxy.Enable(dbus_interface = client_interface,
340
self.proxy.Set(client_interface, "Enabled", False,
342
dbus_interface = dbus.PROPERTIES_IFACE)
347
self.proxy.Disable(dbus_interface = client_interface,
344
350
self.proxy.Approve(dbus.Boolean(True, variant_level=1),
345
351
dbus_interface = client_interface,
354
360
ignore_reply=True)
356
self.proxy.Set(client_interface, "CheckerRunning",
357
dbus.Boolean(True), ignore_reply = True,
358
dbus_interface = dbus.PROPERTIES_IFACE)
362
self.proxy.StartChecker(dbus_interface = client_interface,
360
self.proxy.Set(client_interface, "CheckerRunning",
361
dbus.Boolean(False), ignore_reply = True,
362
dbus_interface = dbus.PROPERTIES_IFACE)
365
self.proxy.StopChecker(dbus_interface = client_interface,
364
368
self.proxy.CheckedOK(dbus_interface = client_interface,
365
369
ignore_reply=True)
376
def properties_changed(self, interface, properties, invalidated):
377
"""Call self.update() if any properties changed.
380
def property_changed(self, property=None, **kwargs):
381
"""Call self.update() if old value is not new value.
378
382
This overrides the method from MandosClientPropertyCache"""
379
old_values = { key: self.properties.get(key)
380
for key in properties.keys() }
381
super(MandosClientWidget, self).properties_changed(
382
interface, properties, invalidated)
383
if any(old_values[key] != self.properties.get(key)
384
for key in old_values):
383
property_name = str(property)
384
old_value = self.properties.get(property_name)
385
super(MandosClientWidget, self).property_changed(
386
property=property, **kwargs)
387
if self.properties.get(property_name) != old_value:
401
404
"""This is the entire user interface - the whole screen
402
405
with boxes, lists of client widgets, etc.
404
def __init__(self, max_log_length=1000, log_level=1):
407
def __init__(self, max_log_length=1000):
405
408
DBusGMainLoop(set_as_default=True)
407
410
self.screen = urwid.curses_display.Screen()
463
464
"q: Quit ?: Help"))
465
466
self.busname = domain + '.Mandos'
466
self.main_loop = GLib.MainLoop()
467
self.main_loop = gobject.MainLoop()
468
469
def client_not_found(self, fingerprint, address):
469
self.log_message("Client with address {} and fingerprint {}"
470
" could not be found"
470
self.log_message("Client with address {0} and fingerprint"
471
" {1} could not be found"
471
472
.format(address, fingerprint))
473
474
def rebuild(self):
486
487
self.uilist.append(self.logbox)
487
488
self.topwidget = urwid.Pile(self.uilist)
489
def log_message(self, message, level=1):
490
def log_message(self, message):
490
491
"""Log message formatted with timestamp"""
491
if level < self.log_level:
493
492
timestamp = datetime.datetime.now().isoformat()
494
self.log_message_raw("{}: {}".format(timestamp, message),
493
self.log_message_raw(timestamp + ": " + message)
497
def log_message_raw(self, markup, level=1):
495
def log_message_raw(self, markup):
498
496
"""Add a log message to the log buffer."""
499
if level < self.log_level:
501
497
self.log.append(urwid.Text(markup, wrap=self.log_wrap))
502
498
if (self.max_log_length
503
499
and len(self.log) > self.max_log_length):
510
506
"""Toggle visibility of the log buffer."""
511
507
self.log_visible = not self.log_visible
513
self.log_message("Log visibility changed to: {}"
514
.format(self.log_visible), level=0)
509
#self.log_message("Log visibility changed to: "
510
# + str(self.log_visible))
516
512
def change_log_display(self):
517
513
"""Change type of log display.
522
518
self.log_wrap = "clip"
523
519
for textwidget in self.log:
524
520
textwidget.set_wrap_mode(self.log_wrap)
525
self.log_message("Wrap mode: {}".format(self.log_wrap),
521
#self.log_message("Wrap mode: " + self.log_wrap)
528
def find_and_remove_client(self, path, interfaces):
523
def find_and_remove_client(self, path, name):
529
524
"""Find a client by its object path and remove it.
531
This is connected to the InterfacesRemoved signal from the
526
This is connected to the ClientRemoved signal from the
532
527
Mandos server object."""
533
if client_interface not in interfaces:
534
# Not a Mandos client object; ignore
537
529
client = self.clients_dict[path]
540
self.log_message("Unknown client {!r} removed"
532
self.log_message("Unknown client {0!r} ({1!r}) removed"
545
def add_new_client(self, path, ifs_and_props):
546
"""Find a client by its object path and remove it.
548
This is connected to the InterfacesAdded signal from the
549
Mandos server object.
551
if client_interface not in ifs_and_props:
552
# Not a Mandos client object; ignore
537
def add_new_client(self, path):
554
538
client_proxy_object = self.bus.get_object(self.busname, path)
555
539
self.add_client(MandosClientWidget(server_proxy_object
556
540
=self.mandos_serv,
605
586
mandos_clients = dbus.Dictionary()
607
588
(self.mandos_serv
608
.connect_to_signal("InterfacesRemoved",
589
.connect_to_signal("ClientRemoved",
609
590
self.find_and_remove_client,
611
= dbus.OBJECT_MANAGER_IFACE,
591
dbus_interface=server_interface,
612
592
byte_arrays=True))
613
593
(self.mandos_serv
614
.connect_to_signal("InterfacesAdded",
594
.connect_to_signal("ClientAdded",
615
595
self.add_new_client,
617
= dbus.OBJECT_MANAGER_IFACE,
596
dbus_interface=server_interface,
618
597
byte_arrays=True))
619
598
(self.mandos_serv
620
599
.connect_to_signal("ClientNotFound",