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
130
134
self.logger = logger
132
136
self._update_timer_callback_tag = None
133
self._update_timer_callback_lock = 0
135
138
# The widget shown normally
136
139
self._text_widget = urwid.Text("")
137
140
# The widget shown when we have focus
138
141
self._focus_text_widget = urwid.Text("")
139
super(MandosClientWidget, self).__init__(
140
update_hook=update_hook, delete_hook=delete_hook,
142
super(MandosClientWidget, self).__init__(**kwargs)
143
144
self.opened = False
145
last_checked_ok = isoformat_to_datetime(self.properties
148
if self.properties ["LastCheckerStatus"] != 0:
149
self.using_timer(True)
151
if self.need_approval:
152
self.using_timer(True)
154
146
self.match_objects = (
155
147
self.proxy.connect_to_signal("CheckerCompleted",
156
148
self.checker_completed,
173
165
client_interface,
174
166
byte_arrays=True))
175
#self.logger('Created client %s' % (self.properties["Name"]))
177
def property_changed(self, property=None, value=None):
178
super(self, MandosClientWidget).property_changed(property,
180
if property == "ApprovalPending":
181
using_timer(bool(value))
182
if property == "LastCheckerStatus":
183
using_timer(value != 0)
184
#self.logger('Checker for client %s (command "%s")'
186
# % (self.properties["Name"], command))
167
#self.logger('Created client {0}'
168
# .format(self.properties["Name"]))
188
170
def using_timer(self, flag):
189
171
"""Call this method with True or False when timer should be
190
172
activated or deactivated.
192
old = self._update_timer_callback_lock
194
self._update_timer_callback_lock += 1
196
self._update_timer_callback_lock -= 1
197
if old == 0 and self._update_timer_callback_lock:
174
if flag and self._update_timer_callback_tag is None:
198
175
# Will update the shown timer value every second
199
176
self._update_timer_callback_tag = (gobject.timeout_add
201
178
self.update_timer))
202
elif old and self._update_timer_callback_lock == 0:
179
elif not (flag or self._update_timer_callback_tag is None):
203
180
gobject.source_remove(self._update_timer_callback_tag)
204
181
self._update_timer_callback_tag = None
211
188
if os.WIFEXITED(condition):
212
self.logger('Checker for client %s (command "%s")'
213
' failed with exit code %s'
214
% (self.properties["Name"], command,
215
os.WEXITSTATUS(condition)))
189
self.logger('Checker for client {0} (command "{1}")'
190
' failed with exit code {2}'
191
.format(self.properties["Name"], command,
192
os.WEXITSTATUS(condition)))
216
193
elif os.WIFSIGNALED(condition):
217
self.logger('Checker for client %s (command "%s")'
218
' was killed by signal %s'
219
% (self.properties["Name"], command,
220
os.WTERMSIG(condition)))
194
self.logger('Checker for client {0} (command "{1}") was'
195
' killed by signal {2}'
196
.format(self.properties["Name"], command,
197
os.WTERMSIG(condition)))
221
198
elif os.WCOREDUMP(condition):
222
self.logger('Checker for client %s (command "%s")'
199
self.logger('Checker for client {0} (command "{1}")'
224
% (self.properties["Name"], command))
201
.format(self.properties["Name"], command))
226
self.logger('Checker for client %s completed'
203
self.logger('Checker for client {0} completed'
205
.format(self.properties["Name"]))
230
208
def checker_started(self, command):
231
209
"""Server signals that a checker started. This could be useful
232
210
to log in the future. """
233
#self.logger('Client %s started checker "%s"'
234
# % (self.properties["Name"], unicode(command)))
211
#self.logger('Client {0} started checker "{1}"'
212
# .format(self.properties["Name"],
237
216
def got_secret(self):
238
self.logger('Client %s received its secret'
239
% self.properties["Name"])
217
self.logger('Client {0} received its secret'
218
.format(self.properties["Name"]))
241
220
def need_approval(self, timeout, default):
243
message = 'Client %s needs approval within %s seconds'
222
message = 'Client {0} needs approval within {1} seconds'
245
message = 'Client %s will get its secret in %s seconds'
247
% (self.properties["Name"], timeout/1000))
248
self.using_timer(True)
224
message = 'Client {0} will get its secret in {1} seconds'
225
self.logger(message.format(self.properties["Name"],
250
228
def rejected(self, reason):
251
self.logger('Client %s was rejected; reason: %s'
252
% (self.properties["Name"], reason))
229
self.logger('Client {0} was rejected; reason: {1}'
230
.format(self.properties["Name"], reason))
254
232
def selectable(self):
255
233
"""Make this a "selectable" widget.
277
255
"bold-underline-blink":
278
256
"bold-underline-blink-standout",
281
259
# Rebuild focus and non-focus widgets using current properties
283
261
# Base part of a client. Name!
285
% {"name": self.properties["Name"]})
262
base = '{name}: '.format(name=self.properties["Name"])
286
263
if not self.properties["Enabled"]:
287
264
message = "DISABLED"
265
self.using_timer(False)
288
266
elif self.properties["ApprovalPending"]:
289
267
timeout = datetime.timedelta(milliseconds
290
268
= self.properties
292
270
last_approval_request = isoformat_to_datetime(
293
271
self.properties["LastApprovalRequest"])
294
272
if last_approval_request is not None:
295
timer = timeout - (datetime.datetime.utcnow()
296
- last_approval_request)
273
timer = max(timeout - (datetime.datetime.utcnow()
274
- last_approval_request),
275
datetime.timedelta())
298
277
timer = datetime.timedelta()
299
278
if self.properties["ApprovedByDefault"]:
300
message = "Approval in %s. (d)eny?"
279
message = "Approval in {0}. (d)eny?"
302
message = "Denial in %s. (a)pprove?"
303
message = message % unicode(timer).rsplit(".", 1)[0]
281
message = "Denial in {0}. (a)pprove?"
282
message = message.format(unicode(timer).rsplit(".", 1)[0])
283
self.using_timer(True)
304
284
elif self.properties["LastCheckerStatus"] != 0:
305
# When checker has failed, print a timer until client expires
285
# When checker has failed, show timer until client expires
306
286
expires = self.properties["Expires"]
307
287
if expires == "":
308
288
timer = datetime.timedelta(0)
310
expires = datetime.datetime.strptime(expires,
311
'%Y-%m-%dT%H:%M:%S.%f')
312
timer = expires - datetime.datetime.utcnow()
290
expires = (datetime.datetime.strptime
291
(expires, '%Y-%m-%dT%H:%M:%S.%f'))
292
timer = max(expires - datetime.datetime.utcnow(),
293
datetime.timedelta())
313
294
message = ('A checker has failed! Time until client'
315
% unicode(timer).rsplit(".", 1)[0])
295
' gets disabled: {0}'
296
.format(unicode(timer).rsplit(".", 1)[0]))
297
self.using_timer(True)
317
299
message = "enabled"
318
self._text = "%s%s" % (base, message)
300
self.using_timer(False)
301
self._text = "{0}{1}".format(base, message)
320
303
if not urwid.supports_unicode():
321
304
self._text = self._text.encode("ascii", "replace")
322
305
textlist = [("normal", self._text)]
399
def property_changed(self, property=None, value=None,
382
def property_changed(self, property=None, **kwargs):
401
383
"""Call self.update() if old value is not new value.
402
384
This overrides the method from MandosClientPropertyCache"""
403
385
property_name = unicode(property)
404
386
old_value = self.properties.get(property_name)
405
387
super(MandosClientWidget, self).property_changed(
406
property=property, value=value, *args, **kwargs)
388
property=property, **kwargs)
407
389
if self.properties.get(property_name) != old_value:
413
395
"down" key presses, thus not allowing any containing widgets to
414
396
use them as an excuse to shift focus away from this widget.
416
def keypress(self, maxcolrow, key):
417
ret = super(ConstrainedListBox, self).keypress(maxcolrow, key)
398
def keypress(self, *args, **kwargs):
399
ret = super(ConstrainedListBox, self).keypress(*args, **kwargs)
418
400
if ret in ("up", "down"):
486
468
self.main_loop = gobject.MainLoop()
488
470
def client_not_found(self, fingerprint, address):
489
self.log_message(("Client with address %s and fingerprint %s"
490
" could not be found" % (address,
471
self.log_message("Client with address {0} and fingerprint"
472
" {1} could not be found"
473
.format(address, fingerprint))
493
475
def rebuild(self):
494
476
"""This rebuilds the User Interface.