/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release
237.7.733 by Teddy Hogeborn
Add -I option to python 3 on the interpreter script ("shebang") line
1
#!/usr/bin/python3 -bbI
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
2
# -*- mode: python; coding: utf-8 -*-
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
3
#
237.2.207 by Teddy Hogeborn
Update copyright year to "2010" wherever appropriate.
4
# Mandos Monitor - Control and monitor the Mandos server
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
5
#
237.7.517 by Teddy Hogeborn
Update copyright year to 2019
6
# Copyright © 2009-2019 Teddy Hogeborn
7
# Copyright © 2009-2019 Björn Påhlsson
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
8
#
237.7.455 by Teddy Hogeborn
Alter copyright notices slightly. Actual license is unchanged!
9
# This file is part of Mandos.
10
#
11
# Mandos is free software: you can redistribute it and/or modify it
12
# under the terms of the GNU General Public License as published by
237.2.207 by Teddy Hogeborn
Update copyright year to "2010" wherever appropriate.
13
# the Free Software Foundation, either version 3 of the License, or
14
# (at your option) any later version.
15
#
237.7.455 by Teddy Hogeborn
Alter copyright notices slightly. Actual license is unchanged!
16
#     Mandos is distributed in the hope that it will be useful, but
17
#     WITHOUT ANY WARRANTY; without even the implied warranty of
237.2.207 by Teddy Hogeborn
Update copyright year to "2010" wherever appropriate.
18
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
#     GNU General Public License for more details.
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
20
#
237.2.207 by Teddy Hogeborn
Update copyright year to "2010" wherever appropriate.
21
# You should have received a copy of the GNU General Public License
237.7.455 by Teddy Hogeborn
Alter copyright notices slightly. Actual license is unchanged!
22
# along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
23
#
237.11.2 by Teddy Hogeborn
Change "fukt.bsnet.se" to "recompile.se" throughout.
24
# Contact the authors at <mandos@recompile.se>.
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
25
#
237.7.36 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
26
from __future__ import (division, absolute_import, print_function,
27
                        unicode_literals)
237.7.801 by Teddy Hogeborn
mandos-monitor: Update boilerplate code
28
237.7.165 by Teddy Hogeborn
* mandos: Bug fix: Don't print output from checkers when running in
29
try:
30
    from future_builtins import *
31
except ImportError:
32
    pass
237.7.127 by Teddy Hogeborn
* mandos: Use all new builtins.
33
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
34
import sys
237.7.801 by Teddy Hogeborn
mandos-monitor: Update boilerplate code
35
import logging
237.2.172 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
36
import os
237.7.722 by Teddy Hogeborn
Address Python 3 bytes/str warnings
37
import warnings
237.2.172 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
38
import datetime
237.7.732 by Teddy Hogeborn
mandos-monitor: Formatting changes only
39
import locale
237.2.172 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
40
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
41
import urwid.curses_display
42
import urwid
43
44
from dbus.mainloop.glib import DBusGMainLoop
237.7.378 by Teddy Hogeborn
Server: Use python-gi instead of old python-gobject
45
from gi.repository import GLib
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
46
47
import dbus
48
237.23.7 by Teddy Hogeborn
Use the .major attribute on sys.version_info instead of using "[0]".
49
if sys.version_info.major == 2:
237.7.740 by teddy at recompile
Simplification of Python 3 compatibility code
50
    __metaclass__ = type
237.7.165 by Teddy Hogeborn
* mandos: Bug fix: Don't print output from checkers when running in
51
    str = unicode
237.7.801 by Teddy Hogeborn
mandos-monitor: Update boilerplate code
52
    input = raw_input
53
54
# Show warnings by default
55
if not sys.warnoptions:
56
    warnings.simplefilter("default")
237.7.165 by Teddy Hogeborn
* mandos: Bug fix: Don't print output from checkers when running in
57
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
58
log = logging.getLogger(os.path.basename(sys.argv[0]))
59
logging.basicConfig(level="NOTSET", # Show all messages
60
                    format="%(message)s") # Show basic log messages
61
62
logging.captureWarnings(True)   # Show warnings via the logging system
63
237.7.732 by Teddy Hogeborn
mandos-monitor: Formatting changes only
64
locale.setlocale(locale.LC_ALL, "")
237.2.174 by Teddy Hogeborn
More consistent terminology: Clients are no longer "invalid" - they
65
237.7.732 by Teddy Hogeborn
mandos-monitor: Formatting changes only
66
logging.getLogger("dbus.proxies").setLevel(logging.CRITICAL)
237.7.861 by Teddy Hogeborn
mandos-monitor: Avoid debug messages from urwid
67
logging.getLogger("urwid").setLevel(logging.INFO)
24.1.153 by Björn Påhlsson
early commit to ease todays coding
68
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
69
# Some useful constants
237.7.732 by Teddy Hogeborn
mandos-monitor: Formatting changes only
70
domain = "se.recompile"
71
server_interface = domain + ".Mandos"
72
client_interface = domain + ".Mandos.Client"
411 by Teddy Hogeborn
Version 1.8.17-1
73
version = "1.8.17"
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
74
237.7.333 by Teddy Hogeborn
Support the standard org.freedesktop.DBus.ObjectManager interface.
75
try:
76
    dbus.OBJECT_MANAGER_IFACE
77
except AttributeError:
78
    dbus.OBJECT_MANAGER_IFACE = "org.freedesktop.DBus.ObjectManager"
79
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
80
237.2.180 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
81
def isoformat_to_datetime(iso):
82
    "Parse an ISO 8601 date string to a datetime.datetime()"
83
    if not iso:
84
        return None
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
85
    d, t = iso.split("T", 1)
86
    year, month, day = d.split("-", 2)
87
    hour, minute, second = t.split(":", 2)
237.2.180 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
88
    second, fraction = divmod(float(second), 1)
89
    return datetime.datetime(int(year),
90
                             int(month),
91
                             int(day),
92
                             int(hour),
93
                             int(minute),
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
94
                             int(second),            # Whole seconds
95
                             int(fraction*1000000))  # Microseconds
96
237.2.180 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
97
237.7.740 by teddy at recompile
Simplification of Python 3 compatibility code
98
class MandosClientPropertyCache:
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
99
    """This wraps a Mandos Client D-Bus proxy object, caches the
100
    properties and calls a hook function when any of them are
101
    changed.
102
    """
237.7.128 by Teddy Hogeborn
* mandos-monitor: Speedup: Use properties from D-Bus
103
    def __init__(self, proxy_object=None, properties=None, **kwargs):
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
104
        self.proxy = proxy_object  # Mandos Client proxy object
237.7.128 by Teddy Hogeborn
* mandos-monitor: Speedup: Use properties from D-Bus
105
        self.properties = dict() if properties is None else properties
237.7.36 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
106
        self.property_changed_match = (
237.7.280 by Teddy Hogeborn
Emit D-Bus "org.freedesktop.DBus.Properties.PropertiesChanged" signal.
107
            self.proxy.connect_to_signal("PropertiesChanged",
108
                                         self.properties_changed,
109
                                         dbus.PROPERTIES_IFACE,
237.7.36 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
110
                                         byte_arrays=True))
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
111
237.7.128 by Teddy Hogeborn
* mandos-monitor: Speedup: Use properties from D-Bus
112
        if properties is None:
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
113
            self.properties.update(self.proxy.GetAll(
114
                client_interface,
115
                dbus_interface=dbus.PROPERTIES_IFACE))
116
237.7.128 by Teddy Hogeborn
* mandos-monitor: Speedup: Use properties from D-Bus
117
        super(MandosClientPropertyCache, self).__init__(**kwargs)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
118
237.7.280 by Teddy Hogeborn
Emit D-Bus "org.freedesktop.DBus.Properties.PropertiesChanged" signal.
119
    def properties_changed(self, interface, properties, invalidated):
120
        """This is called whenever we get a PropertiesChanged signal
121
        It updates the changed properties in the "properties" dict.
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
122
        """
123
        # Update properties dict with new value
237.7.333 by Teddy Hogeborn
Support the standard org.freedesktop.DBus.ObjectManager interface.
124
        if interface == client_interface:
125
            self.properties.update(properties)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
126
237.7.128 by Teddy Hogeborn
* mandos-monitor: Speedup: Use properties from D-Bus
127
    def delete(self):
237.7.36 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
128
        self.property_changed_match.remove()
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
129
130
131
class MandosClientWidget(urwid.FlowWidget, MandosClientPropertyCache):
132
    """A Mandos Client which is visible on the screen.
133
    """
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
134
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
135
    def __init__(self, server_proxy_object=None, update_hook=None,
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
136
                 delete_hook=None, **kwargs):
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
137
        # Called on update
138
        self.update_hook = update_hook
139
        # Called on delete
140
        self.delete_hook = delete_hook
141
        # Mandos Server proxy object
142
        self.server_proxy_object = server_proxy_object
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
143
237.2.180 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
144
        self._update_timer_callback_tag = None
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
145
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
146
        # The widget shown normally
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
147
        self._text_widget = urwid.Text("")
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
148
        # The widget shown when we have focus
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
149
        self._focus_text_widget = urwid.Text("")
237.7.128 by Teddy Hogeborn
* mandos-monitor: Speedup: Use properties from D-Bus
150
        super(MandosClientWidget, self).__init__(**kwargs)
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
151
        self.update()
152
        self.opened = False
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
153
237.7.36 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
154
        self.match_objects = (
155
            self.proxy.connect_to_signal("CheckerCompleted",
156
                                         self.checker_completed,
157
                                         client_interface,
158
                                         byte_arrays=True),
159
            self.proxy.connect_to_signal("CheckerStarted",
160
                                         self.checker_started,
161
                                         client_interface,
162
                                         byte_arrays=True),
163
            self.proxy.connect_to_signal("GotSecret",
164
                                         self.got_secret,
165
                                         client_interface,
166
                                         byte_arrays=True),
167
            self.proxy.connect_to_signal("NeedApproval",
168
                                         self.need_approval,
169
                                         client_interface,
170
                                         byte_arrays=True),
171
            self.proxy.connect_to_signal("Rejected",
172
                                         self.rejected,
173
                                         client_interface,
174
                                         byte_arrays=True))
237.7.732 by Teddy Hogeborn
mandos-monitor: Formatting changes only
175
        log.debug("Created client %s", self.properties["Name"])
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
176
237.2.205 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
177
    def using_timer(self, flag):
178
        """Call this method with True or False when timer should be
179
        activated or deactivated.
180
        """
237.7.129 by Teddy Hogeborn
* mandos (Client.enable, Client.disable, ClientDBus.approve): Call
181
        if flag and self._update_timer_callback_tag is None:
24.1.179 by Björn Påhlsson
New feature:
182
            # Will update the shown timer value every second
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
183
            self._update_timer_callback_tag = (
184
                GLib.timeout_add(1000,
185
                                 glib_safely(self.update_timer)))
237.7.129 by Teddy Hogeborn
* mandos (Client.enable, Client.disable, ClientDBus.approve): Call
186
        elif not (flag or self._update_timer_callback_tag is None):
237.7.378 by Teddy Hogeborn
Server: Use python-gi instead of old python-gobject
187
            GLib.source_remove(self._update_timer_callback_tag)
237.2.205 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
188
            self._update_timer_callback_tag = None
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
189
237.7.331 by Teddy Hogeborn
Revert change to D-Bus API.
190
    def checker_completed(self, exitstatus, condition, command):
237.2.172 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
191
        if exitstatus == 0:
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
192
            log.debug('Checker for client %s (command "%s")'
237.7.732 by Teddy Hogeborn
mandos-monitor: Formatting changes only
193
                      " succeeded", self.properties["Name"], command)
237.2.180 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
194
            self.update()
237.2.172 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
195
            return
237.2.180 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
196
        # Checker failed
237.7.331 by Teddy Hogeborn
Revert change to D-Bus API.
197
        if os.WIFEXITED(condition):
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
198
            log.info('Checker for client %s (command "%s") failed'
237.7.732 by Teddy Hogeborn
mandos-monitor: Formatting changes only
199
                     " with exit code %d", self.properties["Name"],
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
200
                     command, os.WEXITSTATUS(condition))
237.7.331 by Teddy Hogeborn
Revert change to D-Bus API.
201
        elif os.WIFSIGNALED(condition):
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
202
            log.info('Checker for client %s (command "%s") was'
237.7.732 by Teddy Hogeborn
mandos-monitor: Formatting changes only
203
                     " killed by signal %d", self.properties["Name"],
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
204
                     command, os.WTERMSIG(condition))
237.2.180 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
205
        self.update()
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
206
237.2.172 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
207
    def checker_started(self, command):
237.7.261 by Teddy Hogeborn
mandos-monitor: New "verbose" mode to see less important log messages.
208
        """Server signals that a checker started."""
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
209
        log.debug('Client %s started checker "%s"',
210
                  self.properties["Name"], command)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
211
237.2.172 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
212
    def got_secret(self):
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
213
        log.info("Client %s received its secret",
214
                 self.properties["Name"])
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
215
24.1.153 by Björn Påhlsson
early commit to ease todays coding
216
    def need_approval(self, timeout, default):
217
        if not default:
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
218
            message = "Client %s needs approval within %f seconds"
24.1.153 by Björn Påhlsson
early commit to ease todays coding
219
        else:
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
220
            message = "Client %s will get its secret in %f seconds"
221
        log.info(message, self.properties["Name"], timeout/1000)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
222
24.1.153 by Björn Påhlsson
early commit to ease todays coding
223
    def rejected(self, reason):
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
224
        log.info("Client %s was rejected; reason: %s",
225
                 self.properties["Name"], reason)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
226
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
227
    def selectable(self):
228
        """Make this a "selectable" widget.
229
        This overrides the method from urwid.FlowWidget."""
230
        return True
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
231
237.8.1 by teddy at bsnet
* mandos-monitor: Use only unicode string literals.
232
    def rows(self, maxcolrow, focus=False):
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
233
        """How many rows this widget will occupy might depend on
234
        whether we have focus or not.
235
        This overrides the method from urwid.FlowWidget"""
237.8.1 by teddy at bsnet
* mandos-monitor: Use only unicode string literals.
236
        return self.current_widget(focus).rows(maxcolrow, focus=focus)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
237
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
238
    def current_widget(self, focus=False):
239
        if focus or self.opened:
240
            return self._focus_widget
241
        return self._widget
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
242
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
243
    def update(self):
244
        "Called when what is visible on the screen should be updated."
245
        # How to add standout mode to a style
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
246
        with_standout = {"normal": "standout",
247
                         "bold": "bold-standout",
248
                         "underline-blink":
249
                         "underline-blink-standout",
250
                         "bold-underline-blink":
251
                         "bold-underline-blink-standout",
252
                         }
253
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
254
        # Rebuild focus and non-focus widgets using current properties
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
255
24.1.154 by Björn Påhlsson
merge
256
        # Base part of a client. Name!
237.7.732 by Teddy Hogeborn
mandos-monitor: Formatting changes only
257
        base = "{name}: ".format(name=self.properties["Name"])
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
258
        if not self.properties["Enabled"]:
259
            message = "DISABLED"
237.7.129 by Teddy Hogeborn
* mandos (Client.enable, Client.disable, ClientDBus.approve): Call
260
            self.using_timer(False)
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
261
        elif self.properties["ApprovalPending"]:
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
262
            timeout = datetime.timedelta(
263
                milliseconds=self.properties["ApprovalDelay"])
237.2.205 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
264
            last_approval_request = isoformat_to_datetime(
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
265
                self.properties["LastApprovalRequest"])
237.2.205 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
266
            if last_approval_request is not None:
237.7.129 by Teddy Hogeborn
* mandos (Client.enable, Client.disable, ClientDBus.approve): Call
267
                timer = max(timeout - (datetime.datetime.utcnow()
268
                                       - last_approval_request),
269
                            datetime.timedelta())
237.2.205 by Teddy Hogeborn
* DBUS-API: Document new "LastApprovalRequest" client property.
270
            else:
271
                timer = datetime.timedelta()
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
272
            if self.properties["ApprovedByDefault"]:
237.23.5 by Teddy Hogeborn
Use the new auto-numbered "{}" syntax for the .format() string method.
273
                message = "Approval in {}. (d)eny?"
24.1.159 by Björn Påhlsson
added approval to mandos-ctl
274
            else:
237.23.5 by Teddy Hogeborn
Use the new auto-numbered "{}" syntax for the .format() string method.
275
                message = "Denial in {}. (a)pprove?"
237.7.165 by Teddy Hogeborn
* mandos: Bug fix: Don't print output from checkers when running in
276
            message = message.format(str(timer).rsplit(".", 1)[0])
237.7.129 by Teddy Hogeborn
* mandos (Client.enable, Client.disable, ClientDBus.approve): Call
277
            self.using_timer(True)
237.7.105 by Teddy Hogeborn
Use the new Client.LastCheckerStatus property.
278
        elif self.properties["LastCheckerStatus"] != 0:
237.7.120 by Teddy Hogeborn
* mandos-ctl: Break long lines.
279
            # When checker has failed, show timer until client expires
24.1.179 by Björn Påhlsson
New feature:
280
            expires = self.properties["Expires"]
281
            if expires == "":
282
                timer = datetime.timedelta(0)
283
            else:
237.7.120 by Teddy Hogeborn
* mandos-ctl: Break long lines.
284
                expires = (datetime.datetime.strptime
237.7.732 by Teddy Hogeborn
mandos-monitor: Formatting changes only
285
                           (expires, "%Y-%m-%dT%H:%M:%S.%f"))
237.7.129 by Teddy Hogeborn
* mandos (Client.enable, Client.disable, ClientDBus.approve): Call
286
                timer = max(expires - datetime.datetime.utcnow(),
287
                            datetime.timedelta())
237.7.732 by Teddy Hogeborn
mandos-monitor: Formatting changes only
288
            message = ("A checker has failed! Time until client"
289
                       " gets disabled: {}"
237.7.165 by Teddy Hogeborn
* mandos: Bug fix: Don't print output from checkers when running in
290
                       .format(str(timer).rsplit(".", 1)[0]))
237.7.129 by Teddy Hogeborn
* mandos (Client.enable, Client.disable, ClientDBus.approve): Call
291
            self.using_timer(True)
24.1.154 by Björn Påhlsson
merge
292
        else:
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
293
            message = "enabled"
237.7.129 by Teddy Hogeborn
* mandos (Client.enable, Client.disable, ClientDBus.approve): Call
294
            self.using_timer(False)
237.23.5 by Teddy Hogeborn
Use the new auto-numbered "{}" syntax for the .format() string method.
295
        self._text = "{}{}".format(base, message)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
296
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
297
        if not urwid.supports_unicode():
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
298
            self._text = self._text.encode("ascii", "replace")
299
        textlist = [("normal", self._text)]
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
300
        self._text_widget.set_text(textlist)
301
        self._focus_text_widget.set_text([(with_standout[text[0]],
302
                                           text[1])
303
                                          if isinstance(text, tuple)
304
                                          else text
305
                                          for text in textlist])
306
        self._widget = self._text_widget
307
        self._focus_widget = urwid.AttrWrap(self._focus_text_widget,
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
308
                                            "standout")
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
309
        # Run update hook, if any
310
        if self.update_hook is not None:
311
            self.update_hook()
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
312
237.2.180 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
313
    def update_timer(self):
237.7.378 by Teddy Hogeborn
Server: Use python-gi instead of old python-gobject
314
        """called by GLib. Will indefinitely loop until
315
        GLib.source_remove() on tag is called
316
        """
237.2.180 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
317
        self.update()
318
        return True             # Keep calling this
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
319
237.7.128 by Teddy Hogeborn
* mandos-monitor: Speedup: Use properties from D-Bus
320
    def delete(self, **kwargs):
237.2.180 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
321
        if self._update_timer_callback_tag is not None:
237.7.378 by Teddy Hogeborn
Server: Use python-gi instead of old python-gobject
322
            GLib.source_remove(self._update_timer_callback_tag)
237.2.180 by Teddy Hogeborn
* mandos (AvahiService.entry_group_state_changed): Better debug log
323
            self._update_timer_callback_tag = None
237.7.36 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
324
        for match in self.match_objects:
325
            match.remove()
326
        self.match_objects = ()
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
327
        if self.delete_hook is not None:
328
            self.delete_hook(self)
237.7.128 by Teddy Hogeborn
* mandos-monitor: Speedup: Use properties from D-Bus
329
        return super(MandosClientWidget, self).delete(**kwargs)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
330
237.8.1 by teddy at bsnet
* mandos-monitor: Use only unicode string literals.
331
    def render(self, maxcolrow, focus=False):
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
332
        """Render differently if we have focus.
333
        This overrides the method from urwid.FlowWidget"""
237.8.1 by teddy at bsnet
* mandos-monitor: Use only unicode string literals.
334
        return self.current_widget(focus).render(maxcolrow,
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
335
                                                 focus=focus)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
336
237.8.1 by teddy at bsnet
* mandos-monitor: Use only unicode string literals.
337
    def keypress(self, maxcolrow, key):
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
338
        """Handle keys.
339
        This overrides the method from urwid.FlowWidget"""
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
340
        if key == "+":
237.7.329 by Teddy Hogeborn
Deprecate some D-Bus methods in favor of D-Bus properties.
341
            self.proxy.Set(client_interface, "Enabled",
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
342
                           dbus.Boolean(True), ignore_reply=True,
343
                           dbus_interface=dbus.PROPERTIES_IFACE)
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
344
        elif key == "-":
237.7.329 by Teddy Hogeborn
Deprecate some D-Bus methods in favor of D-Bus properties.
345
            self.proxy.Set(client_interface, "Enabled", False,
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
346
                           ignore_reply=True,
347
                           dbus_interface=dbus.PROPERTIES_IFACE)
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
348
        elif key == "a":
24.1.154 by Björn Påhlsson
merge
349
            self.proxy.Approve(dbus.Boolean(True, variant_level=1),
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
350
                               dbus_interface=client_interface,
237.7.30 by Teddy Hogeborn
* mandos: Tolerate restarting Avahi servers. Also Changed to new
351
                               ignore_reply=True)
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
352
        elif key == "d":
24.1.154 by Björn Påhlsson
merge
353
            self.proxy.Approve(dbus.Boolean(False, variant_level=1),
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
354
                               dbus_interface=client_interface,
237.7.30 by Teddy Hogeborn
* mandos: Tolerate restarting Avahi servers. Also Changed to new
355
                               ignore_reply=True)
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
356
        elif key == "R" or key == "_" or key == "ctrl k":
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
357
            self.server_proxy_object.RemoveClient(self.proxy
237.7.30 by Teddy Hogeborn
* mandos: Tolerate restarting Avahi servers. Also Changed to new
358
                                                  .object_path,
359
                                                  ignore_reply=True)
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
360
        elif key == "s":
237.7.329 by Teddy Hogeborn
Deprecate some D-Bus methods in favor of D-Bus properties.
361
            self.proxy.Set(client_interface, "CheckerRunning",
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
362
                           dbus.Boolean(True), ignore_reply=True,
363
                           dbus_interface=dbus.PROPERTIES_IFACE)
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
364
        elif key == "S":
237.7.329 by Teddy Hogeborn
Deprecate some D-Bus methods in favor of D-Bus properties.
365
            self.proxy.Set(client_interface, "CheckerRunning",
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
366
                           dbus.Boolean(False), ignore_reply=True,
367
                           dbus_interface=dbus.PROPERTIES_IFACE)
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
368
        elif key == "C":
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
369
            self.proxy.CheckedOK(dbus_interface=client_interface,
237.7.30 by Teddy Hogeborn
* mandos: Tolerate restarting Avahi servers. Also Changed to new
370
                                 ignore_reply=True)
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
371
        # xxx
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
372
#         elif key == "p" or key == "=":
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
373
#             self.proxy.pause()
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
374
#         elif key == "u" or key == ":":
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
375
#             self.proxy.unpause()
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
376
#         elif key == "RET":
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
377
#             self.open()
378
        else:
379
            return key
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
380
237.7.280 by Teddy Hogeborn
Emit D-Bus "org.freedesktop.DBus.Properties.PropertiesChanged" signal.
381
    def properties_changed(self, interface, properties, invalidated):
382
        """Call self.update() if any properties changed.
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
383
        This overrides the method from MandosClientPropertyCache"""
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
384
        old_values = {key: self.properties.get(key)
385
                      for key in properties.keys()}
237.7.280 by Teddy Hogeborn
Emit D-Bus "org.freedesktop.DBus.Properties.PropertiesChanged" signal.
386
        super(MandosClientWidget, self).properties_changed(
387
            interface, properties, invalidated)
388
        if any(old_values[key] != self.properties.get(key)
389
               for key in old_values):
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
390
            self.update()
391
392
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
393
def glib_safely(func, retval=True):
394
    def safe_func(*args, **kwargs):
395
        try:
396
            return func(*args, **kwargs)
397
        except Exception:
398
            log.exception("")
399
            return retval
400
    return safe_func
401
402
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
403
class ConstrainedListBox(urwid.ListBox):
404
    """Like a normal urwid.ListBox, but will consume all "up" or
405
    "down" key presses, thus not allowing any containing widgets to
406
    use them as an excuse to shift focus away from this widget.
407
    """
237.7.128 by Teddy Hogeborn
* mandos-monitor: Speedup: Use properties from D-Bus
408
    def keypress(self, *args, **kwargs):
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
409
        ret = (super(ConstrainedListBox, self)
410
               .keypress(*args, **kwargs))
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
411
        if ret in ("up", "down"):
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
412
            return
413
        return ret
414
415
237.7.740 by teddy at recompile
Simplification of Python 3 compatibility code
416
class UserInterface:
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
417
    """This is the entire user interface - the whole screen
418
    with boxes, lists of client widgets, etc.
419
    """
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
420
    def __init__(self, max_log_length=1000):
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
421
        DBusGMainLoop(set_as_default=True)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
422
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
423
        self.screen = urwid.curses_display.Screen()
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
424
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
425
        self.screen.register_palette((
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
426
                ("normal",
427
                 "default", "default", None),
428
                ("bold",
237.7.165 by Teddy Hogeborn
* mandos: Bug fix: Don't print output from checkers when running in
429
                 "bold", "default", "bold"),
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
430
                ("underline-blink",
237.7.165 by Teddy Hogeborn
* mandos: Bug fix: Don't print output from checkers when running in
431
                 "underline,blink", "default", "underline,blink"),
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
432
                ("standout",
237.7.165 by Teddy Hogeborn
* mandos: Bug fix: Don't print output from checkers when running in
433
                 "standout", "default", "standout"),
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
434
                ("bold-underline-blink",
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
435
                 "bold,underline,blink", "default",
436
                 "bold,underline,blink"),
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
437
                ("bold-standout",
237.7.165 by Teddy Hogeborn
* mandos: Bug fix: Don't print output from checkers when running in
438
                 "bold,standout", "default", "bold,standout"),
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
439
                ("underline-blink-standout",
237.7.165 by Teddy Hogeborn
* mandos: Bug fix: Don't print output from checkers when running in
440
                 "underline,blink,standout", "default",
441
                 "underline,blink,standout"),
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
442
                ("bold-underline-blink-standout",
237.7.165 by Teddy Hogeborn
* mandos: Bug fix: Don't print output from checkers when running in
443
                 "bold,underline,blink,standout", "default",
444
                 "bold,underline,blink,standout"),
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
445
                ))
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
446
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
447
        if urwid.supports_unicode():
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
448
            self.divider = "─"  # \u2500
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
449
        else:
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
450
            self.divider = "_"  # \u005f
451
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
452
        self.screen.start()
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
453
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
454
        self.size = self.screen.get_cols_rows()
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
455
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
456
        self.clients = urwid.SimpleListWalker([])
457
        self.clients_dict = {}
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
458
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
459
        # We will add Text widgets to this list
237.7.516 by Teddy Hogeborn
Do minor fix to make mandos-monitor work with new python-urwid
460
        self.log = urwid.SimpleListWalker([])
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
461
        self.max_log_length = max_log_length
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
462
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
463
        # We keep a reference to the log widget so we can remove it
464
        # from the ListWalker without it getting destroyed
465
        self.logbox = ConstrainedListBox(self.log)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
466
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
467
        # This keeps track of whether self.uilist currently has
468
        # self.logbox in it or not
469
        self.log_visible = True
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
470
        self.log_wrap = "any"
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
471
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
472
        self.loghandler = UILogHandler(self)
473
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
474
        self.rebuild()
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
475
        self.add_log_line(("bold",
476
                           "Mandos Monitor version " + version))
477
        self.add_log_line(("bold", "q: Quit  ?: Help"))
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
478
237.7.732 by Teddy Hogeborn
mandos-monitor: Formatting changes only
479
        self.busname = domain + ".Mandos"
237.7.378 by Teddy Hogeborn
Server: Use python-gi instead of old python-gobject
480
        self.main_loop = GLib.MainLoop()
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
481
237.7.723 by Teddy Hogeborn
mandos-monitor: Update message from "fingerprint" to "key ID"
482
    def client_not_found(self, key_id, address):
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
483
        log.info("Client with address %s and key ID %s could"
484
                 " not be found", address, key_id)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
485
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
486
    def rebuild(self):
487
        """This rebuilds the User Interface.
488
        Call this when the widget layout needs to change"""
489
        self.uilist = []
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
490
        # self.uilist.append(urwid.ListBox(self.clients))
237.2.185 by Teddy Hogeborn
Rename all D-Bus properties to conform to D-Bus naming conventions;
491
        self.uilist.append(urwid.Frame(ConstrainedListBox(self.
492
                                                          clients),
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
493
                                       # header=urwid.Divider(),
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
494
                                       header=None,
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
495
                                       footer=urwid.Divider(
496
                                           div_char=self.divider)))
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
497
        if self.log_visible:
498
            self.uilist.append(self.logbox)
499
        self.topwidget = urwid.Pile(self.uilist)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
500
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
501
    def add_log_line(self, markup):
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
502
        self.log.append(urwid.Text(markup, wrap=self.log_wrap))
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
503
        if self.max_log_length:
504
            if len(self.log) > self.max_log_length:
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
505
                del self.log[0:(len(self.log) - self.max_log_length)]
237.7.516 by Teddy Hogeborn
Do minor fix to make mandos-monitor work with new python-urwid
506
        self.logbox.set_focus(len(self.logbox.body.contents)-1,
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
507
                              coming_from="above")
237.2.172 by Teddy Hogeborn
* mandos (MandosServer.handle_ipc): Better log message.
508
        self.refresh()
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
509
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
510
    def toggle_log_display(self):
511
        """Toggle visibility of the log buffer."""
512
        self.log_visible = not self.log_visible
513
        self.rebuild()
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
514
        log.debug("Log visibility changed to: %s", self.log_visible)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
515
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
516
    def change_log_display(self):
517
        """Change type of log display.
518
        Currently, this toggles wrapping of text lines."""
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
519
        if self.log_wrap == "clip":
520
            self.log_wrap = "any"
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
521
        else:
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
522
            self.log_wrap = "clip"
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
523
        for textwidget in self.log:
524
            textwidget.set_wrap_mode(self.log_wrap)
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
525
        log.debug("Wrap mode: %s", self.log_wrap)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
526
237.7.333 by Teddy Hogeborn
Support the standard org.freedesktop.DBus.ObjectManager interface.
527
    def find_and_remove_client(self, path, interfaces):
237.7.36 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
528
        """Find a client by its object path and remove it.
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
529
237.7.333 by Teddy Hogeborn
Support the standard org.freedesktop.DBus.ObjectManager interface.
530
        This is connected to the InterfacesRemoved signal from the
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
531
        Mandos server object."""
237.7.333 by Teddy Hogeborn
Support the standard org.freedesktop.DBus.ObjectManager interface.
532
        if client_interface not in interfaces:
533
            # Not a Mandos client object; ignore
534
            return
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
535
        try:
536
            client = self.clients_dict[path]
537
        except KeyError:
538
            # not found?
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
539
            log.warning("Unknown client %s removed", path)
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
540
            return
237.7.36 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Save match tag for
541
        client.delete()
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
542
237.7.333 by Teddy Hogeborn
Support the standard org.freedesktop.DBus.ObjectManager interface.
543
    def add_new_client(self, path, ifs_and_props):
544
        """Find a client by its object path and remove it.
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
545
237.7.333 by Teddy Hogeborn
Support the standard org.freedesktop.DBus.ObjectManager interface.
546
        This is connected to the InterfacesAdded signal from the
547
        Mandos server object.
548
        """
549
        if client_interface not in ifs_and_props:
550
            # Not a Mandos client object; ignore
551
            return
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
552
        client_proxy_object = self.bus.get_object(self.busname, path)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
553
        self.add_client(MandosClientWidget(
554
            server_proxy_object=self.mandos_serv,
555
            proxy_object=client_proxy_object,
556
            update_hook=self.refresh,
557
            delete_hook=self.remove_client,
558
            properties=dict(ifs_and_props[client_interface])),
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
559
                        path=path)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
560
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
561
    def add_client(self, client, path=None):
562
        self.clients.append(client)
563
        if path is None:
564
            path = client.proxy.object_path
565
        self.clients_dict[path] = client
237.7.165 by Teddy Hogeborn
* mandos: Bug fix: Don't print output from checkers when running in
566
        self.clients.sort(key=lambda c: c.properties["Name"])
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
567
        self.refresh()
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
568
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
569
    def remove_client(self, client, path=None):
570
        self.clients.remove(client)
571
        if path is None:
572
            path = client.proxy.object_path
573
        del self.clients_dict[path]
574
        self.refresh()
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
575
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
576
    def refresh(self):
577
        """Redraw the screen"""
578
        canvas = self.topwidget.render(self.size, focus=True)
579
        self.screen.draw_screen(self.size, canvas)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
580
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
581
    def run(self):
582
        """Start the main loop and exit when it's done."""
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
583
        log.addHandler(self.loghandler)
584
        self.orig_log_propagate = log.propagate
585
        log.propagate = False
586
        self.orig_log_level = log.level
587
        log.setLevel("INFO")
237.7.85 by Björn Påhlsson
nicer stacktrace when mandos-monitor fail during startup
588
        self.bus = dbus.SystemBus()
589
        mandos_dbus_objc = self.bus.get_object(
590
            self.busname, "/", follow_name_owner_changes=True)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
591
        self.mandos_serv = dbus.Interface(
592
            mandos_dbus_objc, dbus_interface=server_interface)
237.7.85 by Björn Påhlsson
nicer stacktrace when mandos-monitor fail during startup
593
        try:
594
            mandos_clients = (self.mandos_serv
595
                              .GetAllClientsWithProperties())
237.7.160 by Björn Påhlsson
added note messages when mandos-monitor starts without running server,
596
            if not mandos_clients:
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
597
                log.warning("Note: Server has no clients.")
237.7.85 by Björn Påhlsson
nicer stacktrace when mandos-monitor fail during startup
598
        except dbus.exceptions.DBusException:
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
599
            log.warning("Note: No Mandos server running.")
237.7.85 by Björn Påhlsson
nicer stacktrace when mandos-monitor fail during startup
600
            mandos_clients = dbus.Dictionary()
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
601
237.7.85 by Björn Påhlsson
nicer stacktrace when mandos-monitor fail during startup
602
        (self.mandos_serv
237.7.333 by Teddy Hogeborn
Support the standard org.freedesktop.DBus.ObjectManager interface.
603
         .connect_to_signal("InterfacesRemoved",
237.7.85 by Björn Påhlsson
nicer stacktrace when mandos-monitor fail during startup
604
                            self.find_and_remove_client,
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
605
                            dbus_interface=dbus.OBJECT_MANAGER_IFACE,
237.7.85 by Björn Påhlsson
nicer stacktrace when mandos-monitor fail during startup
606
                            byte_arrays=True))
607
        (self.mandos_serv
237.7.333 by Teddy Hogeborn
Support the standard org.freedesktop.DBus.ObjectManager interface.
608
         .connect_to_signal("InterfacesAdded",
237.7.85 by Björn Påhlsson
nicer stacktrace when mandos-monitor fail during startup
609
                            self.add_new_client,
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
610
                            dbus_interface=dbus.OBJECT_MANAGER_IFACE,
237.7.85 by Björn Påhlsson
nicer stacktrace when mandos-monitor fail during startup
611
                            byte_arrays=True))
612
        (self.mandos_serv
613
         .connect_to_signal("ClientNotFound",
614
                            self.client_not_found,
615
                            dbus_interface=server_interface,
616
                            byte_arrays=True))
237.7.165 by Teddy Hogeborn
* mandos: Bug fix: Don't print output from checkers when running in
617
        for path, client in mandos_clients.items():
237.7.85 by Björn Påhlsson
nicer stacktrace when mandos-monitor fail during startup
618
            client_proxy_object = self.bus.get_object(self.busname,
619
                                                      path)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
620
            self.add_client(MandosClientWidget(
621
                server_proxy_object=self.mandos_serv,
622
                proxy_object=client_proxy_object,
623
                properties=client,
624
                update_hook=self.refresh,
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
625
                delete_hook=self.remove_client),
237.7.85 by Björn Påhlsson
nicer stacktrace when mandos-monitor fail during startup
626
                            path=path)
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
627
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
628
        self.refresh()
237.7.717 by Teddy Hogeborn
mandos-monitor: Use new GLib.io_add_watch() call signature
629
        self._input_callback_tag = (
630
            GLib.io_add_watch(
631
                GLib.IOChannel.unix_new(sys.stdin.fileno()),
632
                GLib.PRIORITY_DEFAULT, GLib.IO_IN,
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
633
                glib_safely(self.process_input)))
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
634
        self.main_loop.run()
635
        # Main loop has finished, we should close everything now
237.7.378 by Teddy Hogeborn
Server: Use python-gi instead of old python-gobject
636
        GLib.source_remove(self._input_callback_tag)
237.7.722 by Teddy Hogeborn
Address Python 3 bytes/str warnings
637
        with warnings.catch_warnings():
638
            warnings.simplefilter("ignore", BytesWarning)
639
            self.screen.stop()
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
640
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
641
    def stop(self):
642
        self.main_loop.quit()
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
643
        log.removeHandler(self.loghandler)
644
        log.propagate = self.orig_log_propagate
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
645
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
646
    def process_input(self, source, condition):
647
        keys = self.screen.get_input()
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
648
        translations = {"ctrl n": "down",       # Emacs
649
                        "ctrl p": "up",         # Emacs
650
                        "ctrl v": "page down",  # Emacs
651
                        "meta v": "page up",    # Emacs
652
                        " ": "page down",       # less
653
                        "f": "page down",       # less
654
                        "b": "page up",         # less
655
                        "j": "down",            # vi
656
                        "k": "up",              # vi
657
                        }
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
658
        for key in keys:
659
            try:
660
                key = translations[key]
661
            except KeyError:    # :-)
662
                pass
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
663
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
664
            if key == "q" or key == "Q":
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
665
                self.stop()
666
                break
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
667
            elif key == "window resize":
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
668
                self.size = self.screen.get_cols_rows()
669
                self.refresh()
237.7.270 by Teddy Hogeborn
mandos-monitor: Bug fix: Make Ctrl-L actually redraw the screen.
670
            elif key == "ctrl l":
671
                self.screen.clear()
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
672
                self.refresh()
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
673
            elif key == "l" or key == "D":
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
674
                self.toggle_log_display()
675
                self.refresh()
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
676
            elif key == "w" or key == "i":
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
677
                self.change_log_display()
678
                self.refresh()
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
679
            elif key == "?" or key == "f1" or key == "esc":
237.2.170 by Teddy Hogeborn
* mandos-monitor (MandosClientWidget): Change "StopChecker" key to "S"
680
                if not self.log_visible:
681
                    self.log_visible = True
682
                    self.rebuild()
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
683
                self.add_log_line(("bold",
684
                                   "  ".join(("q: Quit",
685
                                              "?: Help",
686
                                              "l: Log window toggle",
687
                                              "TAB: Switch window",
688
                                              "w: Wrap (log lines)",
689
                                              "v: Toggle verbose log",
690
                                   ))))
691
                self.add_log_line(("bold",
692
                                   "  ".join(("Clients:",
693
                                              "+: Enable",
694
                                              "-: Disable",
695
                                              "R: Remove",
696
                                              "s: Start new checker",
697
                                              "S: Stop checker",
698
                                              "C: Checker OK",
699
                                              "a: Approve",
700
                                              "d: Deny",
701
                                   ))))
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
702
                self.refresh()
237.8.2 by teddy at bsnet
* mandos-monitor: Use unicode string literals. Update __future__
703
            elif key == "tab":
237.2.168 by Teddy Hogeborn
* mandos-monitor (MandosClientPropertyCache): Remove conversion of
704
                if self.topwidget.get_focus() is self.logbox:
705
                    self.topwidget.set_focus(0)
706
                else:
707
                    self.topwidget.set_focus(self.logbox)
708
                self.refresh()
237.7.261 by Teddy Hogeborn
mandos-monitor: New "verbose" mode to see less important log messages.
709
            elif key == "v":
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
710
                if log.level < logging.INFO:
711
                    log.setLevel(logging.INFO)
712
                    log.info("Verbose mode: Off")
237.7.261 by Teddy Hogeborn
mandos-monitor: New "verbose" mode to see less important log messages.
713
                else:
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
714
                    log.setLevel(logging.NOTSET)
715
                    log.info("Verbose mode: On")
237.7.421 by Teddy Hogeborn
PEP8 compliance: mandos-monitor
716
            # elif (key == "end" or key == "meta >" or key == "G"
717
            #       or key == ">"):
718
            #     pass            # xxx end-of-buffer
719
            # elif (key == "home" or key == "meta <" or key == "g"
720
            #       or key == "<"):
721
            #     pass            # xxx beginning-of-buffer
722
            # elif key == "ctrl e" or key == "$":
723
            #     pass            # xxx move-end-of-line
724
            # elif key == "ctrl a" or key == "^":
725
            #     pass            # xxx move-beginning-of-line
726
            # elif key == "ctrl b" or key == "meta (" or key == "h":
727
            #     pass            # xxx left
728
            # elif key == "ctrl f" or key == "meta )" or key == "l":
729
            #     pass            # xxx right
730
            # elif key == "a":
731
            #     pass            # scroll up log
732
            # elif key == "z":
733
            #     pass            # scroll down log
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
734
            elif self.topwidget.selectable():
735
                self.topwidget.keypress(self.size, key)
736
                self.refresh()
737
        return True
738
237.7.436 by Teddy Hogeborn
Add more PEP8 compliance (as per the "pycodestyle" tool).
739
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
740
class UILogHandler(logging.Handler):
741
    def __init__(self, ui, *args, **kwargs):
742
        self.ui = ui
743
        super(UILogHandler, self).__init__(*args, **kwargs)
744
        self.setFormatter(
745
            logging.Formatter("%(asctime)s: %(message)s"))
746
    def emit(self, record):
747
        msg = self.format(record)
748
        if record.levelno > logging.INFO:
749
            msg = ("bold", msg)
750
        self.ui.add_log_line(msg)
751
752
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
753
ui = UserInterface()
754
try:
755
    ui.run()
24.1.159 by Björn Påhlsson
added approval to mandos-ctl
756
except KeyboardInterrupt:
237.7.731 by Teddy Hogeborn
mandos-monitor: Use Python's standard loggging module
757
    with warnings.catch_warnings():
758
        warnings.filterwarnings("ignore", "", BytesWarning)
759
        ui.screen.stop()
760
except Exception:
761
    with warnings.catch_warnings():
762
        warnings.filterwarnings("ignore", "", BytesWarning)
763
        ui.screen.stop()
237.2.167 by Teddy Hogeborn
* mandos-monitor: New prototype version of interactive server
764
    raise