mirror of
https://git.pleroma.social/pleroma/relay.git
synced 2025-04-19 17:16:42 +00:00
176 lines
3.5 KiB
Python
176 lines
3.5 KiB
Python
import json
|
|
import os
|
|
import yaml
|
|
|
|
from blib import convert_to_boolean
|
|
from functools import cached_property
|
|
from pathlib import Path
|
|
from typing import Any
|
|
from urllib.parse import urlparse
|
|
|
|
|
|
class RelayConfig(dict[str, Any]):
|
|
def __init__(self, path: str):
|
|
dict.__init__(self, {})
|
|
|
|
if self.is_docker:
|
|
path = "/data/config.yaml"
|
|
|
|
self._path = Path(path).expanduser().resolve()
|
|
self.reset()
|
|
|
|
|
|
def __setitem__(self, key: str, value: Any) -> None:
|
|
if key in {"blocked_instances", "blocked_software", "whitelist"}:
|
|
assert isinstance(value, (list, set, tuple))
|
|
|
|
elif key in {"port", "workers", "json_cache", "timeout"}:
|
|
if not isinstance(value, int):
|
|
value = int(value)
|
|
|
|
elif key == "whitelist_enabled":
|
|
if not isinstance(value, bool):
|
|
value = convert_to_boolean(value)
|
|
|
|
super().__setitem__(key, value)
|
|
|
|
|
|
@property
|
|
def db(self) -> Path:
|
|
return Path(self["db"]).expanduser().resolve()
|
|
|
|
|
|
@property
|
|
def actor(self) -> str:
|
|
return f"https://{self['host']}/actor"
|
|
|
|
|
|
@property
|
|
def inbox(self) -> str:
|
|
return f"https://{self['host']}/inbox"
|
|
|
|
|
|
@property
|
|
def keyid(self) -> str:
|
|
return f"{self.actor}#main-key"
|
|
|
|
|
|
@cached_property
|
|
def is_docker(self) -> bool:
|
|
return bool(os.environ.get("DOCKER_RUNNING"))
|
|
|
|
|
|
def reset(self) -> None:
|
|
self.clear()
|
|
self.update({
|
|
"db": str(self._path.parent.joinpath(f"{self._path.stem}.jsonld")),
|
|
"listen": "0.0.0.0",
|
|
"port": 8080,
|
|
"note": "Make a note about your instance here.",
|
|
"push_limit": 512,
|
|
"json_cache": 1024,
|
|
"timeout": 10,
|
|
"workers": 0,
|
|
"host": "relay.example.com",
|
|
"whitelist_enabled": False,
|
|
"blocked_software": [],
|
|
"blocked_instances": [],
|
|
"whitelist": []
|
|
})
|
|
|
|
|
|
def load(self) -> None:
|
|
self.reset()
|
|
|
|
options = {}
|
|
|
|
try:
|
|
options["Loader"] = yaml.FullLoader
|
|
|
|
except AttributeError:
|
|
pass
|
|
|
|
try:
|
|
with self._path.open("r", encoding = "UTF-8") as fd:
|
|
config = yaml.load(fd, **options)
|
|
|
|
except FileNotFoundError:
|
|
return
|
|
|
|
if not config:
|
|
return
|
|
|
|
for key, value in config.items():
|
|
if key == "ap":
|
|
for k, v in value.items():
|
|
if k not in self:
|
|
continue
|
|
|
|
self[k] = v
|
|
|
|
continue
|
|
|
|
if key not in self:
|
|
continue
|
|
|
|
self[key] = value
|
|
|
|
|
|
class RelayDatabase(dict[str, Any]):
|
|
def __init__(self, config: RelayConfig):
|
|
dict.__init__(self, {
|
|
"relay-list": {},
|
|
"private-key": None,
|
|
"follow-requests": {},
|
|
"version": 1
|
|
})
|
|
|
|
self.config = config
|
|
self.signer = None
|
|
|
|
|
|
@property
|
|
def hostnames(self) -> tuple[str]:
|
|
return tuple(self["relay-list"].keys())
|
|
|
|
|
|
@property
|
|
def inboxes(self) -> tuple[dict[str, str]]:
|
|
return tuple(data["inbox"] for data in self["relay-list"].values())
|
|
|
|
|
|
def load(self) -> None:
|
|
try:
|
|
with self.config.db.open() as fd:
|
|
data = json.load(fd)
|
|
|
|
self["version"] = data.get("version", None)
|
|
self["private-key"] = data.get("private-key")
|
|
|
|
if self["version"] is None:
|
|
self["version"] = 1
|
|
|
|
if "actorKeys" in data:
|
|
self["private-key"] = data["actorKeys"]["privateKey"]
|
|
|
|
for item in data.get("relay-list", []):
|
|
domain = urlparse(item).hostname
|
|
self["relay-list"][domain] = {
|
|
"domain": domain,
|
|
"inbox": item,
|
|
"followid": None
|
|
}
|
|
|
|
else:
|
|
self["relay-list"] = data.get("relay-list", {})
|
|
|
|
for domain, instance in self["relay-list"].items():
|
|
if not instance.get("domain"):
|
|
instance["domain"] = domain
|
|
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
except json.decoder.JSONDecodeError as e:
|
|
if self.config.db.stat().st_size > 0:
|
|
raise e from None
|