86
86
properties and calls a hook function when any of them are
89
def __init__(self, proxy_object=None, *args, **kwargs):
89
def __init__(self, proxy_object=None, properties=None, **kwargs):
90
90
self.proxy = proxy_object # Mandos Client proxy object
92
self.properties = dict()
91
self.properties = dict() if properties is None else properties
93
92
self.property_changed_match = (
94
93
self.proxy.connect_to_signal("PropertyChanged",
95
self.property_changed,
94
self._property_changed,
99
self.properties.update(
100
self.proxy.GetAll(client_interface,
101
dbus_interface = dbus.PROPERTIES_IFACE))
103
#XXX This breaks good super behaviour
104
# 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)
107
110
def property_changed(self, property=None, value=None):
108
111
"""This is called whenever we get a PropertyChanged signal
111
114
# Update properties dict with new value
112
115
self.properties[property] = value
114
def delete(self, *args, **kwargs):
115
118
self.property_changed_match.remove()
116
super(MandosClientPropertyCache, self).__init__(
120
121
class MandosClientWidget(urwid.FlowWidget, MandosClientPropertyCache):
124
125
def __init__(self, server_proxy_object=None, update_hook=None,
125
delete_hook=None, logger=None, *args, **kwargs):
126
delete_hook=None, logger=None, **kwargs):
126
127
# Called on update
127
128
self.update_hook = update_hook
128
129
# Called on delete
133
134
self.logger = logger
135
136
self._update_timer_callback_tag = None
136
self._update_timer_callback_lock = 0
138
138
# The widget shown normally
139
139
self._text_widget = urwid.Text("")
140
140
# The widget shown when we have focus
141
141
self._focus_text_widget = urwid.Text("")
142
super(MandosClientWidget, self).__init__(
143
update_hook=update_hook, delete_hook=delete_hook,
142
super(MandosClientWidget, self).__init__(**kwargs)
146
144
self.opened = False
148
last_checked_ok = isoformat_to_datetime(self.properties
151
if self.properties ["LastCheckerStatus"] != 0:
152
self.using_timer(True)
154
if self.need_approval:
155
self.using_timer(True)
157
146
self.match_objects = (
158
147
self.proxy.connect_to_signal("CheckerCompleted",
159
148
self.checker_completed,
178
167
#self.logger('Created client {0}'
179
168
# .format(self.properties["Name"]))
181
def property_changed(self, property=None, value=None):
182
super(self, MandosClientWidget).property_changed(property,
184
if property == "ApprovalPending":
185
using_timer(bool(value))
186
if property == "LastCheckerStatus":
187
using_timer(value != 0)
188
#self.logger('Checker for client {0} (command "{1}") was '
189
# ' successful'.format(self.properties["Name"],
192
170
def using_timer(self, flag):
193
171
"""Call this method with True or False when timer should be
194
172
activated or deactivated.
196
old = self._update_timer_callback_lock
198
self._update_timer_callback_lock += 1
200
self._update_timer_callback_lock -= 1
201
if old == 0 and self._update_timer_callback_lock:
174
if flag and self._update_timer_callback_tag is None:
202
175
# Will update the shown timer value every second
203
176
self._update_timer_callback_tag = (gobject.timeout_add
205
178
self.update_timer))
206
elif old and self._update_timer_callback_lock == 0:
179
elif not (flag or self._update_timer_callback_tag is None):
207
180
gobject.source_remove(self._update_timer_callback_tag)
208
181
self._update_timer_callback_tag = None
251
224
message = 'Client {0} will get its secret in {1} seconds'
252
225
self.logger(message.format(self.properties["Name"],
254
self.using_timer(True)
256
228
def rejected(self, reason):
257
229
self.logger('Client {0} was rejected; reason: {1}'
283
255
"bold-underline-blink":
284
256
"bold-underline-blink-standout",
287
259
# Rebuild focus and non-focus widgets using current properties
289
261
# Base part of a client. Name!
290
262
base = '{name}: '.format(name=self.properties["Name"])
291
263
if not self.properties["Enabled"]:
292
264
message = "DISABLED"
265
self.using_timer(False)
293
266
elif self.properties["ApprovalPending"]:
294
267
timeout = datetime.timedelta(milliseconds
295
268
= self.properties
297
270
last_approval_request = isoformat_to_datetime(
298
271
self.properties["LastApprovalRequest"])
299
272
if last_approval_request is not None:
300
timer = timeout - (datetime.datetime.utcnow()
301
- last_approval_request)
273
timer = max(timeout - (datetime.datetime.utcnow()
274
- last_approval_request),
275
datetime.timedelta())
303
277
timer = datetime.timedelta()
304
278
if self.properties["ApprovedByDefault"]:
307
281
message = "Denial in {0}. (a)pprove?"
308
282
message = message.format(unicode(timer).rsplit(".", 1)[0])
283
self.using_timer(True)
309
284
elif self.properties["LastCheckerStatus"] != 0:
310
285
# When checker has failed, show timer until client expires
311
286
expires = self.properties["Expires"]
315
290
expires = (datetime.datetime.strptime
316
291
(expires, '%Y-%m-%dT%H:%M:%S.%f'))
317
timer = expires - datetime.datetime.utcnow()
292
timer = max(expires - datetime.datetime.utcnow(),
293
datetime.timedelta())
318
294
message = ('A checker has failed! Time until client'
319
295
' gets disabled: {0}'
320
296
.format(unicode(timer).rsplit(".", 1)[0]))
297
self.using_timer(True)
322
299
message = "enabled"
300
self.using_timer(False)
323
301
self._text = "{0}{1}".format(base, message)
325
303
if not urwid.supports_unicode():
326
304
self._text = self._text.encode("ascii", "replace")
327
305
textlist = [("normal", self._text)]
345
323
return True # Keep calling this
347
def delete(self, *args, **kwargs):
325
def delete(self, **kwargs):
348
326
if self._update_timer_callback_tag is not None:
349
327
gobject.source_remove(self._update_timer_callback_tag)
350
328
self._update_timer_callback_tag = None
353
331
self.match_objects = ()
354
332
if self.delete_hook is not None:
355
333
self.delete_hook(self)
356
return super(MandosClientWidget, self).delete(*args, **kwargs)
334
return super(MandosClientWidget, self).delete(**kwargs)
358
336
def render(self, maxcolrow, focus=False):
359
337
"""Render differently if we have focus.
404
def property_changed(self, property=None, value=None,
382
def property_changed(self, property=None, **kwargs):
406
383
"""Call self.update() if old value is not new value.
407
384
This overrides the method from MandosClientPropertyCache"""
408
385
property_name = unicode(property)
409
386
old_value = self.properties.get(property_name)
410
387
super(MandosClientWidget, self).property_changed(
411
property=property, value=value, *args, **kwargs)
388
property=property, **kwargs)
412
389
if self.properties.get(property_name) != old_value:
418
395
"down" key presses, thus not allowing any containing widgets to
419
396
use them as an excuse to shift focus away from this widget.
421
def keypress(self, maxcolrow, key):
422
ret = super(ConstrainedListBox, self).keypress(maxcolrow, key)
398
def keypress(self, *args, **kwargs):
399
ret = super(ConstrainedListBox, self).keypress(*args, **kwargs)
423
400
if ret in ("up", "down"):
512
489
self.topwidget = urwid.Pile(self.uilist)
514
491
def log_message(self, message):
492
"""Log message formatted with timestamp"""
515
493
timestamp = datetime.datetime.now().isoformat()
516
494
self.log_message_raw(timestamp + ": " + message)
608
586
mandos_clients = (self.mandos_serv
609
587
.GetAllClientsWithProperties())
588
if not mandos_clients:
589
self.log_message_raw(("bold", "Note: Server has no clients."))
610
590
except dbus.exceptions.DBusException:
591
self.log_message_raw(("bold", "Note: No Mandos servers running."))
611
592
mandos_clients = dbus.Dictionary()
613
594
(self.mandos_serv