kopia lustrzana https://github.com/snarfed/bridgy-fed
move accept_follow from activitypub to protocol
rodzic
9cc8451182
commit
01768fd58e
|
@ -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))
|
||||
|
||||
|
|
51
protocol.py
51
protocol.py
|
@ -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())
|
||||
|
|
Ładowanie…
Reference in New Issue