mirror of
https://git.pleroma.social/pleroma/relay.git
synced 2024-11-23 23:17:58 +00:00
Compare commits
No commits in common. "f7e1c6b0b88f6a50cde996f0b18d195cecc39155" and "1a7abb4ecb76bfc1292ca2bc46b37876b89186c6" have entirely different histories.
f7e1c6b0b8
...
1a7abb4ecb
|
@ -234,8 +234,7 @@ class RelayConfig(DotDict):
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
config = {
|
config = {
|
||||||
# just turning config.db into a string is good enough for now
|
'db': self['db'],
|
||||||
'db': str(self.db),
|
|
||||||
'listen': self.listen,
|
'listen': self.listen,
|
||||||
'port': self.port,
|
'port': self.port,
|
||||||
'note': self.note,
|
'note': self.note,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
import aputils
|
||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from aiohttp import ClientSession, ClientTimeout, TCPConnector
|
from aiohttp import ClientSession, ClientTimeout, TCPConnector
|
||||||
from aiohttp.client_exceptions import ClientConnectorError, ServerTimeoutError
|
from aiohttp.client_exceptions import ClientConnectorError, ServerTimeoutError
|
||||||
from aputils import Nodeinfo, WellKnownNodeinfo
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from cachetools import LRUCache
|
from cachetools import LRUCache
|
||||||
from json.decoder import JSONDecodeError
|
from json.decoder import JSONDecodeError
|
||||||
|
@ -87,7 +87,7 @@ class HttpClient:
|
||||||
headers = {}
|
headers = {}
|
||||||
|
|
||||||
if sign_headers:
|
if sign_headers:
|
||||||
headers.update(self.database.signer.sign_headers('GET', url, algorithm='original'))
|
headers.update(self.database.signer.sign_headers('GET', url))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logging.verbose(f'Fetching resource: {url}')
|
logging.verbose(f'Fetching resource: {url}')
|
||||||
|
@ -103,6 +103,10 @@ class HttpClient:
|
||||||
return
|
return
|
||||||
|
|
||||||
if loads:
|
if loads:
|
||||||
|
if issubclass(loads, DotDict):
|
||||||
|
message = await resp.json(loads=loads.new_from_json)
|
||||||
|
|
||||||
|
else:
|
||||||
message = await resp.json(loads=loads)
|
message = await resp.json(loads=loads)
|
||||||
|
|
||||||
elif resp.content_type == MIMETYPES['activity']:
|
elif resp.content_type == MIMETYPES['activity']:
|
||||||
|
@ -138,11 +142,11 @@ class HttpClient:
|
||||||
instance = self.database.get_inbox(url)
|
instance = self.database.get_inbox(url)
|
||||||
|
|
||||||
## Using the old algo by default is probably a better idea right now
|
## Using the old algo by default is probably a better idea right now
|
||||||
if instance and instance.get('software') in {'mastodon'}:
|
if instance and instance.get('software') not in {'mastodon'}:
|
||||||
algorithm = 'hs2019'
|
algorithm = aputils.Algorithm.RSASHA256
|
||||||
|
|
||||||
else:
|
else:
|
||||||
algorithm = 'original'
|
algorithm = aputils.Algorithm.HS2019
|
||||||
|
|
||||||
headers = {'Content-Type': 'application/activity+json'}
|
headers = {'Content-Type': 'application/activity+json'}
|
||||||
headers.update(self.database.signer.sign_headers('POST', url, message, algorithm=algorithm))
|
headers.update(self.database.signer.sign_headers('POST', url, message, algorithm=algorithm))
|
||||||
|
@ -169,10 +173,7 @@ class HttpClient:
|
||||||
## Additional methods ##
|
## Additional methods ##
|
||||||
async def fetch_nodeinfo(self, domain):
|
async def fetch_nodeinfo(self, domain):
|
||||||
nodeinfo_url = None
|
nodeinfo_url = None
|
||||||
wk_nodeinfo = await self.get(
|
wk_nodeinfo = await self.get(f'https://{domain}/.well-known/nodeinfo', loads=WKNodeinfo)
|
||||||
f'https://{domain}/.well-known/nodeinfo',
|
|
||||||
loads = WellKnownNodeinfo.new_from_json
|
|
||||||
)
|
|
||||||
|
|
||||||
for version in ['20', '21']:
|
for version in ['20', '21']:
|
||||||
try:
|
try:
|
||||||
|
@ -185,4 +186,4 @@ class HttpClient:
|
||||||
logging.verbose(f'Failed to fetch nodeinfo url for domain: {domain}')
|
logging.verbose(f'Failed to fetch nodeinfo url for domain: {domain}')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return await self.get(nodeinfo_url, loads=Nodeinfo.new_from_json) or False
|
return await request(nodeinfo_url, loads=Nodeinfo) or False
|
||||||
|
|
|
@ -37,6 +37,10 @@ def set_app(new_app):
|
||||||
app = new_app
|
app = new_app
|
||||||
|
|
||||||
|
|
||||||
|
def build_signing_string(headers, used_headers):
|
||||||
|
return '\n'.join(map(lambda x: ': '.join([x.lower(), headers[x]]), used_headers))
|
||||||
|
|
||||||
|
|
||||||
def boolean(value):
|
def boolean(value):
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
if value.lower() in ['on', 'y', 'yes', 'true', 'enable', 'enabled', '1']:
|
if value.lower() in ['on', 'y', 'yes', 'true', 'enable', 'enabled', '1']:
|
||||||
|
@ -275,6 +279,12 @@ class Message(DotDict):
|
||||||
return aputils.Signer.new_from_actor(self)
|
return aputils.Signer.new_from_actor(self)
|
||||||
|
|
||||||
|
|
||||||
|
class Nodeinfo(DotDict):
|
||||||
|
@property
|
||||||
|
def swname(self):
|
||||||
|
return self.software.name
|
||||||
|
|
||||||
|
|
||||||
class Response(AiohttpResponse):
|
class Response(AiohttpResponse):
|
||||||
@classmethod
|
@classmethod
|
||||||
def new(cls, body='', status=200, headers=None, ctype='text'):
|
def new(cls, body='', status=200, headers=None, ctype='text'):
|
||||||
|
@ -340,3 +350,22 @@ class View(AiohttpView):
|
||||||
@property
|
@property
|
||||||
def database(self):
|
def database(self):
|
||||||
return self.app.database
|
return self.app.database
|
||||||
|
|
||||||
|
|
||||||
|
class WKNodeinfo(DotDict):
|
||||||
|
@classmethod
|
||||||
|
def new(cls, v20, v21):
|
||||||
|
return cls({
|
||||||
|
'links': [
|
||||||
|
{'rel': NODEINFO_NS['20'], 'href': v20},
|
||||||
|
{'rel': NODEINFO_NS['21'], 'href': v21}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def get_url(self, version='20'):
|
||||||
|
for item in self.links:
|
||||||
|
if item['rel'] == NODEINFO_NS[version]:
|
||||||
|
return item['href']
|
||||||
|
|
||||||
|
raise KeyError(version)
|
||||||
|
|
|
@ -23,7 +23,7 @@ async def handle_relay(request):
|
||||||
cache[request.message.objectid] = message.id
|
cache[request.message.objectid] = message.id
|
||||||
logging.debug(f'>> relay: {message}')
|
logging.debug(f'>> relay: {message}')
|
||||||
|
|
||||||
inboxes = request.database.distill_inboxes(request.message)
|
niboxes = request.database.distill_inboxes(request.message)
|
||||||
|
|
||||||
for inbox in inboxes:
|
for inbox in inboxes:
|
||||||
request.app.push_message(inbox, message)
|
request.app.push_message(inbox, message)
|
||||||
|
|
|
@ -8,7 +8,7 @@ from pathlib import Path
|
||||||
|
|
||||||
from . import __version__, misc
|
from . import __version__, misc
|
||||||
from .http_debug import STATS
|
from .http_debug import STATS
|
||||||
from .misc import DotDict, Message, Response
|
from .misc import DotDict, Message, Response, WKNodeinfo
|
||||||
from .processors import run_processor
|
from .processors import run_processor
|
||||||
|
|
||||||
|
|
||||||
|
@ -158,37 +158,57 @@ async def webfinger(request):
|
||||||
if subject != f'acct:relay@{request.config.host}':
|
if subject != f'acct:relay@{request.config.host}':
|
||||||
return Response.new_error(404, 'user not found', 'json')
|
return Response.new_error(404, 'user not found', 'json')
|
||||||
|
|
||||||
data = aputils.Webfinger.new(
|
data = {
|
||||||
handle = 'relay',
|
'subject': subject,
|
||||||
domain = request.config.host,
|
'aliases': [request.config.actor],
|
||||||
actor = request.config.actor
|
'links': [
|
||||||
)
|
{'href': request.config.actor, 'rel': 'self', 'type': 'application/activity+json'},
|
||||||
|
{'href': request.config.actor, 'rel': 'self', 'type': 'application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
return Response.new(data, ctype='json')
|
return Response.new(data, ctype='json')
|
||||||
|
|
||||||
|
|
||||||
@register_route('GET', '/nodeinfo/{version:\d.\d\.json}')
|
@register_route('GET', '/nodeinfo/{version:\d.\d\.json}')
|
||||||
async def nodeinfo(request):
|
async def nodeinfo_2_0(request):
|
||||||
niversion = request.match_info['version'][:3]
|
niversion = request.match_info['version'][:3]
|
||||||
|
data = {
|
||||||
|
'openRegistrations': not request.config.whitelist_enabled,
|
||||||
|
'protocols': ['activitypub'],
|
||||||
|
'services': {
|
||||||
|
'inbound': [],
|
||||||
|
'outbound': []
|
||||||
|
},
|
||||||
|
'software': {
|
||||||
|
'name': 'activityrelay',
|
||||||
|
'version': version
|
||||||
|
},
|
||||||
|
'usage': {
|
||||||
|
'localPosts': 0,
|
||||||
|
'users': {
|
||||||
|
'total': 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'metadata': {
|
||||||
|
'peers': request.database.hostnames
|
||||||
|
},
|
||||||
|
'version': niversion
|
||||||
|
}
|
||||||
|
|
||||||
data = dict(
|
if version == '2.1':
|
||||||
name = 'activityrelay',
|
data['software']['repository'] = 'https://git.pleroma.social/pleroma/relay'
|
||||||
version = version,
|
|
||||||
protocols = ['activitypub'],
|
|
||||||
open_regs = not request.config.whitelist_enabled,
|
|
||||||
users = 1,
|
|
||||||
metadata = {'peers': request.database.hostnames}
|
|
||||||
)
|
|
||||||
|
|
||||||
if niversion == '2.1':
|
return Response.new(data, ctype='json')
|
||||||
data['repo'] = 'https://git.pleroma.social/pleroma/relay'
|
|
||||||
|
|
||||||
return Response.new(aputils.Nodeinfo.new(**data), ctype='json')
|
|
||||||
|
|
||||||
|
|
||||||
@register_route('GET', '/.well-known/nodeinfo')
|
@register_route('GET', '/.well-known/nodeinfo')
|
||||||
async def nodeinfo_wellknown(request):
|
async def nodeinfo_wellknown(request):
|
||||||
data = aputils.WellKnownNodeinfo.new_template(request.config.host)
|
data = WKNodeinfo.new(
|
||||||
|
v20 = f'https://{request.config.host}/nodeinfo/2.0.json',
|
||||||
|
v21 = f'https://{request.config.host}/nodeinfo/2.1.json'
|
||||||
|
)
|
||||||
|
|
||||||
return Response.new(data, ctype='json')
|
return Response.new(data, ctype='json')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ install_requires =
|
||||||
click >= 8.1.2
|
click >= 8.1.2
|
||||||
pycryptodome >= 3.14.1
|
pycryptodome >= 3.14.1
|
||||||
PyYAML >= 5.0.0
|
PyYAML >= 5.0.0
|
||||||
aputils @ https://git.barkshark.xyz/barkshark/aputils/archive/0.1.2.tar.gz
|
aputils @ https://git.barkshark.xyz/barkshark/aputils/archive/0.1.1.tar.gz
|
||||||
python_requires = >=3.6
|
python_requires = >=3.6
|
||||||
|
|
||||||
[options.extras_require]
|
[options.extras_require]
|
||||||
|
|
Loading…
Reference in a new issue