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