move accept_follow from activitypub to protocol

pull/448/head
Ryan Barrett 2023-03-11 12:58:36 -08:00
rodzic 9cc8451182
commit 01768fd58e
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
2 zmienionych plików z 65 dodań i 58 usunięć

Wyświetl plik

@ -194,61 +194,6 @@ class ActivityPub(Protocol):
else:
error('HTTP Signature verification failed', status=401)
@classmethod
def accept_follow(cls, obj, user):
"""Replies to an AP Follow request with an Accept request.
TODO: move to Protocol
Args:
obj: :class:`Object`
user: :class:`User`
"""
logger.info('Replying to Follow with Accept')
followee = obj.as2.get('object')
followee_id = followee.get('id') if isinstance(followee, dict) else followee
follower = obj.as2.get('actor')
if not followee or not followee_id or not follower:
error(f'Follow activity requires object and actor. Got: {follow}')
inbox = follower.get('inbox')
follower_id = follower.get('id')
if not inbox or not follower_id:
error(f'Follow actor requires id and inbox. Got: {follower}')
# rendered mf2 HTML proxy pages (in render.py) fall back to redirecting to
# the follow's AS2 id field, but Mastodon's ids are URLs that don't load in
# browsers, eg https://jawns.club/ac33c547-ca6b-4351-80d5-d11a6879a7b0
# so, set a synthetic URL based on the follower's profile.
# https://github.com/snarfed/bridgy-fed/issues/336
follower_url = util.get_url(follower) or follower_id
followee_url = util.get_url(followee) or followee_id
obj.as2.setdefault('url', f'{follower_url}#followed-{followee_url}')
# store Follower
follower_obj = Follower.get_or_create(
dest=user.key.id(), src=follower_id, last_follow=obj.as2)
follower_obj.status = 'active'
follower_obj.put()
# send AP Accept
followee_actor_url = common.host_url(user.key.id())
accept = {
'@context': 'https://www.w3.org/ns/activitystreams',
'id': util.tag_uri(common.PRIMARY_DOMAIN,
f'accept/{user.key.id()}/{obj.key.id()}'),
'type': 'Accept',
'actor': followee_actor_url,
'object': {
'type': 'Follow',
'actor': follower_id,
'object': followee_actor_url,
}
}
return cls.send(inbox, accept, user=user)
def signed_get(url, *, user=None, **kwargs):
return signed_request(util.requests_get, url, user=user, **kwargs)
@ -545,8 +490,9 @@ def inbox(domain=None):
body = request.get_data(as_text=True)
error(f"Couldn't parse body as non-empty JSON mapping: {body}", exc_info=True)
type = activity.get('type')
actor_id = as1.get_object(activity, 'actor').get('id')
logger.info(f'Got {activity.get("type")} activity from {actor_id}: {json_dumps(activity, indent=2)}')
logger.info(f'Got {type} from {actor_id}: {json_dumps(activity, indent=2)}')
# load user
# TODO: store in g instead of passing around
@ -562,10 +508,22 @@ def inbox(domain=None):
# follows, or other activity types, since Mastodon doesn't currently mark
# those as explicitly public. Use as2's is_public instead of as1's because
# as1's interprets unlisted as true.
if activity.get('type') == 'Create' and not as2.is_public(activity):
if type == 'Create' and not as2.is_public(activity):
logger.info('Dropping non-public activity')
return 'OK'
if type == 'Follow':
# rendered mf2 HTML proxy pages (in render.py) fall back to redirecting
# to the follow's AS2 id field, but Mastodon's Accept ids are URLs that
# don't load in browsers, eg:
# https://jawns.club/ac33c547-ca6b-4351-80d5-d11a6879a7b0
#
# so, set a synthetic URL based on the follower's profile.
# https://github.com/snarfed/bridgy-fed/issues/336
follower_url = redirect_unwrap(util.get_url(activity, 'actor'))
followee_url = redirect_unwrap(util.get_url(activity, 'object'))
activity.setdefault('url', f'{follower_url}#followed-{followee_url}')
return ActivityPub.receive(activity.get('id'), user=user,
as2=redirect_unwrap(activity))

Wyświetl plik

@ -12,6 +12,7 @@ from common import error
# import module instead of individual classes to avoid circular import
import models
from oauth_dropins.webutil import util, webmention
from oauth_dropins.webutil.util import json_dumps, json_loads
SUPPORTED_TYPES = (
'accept',
@ -114,6 +115,8 @@ class Protocol:
obj.populate(source_protocol=cls.LABEL, **props)
obj.put()
logging.info(f'Got AS1: {json_dumps(obj.as1, indent=2)}')
if obj.type not in SUPPORTED_TYPES:
error(f'Sorry, {obj.type} activities are not supported yet.', status=501)
@ -193,7 +196,7 @@ class Protocol:
inner_obj = obj.as2['object'] = cls.get_object(inner_obj_id, user=user).as2
if obj.type == 'follow':
resp = cls.accept_follow(obj, user)
cls.accept_follow(obj, user=user)
# send webmentions to each target
send_webmentions(obj, proxy=True)
@ -215,6 +218,52 @@ class Protocol:
obj.put()
return 'OK'
@classmethod
def accept_follow(cls, obj, *, user=None):
"""Replies to an AP Follow request with an Accept request.
TODO: move to Protocol
Args:
obj: :class:`Object`
user: :class:`User`
"""
logger.info('Replying to Follow with Accept')
followee = as1.get_object(obj.as1)
followee_id = followee.get('id')
follower = as1.get_object(obj.as1, 'actor')
if not followee or not followee_id or not follower:
error(f'Follow activity requires object and actor. Got: {follow}')
inbox = follower.get('inbox')
follower_id = follower.get('id')
if not inbox or not follower_id:
error(f'Follow actor requires id and inbox. Got: {follower}')
# store Follower
follower_obj = models.Follower.get_or_create(
dest=user.key.id(), src=follower_id, last_follow=obj.as2)
follower_obj.status = 'active'
follower_obj.put()
# send AP Accept
followee_actor_url = common.host_url(user.key.id())
accept = {
'@context': 'https://www.w3.org/ns/activitystreams',
'id': util.tag_uri(common.PRIMARY_DOMAIN,
f'accept/{user.key.id()}/{obj.key.id()}'),
'type': 'Accept',
'actor': followee_actor_url,
'object': {
'type': 'Follow',
'actor': follower_id,
'object': followee_actor_url,
}
}
return cls.send(inbox, accept, user=user)
@classmethod
@cached(LRUCache(1000), key=lambda cls, id, user=None: util.fragmentless(id),
lock=threading.Lock())