83
86
properties and calls a hook function when any of them are
86
def __init__(self, proxy_object=None, *args, **kwargs):
89
def __init__(self, proxy_object=None, properties=None, **kwargs):
87
90
self.proxy = proxy_object # Mandos Client proxy object
89
self.properties = dict()
91
self.properties = dict() if properties is None else properties
90
92
self.property_changed_match = (
91
93
self.proxy.connect_to_signal("PropertyChanged",
92
self.property_changed,
94
self._property_changed,
96
self.properties.update(
97
self.proxy.GetAll(client_interface,
98
dbus_interface = dbus.PROPERTIES_IFACE))
100
#XXX This breaks good super behaviour
101
# super(MandosClientPropertyCache, self).__init__(
98
if properties is None:
99
self.properties.update(
100
self.proxy.GetAll(client_interface,
102
= dbus.PROPERTIES_IFACE))
104
super(MandosClientPropertyCache, self).__init__(**kwargs)
106
def _property_changed(self, property, value):
107
"""Helper which takes positional arguments"""
108
return self.property_changed(property=property, value=value)
104
110
def property_changed(self, property=None, value=None):
105
111
"""This is called whenever we get a PropertyChanged signal
132
136
self._update_timer_callback_tag = None
133
137
self._update_timer_callback_lock = 0
134
self.last_checker_failed = False
136
139
# The widget shown normally
137
140
self._text_widget = urwid.Text("")
138
141
# The widget shown when we have focus
139
142
self._focus_text_widget = urwid.Text("")
140
super(MandosClientWidget, self).__init__(
141
update_hook=update_hook, delete_hook=delete_hook,
143
super(MandosClientWidget, self).__init__(**kwargs)
144
145
self.opened = False
146
147
last_checked_ok = isoformat_to_datetime(self.properties
147
148
["LastCheckedOK"])
148
if last_checked_ok is None:
149
self.last_checker_failed = True
151
self.last_checker_failed = ((datetime.datetime.utcnow()
158
if self.last_checker_failed:
150
if self.properties ["LastCheckerStatus"] != 0:
159
151
self.using_timer(True)
161
153
if self.need_approval:
183
175
client_interface,
184
176
byte_arrays=True))
185
#self.logger('Created client %s' % (self.properties["Name"]))
177
#self.logger('Created client {0}'
178
# .format(self.properties["Name"]))
187
180
def property_changed(self, property=None, value=None):
188
181
super(self, MandosClientWidget).property_changed(property,
190
183
if property == "ApprovalPending":
191
184
using_timer(bool(value))
185
if property == "LastCheckerStatus":
186
using_timer(value != 0)
187
#self.logger('Checker for client {0} (command "{1}") was '
188
# ' successful'.format(self.properties["Name"],
193
191
def using_timer(self, flag):
194
192
"""Call this method with True or False when timer should be
195
193
activated or deactivated.
211
209
def checker_completed(self, exitstatus, condition, command):
212
210
if exitstatus == 0:
213
if self.last_checker_failed:
214
self.last_checker_failed = False
215
self.using_timer(False)
216
#self.logger('Checker for client %s (command "%s")'
218
# % (self.properties["Name"], command))
222
if not self.last_checker_failed:
223
self.last_checker_failed = True
224
self.using_timer(True)
225
214
if os.WIFEXITED(condition):
226
self.logger('Checker for client %s (command "%s")'
227
' failed with exit code %s'
228
% (self.properties["Name"], command,
229
os.WEXITSTATUS(condition)))
215
self.logger('Checker for client {0} (command "{1}")'
216
' failed with exit code {2}'
217
.format(self.properties["Name"], command,
218
os.WEXITSTATUS(condition)))
230
219
elif os.WIFSIGNALED(condition):
231
self.logger('Checker for client %s (command "%s")'
232
' was killed by signal %s'
233
% (self.properties["Name"], command,
234
os.WTERMSIG(condition)))
220
self.logger('Checker for client {0} (command "{1}") was'
221
' killed by signal {2}'
222
.format(self.properties["Name"], command,
223
os.WTERMSIG(condition)))
235
224
elif os.WCOREDUMP(condition):
236
self.logger('Checker for client %s (command "%s")'
225
self.logger('Checker for client {0} (command "{1}")'
238
% (self.properties["Name"], command))
227
.format(self.properties["Name"], command))
240
self.logger('Checker for client %s completed'
229
self.logger('Checker for client {0} completed'
231
.format(self.properties["Name"]))
244
234
def checker_started(self, command):
245
#self.logger('Client %s started checker "%s"'
246
# % (self.properties["Name"], unicode(command)))
235
"""Server signals that a checker started. This could be useful
236
to log in the future. """
237
#self.logger('Client {0} started checker "{1}"'
238
# .format(self.properties["Name"],
249
242
def got_secret(self):
250
self.last_checker_failed = False
251
self.logger('Client %s received its secret'
252
% self.properties["Name"])
243
self.logger('Client {0} received its secret'
244
.format(self.properties["Name"]))
254
246
def need_approval(self, timeout, default):
256
message = 'Client %s needs approval within %s seconds'
248
message = 'Client {0} needs approval within {1} seconds'
258
message = 'Client %s will get its secret in %s seconds'
260
% (self.properties["Name"], timeout/1000))
250
message = 'Client {0} will get its secret in {1} seconds'
251
self.logger(message.format(self.properties["Name"],
261
253
self.using_timer(True)
263
255
def rejected(self, reason):
264
self.logger('Client %s was rejected; reason: %s'
265
% (self.properties["Name"], reason))
256
self.logger('Client {0} was rejected; reason: {1}'
257
.format(self.properties["Name"], reason))
267
259
def selectable(self):
268
260
"""Make this a "selectable" widget.
311
302
timer = datetime.timedelta()
312
303
if self.properties["ApprovedByDefault"]:
313
message = "Approval in %s. (d)eny?"
304
message = "Approval in {0}. (d)eny?"
315
message = "Denial in %s. (a)pprove?"
316
message = message % unicode(timer).rsplit(".", 1)[0]
317
elif self.last_checker_failed:
318
# When checker has failed, print a timer until client expires
306
message = "Denial in {0}. (a)pprove?"
307
message = message.format(unicode(timer).rsplit(".", 1)[0])
308
elif self.properties["LastCheckerStatus"] != 0:
309
# When checker has failed, show timer until client expires
319
310
expires = self.properties["Expires"]
320
311
if expires == "":
321
312
timer = datetime.timedelta(0)
323
expires = datetime.datetime.strptime(expires,
324
'%Y-%m-%dT%H:%M:%S.%f')
314
expires = (datetime.datetime.strptime
315
(expires, '%Y-%m-%dT%H:%M:%S.%f'))
325
316
timer = expires - datetime.datetime.utcnow()
326
317
message = ('A checker has failed! Time until client'
328
% unicode(timer).rsplit(".", 1)[0])
318
' gets disabled: {0}'
319
.format(unicode(timer).rsplit(".", 1)[0]))
330
321
message = "enabled"
331
self._text = "%s%s" % (base, message)
322
self._text = "{0}{1}".format(base, message)
333
324
if not urwid.supports_unicode():
334
325
self._text = self._text.encode("ascii", "replace")
412
def property_changed(self, property=None, value=None,
403
def property_changed(self, property=None, **kwargs):
414
404
"""Call self.update() if old value is not new value.
415
405
This overrides the method from MandosClientPropertyCache"""
416
406
property_name = unicode(property)
417
407
old_value = self.properties.get(property_name)
418
408
super(MandosClientWidget, self).property_changed(
419
property=property, value=value, *args, **kwargs)
409
property=property, **kwargs)
420
410
if self.properties.get(property_name) != old_value:
426
416
"down" key presses, thus not allowing any containing widgets to
427
417
use them as an excuse to shift focus away from this widget.
429
def keypress(self, maxcolrow, key):
430
ret = super(ConstrainedListBox, self).keypress(maxcolrow, key)
419
def keypress(self, *args, **kwargs):
420
ret = super(ConstrainedListBox, self).keypress(*args, **kwargs)
431
421
if ret in ("up", "down"):
498
488
self.busname = domain + '.Mandos'
499
489
self.main_loop = gobject.MainLoop()
500
self.bus = dbus.SystemBus()
501
mandos_dbus_objc = self.bus.get_object(
502
self.busname, "/", follow_name_owner_changes=True)
503
self.mandos_serv = dbus.Interface(mandos_dbus_objc,
507
mandos_clients = (self.mandos_serv
508
.GetAllClientsWithProperties())
509
except dbus.exceptions.DBusException:
510
mandos_clients = dbus.Dictionary()
513
.connect_to_signal("ClientRemoved",
514
self.find_and_remove_client,
515
dbus_interface=server_interface,
518
.connect_to_signal("ClientAdded",
520
dbus_interface=server_interface,
523
.connect_to_signal("ClientNotFound",
524
self.client_not_found,
525
dbus_interface=server_interface,
527
for path, client in mandos_clients.iteritems():
528
client_proxy_object = self.bus.get_object(self.busname,
530
self.add_client(MandosClientWidget(server_proxy_object
533
=client_proxy_object,
543
491
def client_not_found(self, fingerprint, address):
544
self.log_message(("Client with address %s and fingerprint %s"
545
" could not be found" % (address,
492
self.log_message("Client with address {0} and fingerprint"
493
" {1} could not be found"
494
.format(address, fingerprint))
548
496
def rebuild(self):
549
497
"""This rebuilds the User Interface.
651
598
"""Start the main loop and exit when it's done."""
599
self.bus = dbus.SystemBus()
600
mandos_dbus_objc = self.bus.get_object(
601
self.busname, "/", follow_name_owner_changes=True)
602
self.mandos_serv = dbus.Interface(mandos_dbus_objc,
606
mandos_clients = (self.mandos_serv
607
.GetAllClientsWithProperties())
608
except dbus.exceptions.DBusException:
609
mandos_clients = dbus.Dictionary()
612
.connect_to_signal("ClientRemoved",
613
self.find_and_remove_client,
614
dbus_interface=server_interface,
617
.connect_to_signal("ClientAdded",
619
dbus_interface=server_interface,
622
.connect_to_signal("ClientNotFound",
623
self.client_not_found,
624
dbus_interface=server_interface,
626
for path, client in mandos_clients.iteritems():
627
client_proxy_object = self.bus.get_object(self.busname,
629
self.add_client(MandosClientWidget(server_proxy_object
632
=client_proxy_object,
653
643
self._input_callback_tag = (gobject.io_add_watch
654
644
(sys.stdin.fileno(),