kopia lustrzana https://github.com/snarfed/bridgy-fed
rodzic
0f11cd1ff1
commit
42ad9d1998
|
@ -119,44 +119,46 @@ class InboxHandler(webapp2.RequestHandler):
|
|||
|
||||
# TODO: verify signature if there is one
|
||||
|
||||
if type == 'Follow':
|
||||
self.accept_follow(activity)
|
||||
return
|
||||
|
||||
# fetch actor if necessary so we have name, profile photo, etc
|
||||
if type in ('Like', 'Announce'):
|
||||
if type in ('Announce', 'Like', 'Follow'):
|
||||
for elem in obj, activity:
|
||||
actor = elem.get('actor')
|
||||
if actor and isinstance(actor, basestring):
|
||||
elem['actor'] = common.get_as2(actor).json()
|
||||
|
||||
# send webmentions to each target
|
||||
as1 = as2.to_as1(activity)
|
||||
source_as2 = json.dumps(common.redirect_unwrap(activity))
|
||||
common.send_webmentions(self, as1, proxy=True, protocol='activitypub',
|
||||
source_as2=source_as2)
|
||||
activity_unwrapped = common.redirect_unwrap(activity)
|
||||
if type == 'Follow':
|
||||
self.accept_follow(activity, activity_unwrapped)
|
||||
return
|
||||
|
||||
def accept_follow(self, follow):
|
||||
# send webmentions to each target
|
||||
as1 = as2.to_as1(activity_unwrapped)
|
||||
common.send_webmentions(self, as1, proxy=True, protocol='activitypub',
|
||||
source_as2=json.dumps(activity_unwrapped))
|
||||
|
||||
def accept_follow(self, follow, follow_unwrapped):
|
||||
"""Replies to an AP Follow request with an Accept request.
|
||||
|
||||
Args:
|
||||
follow: dict, AP Follow activity
|
||||
follow_unwrapped: dict, same, except with redirect URLs unwrapped
|
||||
"""
|
||||
logging.info('Replying to Follow with Accept')
|
||||
|
||||
obj = follow.get('object')
|
||||
actor = follow.get('actor')
|
||||
if not obj or not actor:
|
||||
followee = follow.get('object')
|
||||
followee_unwrapped = follow_unwrapped.get('object')
|
||||
follower = follow.get('actor')
|
||||
if not followee or not followee_unwrapped or not follower:
|
||||
common.error(self, 'Follow activity requires object and actor. Got: %s' % follow)
|
||||
|
||||
actor_full = common.get_as2(actor).json()
|
||||
inbox = actor_full.get('inbox')
|
||||
if not inbox:
|
||||
common.error(self, 'Found no inbox for actor %s', actor)
|
||||
inbox = follower.get('inbox')
|
||||
follower_id = follower.get('id')
|
||||
if not inbox or not follower_id:
|
||||
common.error(self, 'Follow actor requires id and inbox. Got: %s', follower)
|
||||
|
||||
# store Follower
|
||||
user_domain = util.domain_from_link(common.redirect_unwrap(obj))
|
||||
Follower.get_or_create(user_domain, actor, last_follow=json.dumps(follow))
|
||||
user_domain = util.domain_from_link(followee_unwrapped)
|
||||
Follower.get_or_create(user_domain, follower_id, last_follow=json.dumps(follow))
|
||||
|
||||
# send AP Accept
|
||||
accept = {
|
||||
|
@ -164,11 +166,11 @@ class InboxHandler(webapp2.RequestHandler):
|
|||
'id': util.tag_uri(appengine_config.HOST, 'accept/%s/%s' % (
|
||||
(user_domain, follow.get('id')))),
|
||||
'type': 'Accept',
|
||||
'actor': obj,
|
||||
'actor': followee,
|
||||
'object': {
|
||||
'type': 'Follow',
|
||||
'actor': actor,
|
||||
'object': obj,
|
||||
'type': 'Follow',
|
||||
'actor': follower_id,
|
||||
'object': followee,
|
||||
}
|
||||
}
|
||||
resp = send(accept, inbox, user_domain)
|
||||
|
@ -176,9 +178,9 @@ class InboxHandler(webapp2.RequestHandler):
|
|||
self.response.write(resp.text)
|
||||
|
||||
# send webmention
|
||||
unwrapped_as2 = common.redirect_unwrap(follow)
|
||||
common.send_webmentions(self, as2.to_as1(follow), proxy=True,
|
||||
protocol='activitypub', source_as2=json.dumps(follow))
|
||||
common.send_webmentions(
|
||||
self, as2.to_as1(follow), proxy=True, protocol='activitypub',
|
||||
source_as2=json.dumps(follow_unwrapped))
|
||||
|
||||
|
||||
app = webapp2.WSGIApplication([
|
||||
|
|
|
@ -50,14 +50,41 @@ LIKE = {
|
|||
}
|
||||
LIKE_WRAPPED = copy.deepcopy(LIKE)
|
||||
LIKE_WRAPPED['object'] = common.redirect_wrap(LIKE_WRAPPED['object'])
|
||||
LIKE_WITH_ACTOR = copy.deepcopy(LIKE)
|
||||
LIKE_WITH_ACTOR['actor'] = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': 'http://orig/actor',
|
||||
'type': 'Person',
|
||||
'name': 'Ms. Actor',
|
||||
'preferredUsername': 'msactor',
|
||||
'image': {'type': 'Image', 'url': 'http://orig/pic.jpg'},
|
||||
}
|
||||
|
||||
FOLLOW_WRAPPED = {
|
||||
FOLLOW = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': 'https://mastodon.social/6d1a',
|
||||
'type': 'Follow',
|
||||
'actor': 'https://mastodon.social/users/swentel',
|
||||
'object': 'http://localhost/realize.be',
|
||||
'object': 'https://realize.be/',
|
||||
}
|
||||
FOLLOW_WRAPPED = copy.deepcopy(FOLLOW)
|
||||
FOLLOW_WRAPPED['object'] = 'http://localhost/realize.be'
|
||||
ACTOR = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': FOLLOW['actor'],
|
||||
'type': 'Person',
|
||||
'inbox': 'http://follower/inbox',
|
||||
}
|
||||
FOLLOW_WITH_ACTOR = copy.deepcopy(FOLLOW)
|
||||
FOLLOW_WITH_ACTOR['actor'] = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': FOLLOW['actor'],
|
||||
'type': 'Person',
|
||||
'inbox': 'http://follower/inbox',
|
||||
}
|
||||
FOLLOW_WRAPPED_WITH_ACTOR = copy.deepcopy(FOLLOW_WRAPPED)
|
||||
FOLLOW_WRAPPED_WITH_ACTOR['actor'] = FOLLOW_WITH_ACTOR['actor']
|
||||
|
||||
ACCEPT = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'type': 'Accept',
|
||||
|
@ -155,18 +182,10 @@ class ActivityPubTest(testutil.TestCase):
|
|||
self.assertEqual(expected_as2, json.loads(resp.source_as2))
|
||||
|
||||
def test_inbox_like(self, mock_head, mock_get, mock_post):
|
||||
actor = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': 'http://orig/actor',
|
||||
'type': 'Person',
|
||||
'name': 'Ms. Actor',
|
||||
'preferredUsername': 'msactor',
|
||||
'image': {'type': 'Image', 'url': 'http://orig/pic.jpg'},
|
||||
}
|
||||
mock_head.return_value = requests_response(url='http://orig/post')
|
||||
mock_get.side_effect = [
|
||||
# source actor
|
||||
requests_response(actor, headers={'Content-Type': common.CONTENT_TYPE_AS2}),
|
||||
requests_response(LIKE_WITH_ACTOR['actor'], headers={'Content-Type': common.CONTENT_TYPE_AS2}),
|
||||
# target post webmention discovery
|
||||
requests_response(
|
||||
'<html><head><link rel="webmention" href="/webmention"></html>'),
|
||||
|
@ -196,22 +215,14 @@ class ActivityPubTest(testutil.TestCase):
|
|||
self.assertEqual('in', resp.direction)
|
||||
self.assertEqual('activitypub', resp.protocol)
|
||||
self.assertEqual('complete', resp.status)
|
||||
like_activity = copy.deepcopy(LIKE)
|
||||
like_activity['actor'] = actor
|
||||
self.assertEqual(like_activity, json.loads(resp.source_as2))
|
||||
self.assertEqual(LIKE_WITH_ACTOR, json.loads(resp.source_as2))
|
||||
|
||||
def test_inbox_follow_accept(self, mock_head, mock_get, mock_post):
|
||||
follower = FOLLOW_WRAPPED['actor']
|
||||
actor = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': follower,
|
||||
'type': 'Person',
|
||||
'inbox': 'http://follower/inbox',
|
||||
}
|
||||
mock_head.return_value = requests_response(url='https://realize.be/')
|
||||
mock_get.side_effect = [
|
||||
# source actor
|
||||
requests_response(actor, content_type=common.CONTENT_TYPE_AS2),
|
||||
requests_response(FOLLOW_WITH_ACTOR['actor'],
|
||||
content_type=common.CONTENT_TYPE_AS2),
|
||||
# target post webmention discovery
|
||||
requests_response(
|
||||
'<html><head><link rel="webmention" href="/webmention"></html>'),
|
||||
|
@ -225,7 +236,7 @@ class ActivityPubTest(testutil.TestCase):
|
|||
as2_headers = copy.deepcopy(common.HEADERS)
|
||||
as2_headers.update(common.CONNEG_HEADERS_AS2_HTML)
|
||||
mock_get.assert_has_calls((
|
||||
call(follower, headers=as2_headers, timeout=15),
|
||||
call(FOLLOW['actor'], headers=as2_headers, timeout=15),
|
||||
))
|
||||
|
||||
# check AP Accept
|
||||
|
@ -246,11 +257,11 @@ class ActivityPubTest(testutil.TestCase):
|
|||
self.assertEqual('in', resp.direction)
|
||||
self.assertEqual('activitypub', resp.protocol)
|
||||
self.assertEqual('complete', resp.status)
|
||||
self.assertEqual(FOLLOW_WRAPPED, json.loads(resp.source_as2))
|
||||
self.assertEqual(FOLLOW_WITH_ACTOR, json.loads(resp.source_as2))
|
||||
|
||||
# check that we stored a Follower object
|
||||
follower = Follower.get_by_id('realize.be %s' % (follower))
|
||||
self.assertEqual(FOLLOW_WRAPPED, json.loads(follower.last_follow))
|
||||
follower = Follower.get_by_id('realize.be %s' % (FOLLOW['actor']))
|
||||
self.assertEqual(FOLLOW_WRAPPED_WITH_ACTOR, json.loads(follower.last_follow))
|
||||
|
||||
def test_inbox_unsupported_type(self, *_):
|
||||
got = app.get_response('/foo.com/inbox', method='POST', body=json.dumps({
|
||||
|
|
Ładowanie…
Reference in New Issue