actor: implement mastodon & pleroma relay handshakes

This commit is contained in:
kaniini 2018-10-30 02:49:38 +00:00
parent 5ab9ccf338
commit 36749620ec

View file

@ -1,5 +1,6 @@
import aiohttp import aiohttp
import aiohttp.web import aiohttp.web
import asyncio
import logging import logging
import uuid import uuid
import urllib.parse import urllib.parse
@ -65,8 +66,13 @@ app.router.add_get('/actor', actor)
from .http_signatures import sign_headers from .http_signatures import sign_headers
get_actor_inbox = lambda actor: actor.get('endpoints', {}).get('sharedInbox', actor['inbox'])
async def push_message_to_actor(actor, message, our_key_id): async def push_message_to_actor(actor, message, our_key_id):
url = urllib.parse.urlsplit(actor['inbox']) inbox = get_actor_inbox(actor)
url = urllib.parse.urlsplit(inbox)
# XXX: Digest # XXX: Digest
data = json.dumps(message) data = json.dumps(message)
@ -78,12 +84,12 @@ async def push_message_to_actor(actor, message, our_key_id):
} }
headers['signature'] = sign_headers(headers, PRIVKEY, our_key_id) headers['signature'] = sign_headers(headers, PRIVKEY, our_key_id)
logging.debug('%r', headers) logging.debug('%r >> %r', inbox, message)
logging.debug('%r >> %r', actor['inbox'], message)
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.post(actor['inbox'], data=data, headers=headers) as resp: async with session.post(inbox, data=data, headers=headers) as resp:
pass resp_payload = await resp.text()
logging.debug('%r >> resp %r', inbox, resp_payload)
async def follow_remote_actor(actor_uri): async def follow_remote_actor(actor_uri):
@ -134,6 +140,15 @@ async def handle_create(actor, data, request):
async def handle_follow(actor, data, request): async def handle_follow(actor, data, request):
global DATABASE
following = DATABASE.get('relay-list', [])
inbox = get_actor_inbox(actor)
if inbox not in following:
following += [inbox]
DATABASE['relay-list'] = following
message = { message = {
"@context": "https://www.w3.org/ns/activitystreams", "@context": "https://www.w3.org/ns/activitystreams",
"type": "Accept", "type": "Accept",
@ -150,12 +165,34 @@ async def handle_follow(actor, data, request):
"id": "https://{}/activities/{}".format(request.host, uuid.uuid4()), "id": "https://{}/activities/{}".format(request.host, uuid.uuid4()),
} }
await push_message_to_actor(actor, message, 'https://{}/actor#main-key'.format(request.host))
asyncio.ensure_future(push_message_to_actor(actor, message, 'https://{}/actor#main-key'.format(request.host)))
if data['object'].endswith('/actor'):
asyncio.ensure_future(follow_remote_actor(actor['id']))
async def handle_undo(actor, data, request):
global DATABASE
child = data['object']
if child['type'] == 'Follow':
following = DATABASE.get('relay-list', [])
inbox = get_actor_inbox(actor)
if inbox in following:
following.remove(inbox)
DATABASE['relay-list'] = following
if child['object'].endswith('/actor'):
await unfollow_remote_actor(actor['id'])
processors = { processors = {
'Create': handle_create, 'Create': handle_create,
'Follow': handle_follow 'Follow': handle_follow,
'Undo': handle_undo
} }
@ -168,6 +205,8 @@ async def inbox(request):
actor = await fetch_actor(data["actor"]) actor = await fetch_actor(data["actor"])
actor_uri = 'https://{}/actor'.format(request.host) actor_uri = 'https://{}/actor'.format(request.host)
logging.debug(">> payload %r", data)
processor = processors.get(data['type'], None) processor = processors.get(data['type'], None)
if processor: if processor:
await processor(actor, data, request) await processor(actor, data, request)