/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to mandos-monitor

  • Committer: Teddy Hogeborn
  • Date: 2012-05-06 16:13:00 UTC
  • Revision ID: teddy@recompile.se-20120506161300-43rls2rr4qub3zhw
* mandos: Use a class decorator instead of a metaclass to provide
          alternate D-Bus interface names on D-Bus object attributes.
  (alternate_dbus_interfaces): New class decorator.
  (AlternateDBusNamesMetaclass, ClientDBusTransitional,
   MandosDBusServiceTransitional): Removed; all users changed.
  (ClientDbus, MandosDBusService): Use new "alternate_dbus_interfaces"
                                   class decorator.

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
from __future__ import (division, absolute_import, print_function,
27
27
                        unicode_literals)
28
28
 
29
 
from future_builtins import *
30
 
 
31
29
import sys
32
30
import os
33
31
import signal
55
53
domain = 'se.recompile'
56
54
server_interface = domain + '.Mandos'
57
55
client_interface = domain + '.Mandos.Client'
58
 
version = "1.6.0"
 
56
version = "1.5.3"
59
57
 
60
58
# Always run in monochrome mode
61
59
urwid.curses_display.curses.has_colors = lambda : False
86
84
    properties and calls a hook function when any of them are
87
85
    changed.
88
86
    """
89
 
    def __init__(self, proxy_object=None, properties=None, **kwargs):
 
87
    def __init__(self, proxy_object=None, *args, **kwargs):
90
88
        self.proxy = proxy_object # Mandos Client proxy object
91
 
        self.properties = dict() if properties is None else properties
 
89
        
 
90
        self.properties = dict()
92
91
        self.property_changed_match = (
93
92
            self.proxy.connect_to_signal("PropertyChanged",
94
 
                                         self._property_changed,
 
93
                                         self.property_changed,
95
94
                                         client_interface,
96
95
                                         byte_arrays=True))
97
96
        
98
 
        if properties is None:
99
 
            self.properties.update(
100
 
                self.proxy.GetAll(client_interface,
101
 
                                  dbus_interface
102
 
                                  = dbus.PROPERTIES_IFACE))
103
 
        
104
 
        super(MandosClientPropertyCache, self).__init__(**kwargs)
105
 
    
106
 
    def _property_changed(self, property, value):
107
 
        """Helper which takes positional arguments"""
108
 
        return self.property_changed(property=property, value=value)
 
97
        self.properties.update(
 
98
            self.proxy.GetAll(client_interface,
 
99
                              dbus_interface = dbus.PROPERTIES_IFACE))
 
100
 
 
101
        #XXX This breaks good super behaviour
 
102
#        super(MandosClientPropertyCache, self).__init__(
 
103
#            *args, **kwargs)
109
104
    
110
105
    def property_changed(self, property=None, value=None):
111
106
        """This is called whenever we get a PropertyChanged signal
114
109
        # Update properties dict with new value
115
110
        self.properties[property] = value
116
111
    
117
 
    def delete(self):
 
112
    def delete(self, *args, **kwargs):
118
113
        self.property_changed_match.remove()
 
114
        super(MandosClientPropertyCache, self).__init__(
 
115
            *args, **kwargs)
119
116
 
120
117
 
121
118
class MandosClientWidget(urwid.FlowWidget, MandosClientPropertyCache):
123
120
    """
124
121
    
125
122
    def __init__(self, server_proxy_object=None, update_hook=None,
126
 
                 delete_hook=None, logger=None, **kwargs):
 
123
                 delete_hook=None, logger=None, *args, **kwargs):
127
124
        # Called on update
128
125
        self.update_hook = update_hook
129
126
        # Called on delete
134
131
        self.logger = logger
135
132
        
136
133
        self._update_timer_callback_tag = None
 
134
        self._update_timer_callback_lock = 0
137
135
        
138
136
        # The widget shown normally
139
137
        self._text_widget = urwid.Text("")
140
138
        # The widget shown when we have focus
141
139
        self._focus_text_widget = urwid.Text("")
142
 
        super(MandosClientWidget, self).__init__(**kwargs)
 
140
        super(MandosClientWidget, self).__init__(
 
141
            update_hook=update_hook, delete_hook=delete_hook,
 
142
            *args, **kwargs)
143
143
        self.update()
144
144
        self.opened = False
145
145
        
 
146
        last_checked_ok = isoformat_to_datetime(self.properties
 
147
                                                ["LastCheckedOK"])
 
148
        
 
149
        if self.properties ["LastCheckerStatus"] != 0:
 
150
            self.using_timer(True)
 
151
        
 
152
        if self.need_approval:
 
153
            self.using_timer(True)
 
154
        
146
155
        self.match_objects = (
147
156
            self.proxy.connect_to_signal("CheckerCompleted",
148
157
                                         self.checker_completed,
167
176
        #self.logger('Created client {0}'
168
177
        #            .format(self.properties["Name"]))
169
178
    
 
179
    def property_changed(self, property=None, value=None):
 
180
        super(self, MandosClientWidget).property_changed(property,
 
181
                                                         value)
 
182
        if property == "ApprovalPending":
 
183
            using_timer(bool(value))
 
184
        if property == "LastCheckerStatus":
 
185
            using_timer(value != 0)
 
186
            #self.logger('Checker for client {0} (command "{1}") was '
 
187
            #            ' successful'.format(self.properties["Name"],
 
188
            #                                 command))
 
189
    
170
190
    def using_timer(self, flag):
171
191
        """Call this method with True or False when timer should be
172
192
        activated or deactivated.
173
193
        """
174
 
        if flag and self._update_timer_callback_tag is None:
 
194
        old = self._update_timer_callback_lock
 
195
        if flag:
 
196
            self._update_timer_callback_lock += 1
 
197
        else:
 
198
            self._update_timer_callback_lock -= 1
 
199
        if old == 0 and self._update_timer_callback_lock:
175
200
            # Will update the shown timer value every second
176
201
            self._update_timer_callback_tag = (gobject.timeout_add
177
202
                                               (1000,
178
203
                                                self.update_timer))
179
 
        elif not (flag or self._update_timer_callback_tag is None):
 
204
        elif old and self._update_timer_callback_lock == 0:
180
205
            gobject.source_remove(self._update_timer_callback_tag)
181
206
            self._update_timer_callback_tag = None
182
207
    
224
249
            message = 'Client {0} will get its secret in {1} seconds'
225
250
        self.logger(message.format(self.properties["Name"],
226
251
                                   timeout/1000))
 
252
        self.using_timer(True)
227
253
    
228
254
    def rejected(self, reason):
229
255
        self.logger('Client {0} was rejected; reason: {1}'
255
281
                          "bold-underline-blink":
256
282
                              "bold-underline-blink-standout",
257
283
                          }
258
 
        
 
284
 
259
285
        # Rebuild focus and non-focus widgets using current properties
260
 
        
 
286
 
261
287
        # Base part of a client. Name!
262
288
        base = '{name}: '.format(name=self.properties["Name"])
263
289
        if not self.properties["Enabled"]:
264
290
            message = "DISABLED"
265
 
            self.using_timer(False)
266
291
        elif self.properties["ApprovalPending"]:
267
292
            timeout = datetime.timedelta(milliseconds
268
293
                                         = self.properties
270
295
            last_approval_request = isoformat_to_datetime(
271
296
                self.properties["LastApprovalRequest"])
272
297
            if last_approval_request is not None:
273
 
                timer = max(timeout - (datetime.datetime.utcnow()
274
 
                                       - last_approval_request),
275
 
                            datetime.timedelta())
 
298
                timer = timeout - (datetime.datetime.utcnow()
 
299
                                   - last_approval_request)
276
300
            else:
277
301
                timer = datetime.timedelta()
278
302
            if self.properties["ApprovedByDefault"]:
280
304
            else:
281
305
                message = "Denial in {0}. (a)pprove?"
282
306
            message = message.format(unicode(timer).rsplit(".", 1)[0])
283
 
            self.using_timer(True)
284
307
        elif self.properties["LastCheckerStatus"] != 0:
285
308
            # When checker has failed, show timer until client expires
286
309
            expires = self.properties["Expires"]
289
312
            else:
290
313
                expires = (datetime.datetime.strptime
291
314
                           (expires, '%Y-%m-%dT%H:%M:%S.%f'))
292
 
                timer = max(expires - datetime.datetime.utcnow(),
293
 
                            datetime.timedelta())
 
315
                timer = expires - datetime.datetime.utcnow()
294
316
            message = ('A checker has failed! Time until client'
295
317
                       ' gets disabled: {0}'
296
318
                       .format(unicode(timer).rsplit(".", 1)[0]))
297
 
            self.using_timer(True)
298
319
        else:
299
320
            message = "enabled"
300
 
            self.using_timer(False)
301
321
        self._text = "{0}{1}".format(base, message)
302
 
        
 
322
            
303
323
        if not urwid.supports_unicode():
304
324
            self._text = self._text.encode("ascii", "replace")
305
325
        textlist = [("normal", self._text)]
322
342
        self.update()
323
343
        return True             # Keep calling this
324
344
    
325
 
    def delete(self, **kwargs):
 
345
    def delete(self, *args, **kwargs):
326
346
        if self._update_timer_callback_tag is not None:
327
347
            gobject.source_remove(self._update_timer_callback_tag)
328
348
            self._update_timer_callback_tag = None
331
351
        self.match_objects = ()
332
352
        if self.delete_hook is not None:
333
353
            self.delete_hook(self)
334
 
        return super(MandosClientWidget, self).delete(**kwargs)
 
354
        return super(MandosClientWidget, self).delete(*args, **kwargs)
335
355
    
336
356
    def render(self, maxcolrow, focus=False):
337
357
        """Render differently if we have focus.
379
399
        else:
380
400
            return key
381
401
    
382
 
    def property_changed(self, property=None, **kwargs):
 
402
    def property_changed(self, property=None, value=None,
 
403
                         *args, **kwargs):
383
404
        """Call self.update() if old value is not new value.
384
405
        This overrides the method from MandosClientPropertyCache"""
385
406
        property_name = unicode(property)
386
407
        old_value = self.properties.get(property_name)
387
408
        super(MandosClientWidget, self).property_changed(
388
 
            property=property, **kwargs)
 
409
            property=property, value=value, *args, **kwargs)
389
410
        if self.properties.get(property_name) != old_value:
390
411
            self.update()
391
412
 
395
416
    "down" key presses, thus not allowing any containing widgets to
396
417
    use them as an excuse to shift focus away from this widget.
397
418
    """
398
 
    def keypress(self, *args, **kwargs):
399
 
        ret = super(ConstrainedListBox, self).keypress(*args, **kwargs)
 
419
    def keypress(self, maxcolrow, key):
 
420
        ret = super(ConstrainedListBox, self).keypress(maxcolrow, key)
400
421
        if ret in ("up", "down"):
401
422
            return
402
423
        return ret
617
638
                                               logger
618
639
                                               =self.log_message),
619
640
                            path=path)
620
 
        
 
641
 
621
642
        self.refresh()
622
643
        self._input_callback_tag = (gobject.io_add_watch
623
644
                                    (sys.stdin.fileno(),