mirror of
https://git.pleroma.social/pleroma/relay.git
synced 2025-04-20 09:36:45 +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
|