mirror of
https://github.com/matrix-org/pantalaimon.git
synced 2025-02-07 10:35:29 -05:00
pantalaimon: Add a configuration file for the daemon.
This commit is contained in:
parent
65d1401b76
commit
2987589854
2
Makefile
2
Makefile
@ -10,4 +10,4 @@ typecheck:
|
|||||||
mypy --ignore-missing-imports pantalaimon
|
mypy --ignore-missing-imports pantalaimon
|
||||||
|
|
||||||
run-local:
|
run-local:
|
||||||
python -m pantalaimon.main https://localhost:8448 --proxy http://localhost:8080 -k --log-level debug
|
python -m pantalaimon.main --log-level debug --config ./contrib/pantalaimon.conf
|
||||||
|
150
pantalaimon/config.py
Normal file
150
pantalaimon/config.py
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
import configparser
|
||||||
|
import os
|
||||||
|
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
from ipaddress import ip_address, IPv4Address, IPv6Address
|
||||||
|
from urllib.parse import urlparse, ParseResult
|
||||||
|
|
||||||
|
import logbook
|
||||||
|
import attr
|
||||||
|
|
||||||
|
|
||||||
|
class PanConfigParser(configparser.ConfigParser):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(
|
||||||
|
default_section="Default",
|
||||||
|
defaults={
|
||||||
|
"SSL": "True",
|
||||||
|
"ListenAddress": "localhost",
|
||||||
|
"ListenPort": "8009",
|
||||||
|
"LogLevel": "warnig",
|
||||||
|
},
|
||||||
|
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(value):
|
||||||
|
# type: (str) -> ParseResult
|
||||||
|
value = urlparse(value)
|
||||||
|
|
||||||
|
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:
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
homeserver = attr.ib()
|
||||||
|
listen_address = attr.ib(type=Union[IPv4Address, IPv6Address])
|
||||||
|
listen_port = attr.ib(type=int)
|
||||||
|
proxy = attr.ib(type=str)
|
||||||
|
ssl = attr.ib(type=bool, default=True)
|
||||||
|
|
||||||
|
|
||||||
|
@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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
config_file = attr.ib()
|
||||||
|
|
||||||
|
log_level = 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")
|
||||||
|
|
||||||
|
try:
|
||||||
|
for section_name, section in config.items():
|
||||||
|
|
||||||
|
if section_name == "Default":
|
||||||
|
continue
|
||||||
|
|
||||||
|
homeserver = section.geturl("Homeserver")
|
||||||
|
listen_address = section.getaddress("ListenAddress")
|
||||||
|
listen_port = section.getint("ListenPort")
|
||||||
|
ssl = section.getboolean("SSL")
|
||||||
|
proxy = section.geturl("Proxy")
|
||||||
|
|
||||||
|
server_conf = ServerConfig(
|
||||||
|
homeserver,
|
||||||
|
listen_address,
|
||||||
|
listen_port,
|
||||||
|
proxy,
|
||||||
|
ssl
|
||||||
|
)
|
||||||
|
|
||||||
|
self.servers[section_name] = server_conf
|
||||||
|
|
||||||
|
except ValueError as e:
|
||||||
|
raise PanConfigError(e)
|
@ -7,16 +7,28 @@ from urllib.parse import urlparse
|
|||||||
|
|
||||||
import click
|
import click
|
||||||
import janus
|
import janus
|
||||||
import logbook
|
|
||||||
|
|
||||||
from appdirs import user_data_dir
|
from appdirs import user_data_dir, user_config_dir
|
||||||
from logbook import StderrHandler
|
from logbook import StderrHandler
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
|
||||||
from pantalaimon.ui import GlibT
|
from pantalaimon.ui import GlibT
|
||||||
from pantalaimon.log import logger
|
|
||||||
from pantalaimon.daemon import ProxyDaemon
|
from pantalaimon.daemon import ProxyDaemon
|
||||||
|
from pantalaimon.config import PanConfig, PanConfigError, parse_log_level
|
||||||
|
from pantalaimon.log import logger
|
||||||
|
|
||||||
|
|
||||||
|
def create_dirs(data_dir, conf_dir):
|
||||||
|
try:
|
||||||
|
os.makedirs(data_dir)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.makedirs(conf_dir)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
async def init(homeserver, http_proxy, ssl, send_queue, recv_queue):
|
async def init(homeserver, http_proxy, ssl, send_queue, recv_queue):
|
||||||
@ -84,77 +96,55 @@ class ipaddress(click.ParamType):
|
|||||||
@click.command(
|
@click.command(
|
||||||
help=("pantalaimon is a reverse proxy for matrix homeservers that "
|
help=("pantalaimon is a reverse proxy for matrix homeservers that "
|
||||||
"transparently encrypts and decrypts messages for clients that "
|
"transparently encrypts and decrypts messages for clients that "
|
||||||
"connect to pantalaimon.\n\n"
|
"connect to pantalaimon.")
|
||||||
"HOMESERVER - the homeserver that the daemon should connect to.")
|
|
||||||
|
|
||||||
)
|
)
|
||||||
@click.option(
|
|
||||||
"--proxy",
|
|
||||||
type=URL(),
|
|
||||||
default=None,
|
|
||||||
help="A proxy that will be used to connect to the homeserver."
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"-k",
|
|
||||||
"--ssl-insecure/--no-ssl-insecure",
|
|
||||||
default=False,
|
|
||||||
help="Disable SSL verification for the homeserver connection."
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"-l",
|
|
||||||
"--listen-address",
|
|
||||||
type=ipaddress(),
|
|
||||||
default=ip_address("127.0.0.1"),
|
|
||||||
help=("The listening address for incoming client connections "
|
|
||||||
"(default: 127.0.0.1)")
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"-p",
|
|
||||||
"--listen-port",
|
|
||||||
type=int,
|
|
||||||
default=8009,
|
|
||||||
help="The listening port for incoming client connections (default: 8009)"
|
|
||||||
)
|
|
||||||
@click.option("--log-level", type=click.Choice([
|
@click.option("--log-level", type=click.Choice([
|
||||||
"error",
|
"error",
|
||||||
"warning",
|
"warning",
|
||||||
"info",
|
"info",
|
||||||
"debug"
|
"debug"
|
||||||
]), default="error")
|
]), default=None)
|
||||||
@click.argument(
|
@click.option("-c", "--config", type=click.Path(exists=True))
|
||||||
"homeserver",
|
@click.pass_context
|
||||||
type=URL(),
|
|
||||||
)
|
|
||||||
def main(
|
def main(
|
||||||
proxy,
|
context,
|
||||||
ssl_insecure,
|
|
||||||
listen_address,
|
|
||||||
listen_port,
|
|
||||||
log_level,
|
log_level,
|
||||||
homeserver
|
config
|
||||||
):
|
):
|
||||||
ssl = None if ssl_insecure is False else False
|
conf_dir = user_config_dir("pantalaimon", "")
|
||||||
|
data_dir = user_data_dir("pantalaimon", "")
|
||||||
|
create_dirs(data_dir, conf_dir)
|
||||||
|
|
||||||
StderrHandler(level=log_level.upper()).push_application()
|
config = config or os.path.join(conf_dir, "pantalaimon.conf")
|
||||||
|
|
||||||
if log_level == "info":
|
if log_level:
|
||||||
logger.level = logbook.INFO
|
log_level = parse_log_level(log_level)
|
||||||
elif log_level == "warning":
|
|
||||||
logger.level = logbook.WARNING
|
pan_conf = PanConfig(config, log_level)
|
||||||
elif log_level == "error":
|
|
||||||
logger.level = logbook.ERROR
|
try:
|
||||||
elif log_level == "debug":
|
pan_conf.read()
|
||||||
logger.level = logbook.DEBUG
|
except (OSError, PanConfigError) as e:
|
||||||
|
context.fail(e)
|
||||||
|
|
||||||
|
if not pan_conf.servers:
|
||||||
|
context.fail("Homeserver is not configured.")
|
||||||
|
|
||||||
|
logger.level = pan_conf.log_level
|
||||||
|
StderrHandler().push_application()
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
pan_queue = janus.Queue(loop=loop)
|
pan_queue = janus.Queue(loop=loop)
|
||||||
ui_queue = janus.Queue(loop=loop)
|
ui_queue = janus.Queue(loop=loop)
|
||||||
|
|
||||||
|
# TODO start the other servers as well
|
||||||
|
server_conf = list(pan_conf.servers.values())[0]
|
||||||
|
|
||||||
proxy, app = loop.run_until_complete(init(
|
proxy, app = loop.run_until_complete(init(
|
||||||
homeserver,
|
server_conf.homeserver,
|
||||||
proxy.geturl() if proxy else None,
|
server_conf.proxy.geturl() if server_conf.proxy else None,
|
||||||
ssl,
|
server_conf.ssl,
|
||||||
pan_queue.async_q,
|
pan_queue.async_q,
|
||||||
ui_queue.async_q
|
ui_queue.async_q
|
||||||
))
|
))
|
||||||
@ -179,7 +169,11 @@ def main(
|
|||||||
home = os.path.expanduser("~")
|
home = os.path.expanduser("~")
|
||||||
os.chdir(home)
|
os.chdir(home)
|
||||||
|
|
||||||
web.run_app(app, host=str(listen_address), port=listen_port)
|
web.run_app(
|
||||||
|
app,
|
||||||
|
host=str(server_conf.listen_address),
|
||||||
|
port=server_conf.listen_port
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
Loading…
x
Reference in New Issue
Block a user