sedi-relay/relay/database.py

122 lines
2.3 KiB
Python
Raw Normal View History

2022-05-06 07:04:51 +00:00
import json
2018-08-10 19:59:46 +00:00
import logging
2022-05-06 07:04:51 +00:00
import traceback
2018-08-10 19:59:46 +00:00
2022-05-06 07:04:51 +00:00
from Crypto.PublicKey import RSA
from urllib.parse import urlparse
2018-08-10 19:59:46 +00:00
2022-05-06 07:04:51 +00:00
class RelayDatabase:
def __init__(self, config):
self.config = config
self.data = None
self.PRIVKEY = None
2018-08-10 19:59:46 +00:00
2022-05-06 07:04:51 +00:00
@property
def PUBKEY(self):
return self.PRIVKEY.publickey()
2019-05-21 16:29:55 +00:00
2022-05-06 07:04:51 +00:00
@property
def pubkey(self):
return self.PUBKEY.exportKey('PEM').decode('utf-8')
2020-11-22 05:50:57 +00:00
2018-08-10 19:59:46 +00:00
2022-05-06 07:04:51 +00:00
@property
def privkey(self):
try:
return self.data['private-key']
2022-05-06 07:04:51 +00:00
except KeyError:
return False
2018-08-10 19:59:46 +00:00
2022-05-06 07:04:51 +00:00
@property
def hostnames(self):
return [urlparse(inbox).hostname for inbox in self.inboxes]
@property
def inboxes(self):
return self.data.get('relay-list', [])
def generate_key(self):
self.PRIVKEY = RSA.generate(4096)
self.data['private-key'] = self.PRIVKEY.exportKey('PEM').decode('utf-8')
def load(self):
new_db = True
try:
with self.config.db.open() as fd:
self.data = json.load(fd)
key = self.data.pop('actorKeys', None)
if key:
self.data['private-key'] = key.get('privateKey')
self.data.pop('actors', None)
new_db = False
except FileNotFoundError:
pass
except json.decoder.JSONDecodeError as e:
if self.config.db.stat().st_size > 0:
raise e from None
if not self.data:
logging.info('No database was found. Making a new one.')
self.data = {}
for inbox in self.inboxes:
if self.config.is_banned(inbox) or (self.config.whitelist_enabled and not self.config.is_whitelisted(inbox)):
self.del_inbox(inbox)
if not self.privkey:
logging.info("No actor keys present, generating 4096-bit RSA keypair.")
self.generate_key()
else:
self.PRIVKEY = RSA.importKey(self.privkey)
self.save()
return not new_db
def save(self):
with self.config.db.open('w') as fd:
data = {
'relay-list': self.inboxes,
'private-key': self.privkey
}
json.dump(data, fd, indent=4)
def get_inbox(self, domain):
if domain.startswith('http'):
domain = urlparse(domain).hostname
for inbox in self.inboxes:
if domain == urlparse(inbox).hostname:
return inbox
def add_inbox(self, inbox):
assert inbox.startswith('https')
assert inbox not in self.inboxes
self.data['relay-list'].append(inbox)
def del_inbox(self, inbox):
if inbox not in self.inboxes:
raise KeyError(inbox)
self.data['relay-list'].remove(inbox)