mirror of
https://github.com/matrix-org/pantalaimon.git
synced 2025-03-29 09:28:10 -04:00

This patch adds a config option that enables a mode wher a proxy will only keep the latest room key from a sender in a certain room. This is useful for bots that use pantalaimon since they are mostly only interested in the latest messages and don't care about room history.
258 lines
8.6 KiB
Python
258 lines
8.6 KiB
Python
# Copyright 2019 The Matrix.org Foundation CIC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import configparser
|
|
import os
|
|
from ipaddress import IPv4Address, IPv6Address, ip_address
|
|
from typing import Union
|
|
from urllib.parse import ParseResult, urlparse
|
|
|
|
import attr
|
|
import logbook
|
|
|
|
|
|
class PanConfigParser(configparser.ConfigParser):
|
|
def __init__(self):
|
|
super().__init__(
|
|
default_section="Default",
|
|
defaults={
|
|
"SSL": "True",
|
|
"IgnoreVerification": "False",
|
|
"ListenAddress": "localhost",
|
|
"ListenPort": "8009",
|
|
"LogLevel": "warnig",
|
|
"Notifications": "on",
|
|
"UseKeyring": "yes",
|
|
"SearchRequests": "off",
|
|
"IndexEncryptedOnly": "True",
|
|
"IndexingBatchSize": "100",
|
|
"HistoryFetchDelay": "3000",
|
|
"DebugEncryption": "False",
|
|
"DropOldKeys": "False",
|
|
},
|
|
converters={
|
|
"address": parse_address,
|
|
"url": parse_url,
|
|
"loglevel": parse_log_level,
|
|
},
|
|
)
|
|
|
|
|
|
def parse_address(value):
|
|
# type: (str) -> Union[IPv4Address, IPv6Address]
|
|
if value == "localhost":
|
|
return ip_address("127.0.0.1")
|
|
|
|
return ip_address(value)
|
|
|
|
|
|
def parse_url(v):
|
|
# type: (str) -> ParseResult
|
|
value = urlparse(v)
|
|
|
|
if value.scheme not in ("http", "https"):
|
|
raise ValueError(
|
|
f"Invalid URL scheme {value.scheme}. " f"Only HTTP(s) URLs are allowed"
|
|
)
|
|
value.port
|
|
|
|
return value
|
|
|
|
|
|
def parse_log_level(value):
|
|
# type: (str) -> logbook
|
|
value = value.lower()
|
|
|
|
if value == "info":
|
|
return logbook.INFO
|
|
elif value == "warning":
|
|
return logbook.WARNING
|
|
elif value == "error":
|
|
return logbook.ERROR
|
|
elif value == "debug":
|
|
return logbook.DEBUG
|
|
|
|
return logbook.WARNING
|
|
|
|
|
|
class PanConfigError(Exception):
|
|
"""Pantalaimon configuration error."""
|
|
|
|
pass
|
|
|
|
|
|
@attr.s
|
|
class ServerConfig:
|
|
"""Server configuration.
|
|
|
|
Args:
|
|
name (str): A unique user chosen name that identifies the server.
|
|
homeserver (ParseResult): The URL of the Matrix homeserver that we want
|
|
to forward requests to.
|
|
listen_address (str): The local address where pantalaimon will listen
|
|
for connections.
|
|
listen_port (int): The port where pantalaimon will listen for
|
|
connections.
|
|
proxy (ParseResult):
|
|
A proxy that the daemon should use when making connections to the
|
|
homeserver.
|
|
ssl (bool): Enable or disable SSL for the connection between
|
|
pantalaimon and the homeserver.
|
|
ignore_verification (bool): Enable or disable device verification for
|
|
E2E encrypted messages.
|
|
keyring (bool): Enable or disable the OS keyring for the storage of
|
|
access tokens.
|
|
search_requests (bool): Enable or disable aditional Homeserver requests
|
|
for the search API endpoint.
|
|
index_encrypted_only (bool): Enable or disable message indexing fro
|
|
non-encrypted rooms.
|
|
indexing_batch_size (int): The number of messages that should be
|
|
requested from the Homeserver when we fetch and index messages from
|
|
the room history.
|
|
history_fetch_delay (int): The delay between room history fetching
|
|
requests in seconds.
|
|
drop_old_keys (bool): Should Pantalaimon only keep the most recent
|
|
decryption key around.
|
|
"""
|
|
|
|
name = attr.ib(type=str)
|
|
homeserver = attr.ib(type=ParseResult)
|
|
listen_address = attr.ib(
|
|
type=Union[IPv4Address, IPv6Address], default=ip_address("127.0.0.1")
|
|
)
|
|
listen_port = attr.ib(type=int, default=8009)
|
|
proxy = attr.ib(type=str, default="")
|
|
ssl = attr.ib(type=bool, default=True)
|
|
ignore_verification = attr.ib(type=bool, default=False)
|
|
keyring = attr.ib(type=bool, default=True)
|
|
search_requests = attr.ib(type=bool, default=False)
|
|
index_encrypted_only = attr.ib(type=bool, default=True)
|
|
indexing_batch_size = attr.ib(type=int, default=100)
|
|
history_fetch_delay = attr.ib(type=int, default=3)
|
|
drop_old_keys = attr.ib(type=bool, default=False)
|
|
|
|
|
|
@attr.s
|
|
class PanConfig:
|
|
"""Pantalaimon configuration.
|
|
|
|
Args:
|
|
config_path (str): The path where we should search for a configuration
|
|
file.
|
|
filename (str): The name of the file that we should read.
|
|
debug_encryption (bool): Should debug logs be enabled for the Matrix
|
|
encryption support.
|
|
"""
|
|
|
|
config_file = attr.ib()
|
|
|
|
log_level = attr.ib(default=None)
|
|
debug_encryption = attr.ib(type=bool, default=None)
|
|
notifications = attr.ib(default=None)
|
|
servers = attr.ib(init=False, default=attr.Factory(dict))
|
|
|
|
def read(self):
|
|
"""Read the configuration file.
|
|
|
|
Raises OSError if the file can't be read or PanConfigError if there is
|
|
a syntax error with the config file.
|
|
"""
|
|
config = PanConfigParser()
|
|
try:
|
|
config.read(os.path.abspath(self.config_file))
|
|
except configparser.Error as e:
|
|
raise PanConfigError(e)
|
|
|
|
if self.log_level is None:
|
|
self.log_level = config["Default"].getloglevel("LogLevel")
|
|
|
|
if self.notifications is None:
|
|
self.notifications = config["Default"].getboolean("Notifications")
|
|
|
|
self.debug_encryption = config["Default"].getboolean("DebugEncryption")
|
|
|
|
listen_set = set()
|
|
|
|
try:
|
|
for section_name, section in config.items():
|
|
|
|
if section_name == "Default":
|
|
continue
|
|
|
|
homeserver = section.geturl("Homeserver")
|
|
|
|
if not homeserver:
|
|
raise PanConfigError(
|
|
f"Homserver is not set for " f"section {section_name}"
|
|
)
|
|
|
|
listen_address = section.getaddress("ListenAddress")
|
|
listen_port = section.getint("ListenPort")
|
|
ssl = section.getboolean("SSL")
|
|
ignore_verification = section.getboolean("IgnoreVerification")
|
|
keyring = section.getboolean("UseKeyring")
|
|
proxy = section.geturl("Proxy")
|
|
search_requests = section.getboolean("SearchRequests")
|
|
index_encrypted_only = section.getboolean("IndexEncryptedOnly")
|
|
|
|
indexing_batch_size = section.getint("IndexingBatchSize")
|
|
|
|
if not 1 < indexing_batch_size <= 1000:
|
|
raise PanConfigError(
|
|
"The indexing batch size needs to be "
|
|
"a positive integer between 1 and "
|
|
"1000"
|
|
)
|
|
|
|
history_fetch_delay = section.getint("HistoryFetchDelay")
|
|
|
|
if not 100 < history_fetch_delay <= 10000:
|
|
raise PanConfigError(
|
|
"The history fetch delay needs to be "
|
|
"a positive integer between 100 and "
|
|
"10000"
|
|
)
|
|
|
|
listen_tuple = (listen_address, listen_port)
|
|
|
|
if listen_tuple in listen_set:
|
|
raise PanConfigError(
|
|
f"The listen address/port combination"
|
|
f" for section {section_name} was "
|
|
f"already defined before."
|
|
)
|
|
listen_set.add(listen_tuple)
|
|
drop_old_keys = section.getboolean("DropOldKeys")
|
|
|
|
server_conf = ServerConfig(
|
|
section_name,
|
|
homeserver,
|
|
listen_address,
|
|
listen_port,
|
|
proxy,
|
|
ssl,
|
|
ignore_verification,
|
|
keyring,
|
|
search_requests,
|
|
index_encrypted_only,
|
|
indexing_batch_size,
|
|
history_fetch_delay / 1000,
|
|
drop_old_keys,
|
|
)
|
|
|
|
self.servers[section_name] = server_conf
|
|
|
|
except ValueError as e:
|
|
raise PanConfigError(e)
|