kopia lustrzana https://github.com/snarfed/bridgy-fed
wm => AP: fix reposts from h-cites that turn into composite objects
instead of bare string id objects. thanks @gRegorLove for reporting!pull/489/head
rodzic
d2ab48b23e
commit
d9b1223392
|
@ -284,7 +284,7 @@ def signed_request(fn, url, data=None, log_data=True, headers=None, **kwargs):
|
|||
return resp
|
||||
|
||||
|
||||
def postprocess_as2(activity, target=None):
|
||||
def postprocess_as2(activity, target=None, wrap=True):
|
||||
"""Prepare an AS2 object to be served or sent via ActivityPub.
|
||||
|
||||
g.user is required. Populates it into the actor.id and publicKey fields.
|
||||
|
@ -293,6 +293,7 @@ def postprocess_as2(activity, target=None):
|
|||
activity: dict, AS2 object or activity
|
||||
target: dict, AS2 object, optional. The target of activity's inReplyTo or
|
||||
Like/Announce/etc object, if any.
|
||||
wrap: boolean, whether to wrap id, url, object, actor, and attributedTo
|
||||
"""
|
||||
if not activity or isinstance(activity, str):
|
||||
return activity
|
||||
|
@ -319,11 +320,12 @@ def postprocess_as2(activity, target=None):
|
|||
})
|
||||
return activity
|
||||
|
||||
for field in 'actor', 'attributedTo':
|
||||
activity[field] = [postprocess_as2_actor(actor)
|
||||
for actor in util.get_list(activity, field)]
|
||||
if len(activity[field]) == 1:
|
||||
activity[field] = activity[field][0]
|
||||
if wrap:
|
||||
for field in 'actor', 'attributedTo':
|
||||
activity[field] = [postprocess_as2_actor(actor, wrap=wrap)
|
||||
for actor in util.get_list(activity, field)]
|
||||
if len(activity[field]) == 1:
|
||||
activity[field] = activity[field][0]
|
||||
|
||||
# inReplyTo: singly valued, prefer id over url
|
||||
# TODO: ignore target, do for all inReplyTo
|
||||
|
@ -372,20 +374,20 @@ def postprocess_as2(activity, target=None):
|
|||
if not activity.get('id'):
|
||||
activity['id'] = util.get_first(activity, 'url')
|
||||
|
||||
# Deletes' object is our own id
|
||||
if type == 'Delete':
|
||||
activity['object'] = redirect_wrap(activity['object'])
|
||||
if wrap:
|
||||
# Deletes' object is our own id
|
||||
if type == 'Delete':
|
||||
activity['object'] = redirect_wrap(activity['object'])
|
||||
activity['id'] = redirect_wrap(activity.get('id'))
|
||||
activity['url'] = [redirect_wrap(u) for u in util.get_list(activity, 'url')]
|
||||
if len(activity['url']) == 1:
|
||||
activity['url'] = activity['url'][0]
|
||||
|
||||
# TODO: find a better way to check this, sometimes or always?
|
||||
# removed for now since it fires on posts without u-id or u-url, eg
|
||||
# https://chrisbeckstrom.com/2018/12/27/32551/
|
||||
# assert activity.get('id') or (isinstance(obj, dict) and obj.get('id'))
|
||||
|
||||
activity['id'] = redirect_wrap(activity.get('id'))
|
||||
activity['url'] = [redirect_wrap(u) for u in util.get_list(activity, 'url')]
|
||||
if len(activity['url']) == 1:
|
||||
activity['url'] = activity['url'][0]
|
||||
|
||||
# copy image(s) into attachment(s). may be Mastodon-specific.
|
||||
# https://github.com/snarfed/bridgy-fed/issues/33#issuecomment-440965618
|
||||
obj_or_activity = obj if obj.keys() > set(['id']) else activity
|
||||
|
@ -432,18 +434,20 @@ def postprocess_as2(activity, target=None):
|
|||
if not name.startswith('#'):
|
||||
tag['name'] = f'#{name}'
|
||||
|
||||
activity['object'] = postprocess_as2(activity.get('object'), target=target)
|
||||
activity['object'] = postprocess_as2(activity.get('object'), target=target,
|
||||
wrap=type in ('Create', 'Update', 'Delete'))
|
||||
|
||||
return util.trim_nulls(activity)
|
||||
|
||||
|
||||
def postprocess_as2_actor(actor):
|
||||
def postprocess_as2_actor(actor, wrap=True):
|
||||
"""Prepare an AS2 actor object to be served or sent via ActivityPub.
|
||||
|
||||
Modifies actor in place.
|
||||
|
||||
Args:
|
||||
actor: dict, AS2 actor object
|
||||
wrap: boolean, whether to wrap url
|
||||
|
||||
Returns:
|
||||
actor dict
|
||||
|
@ -457,7 +461,8 @@ def postprocess_as2_actor(actor):
|
|||
urls = [url]
|
||||
|
||||
domain = util.domain_from_link(urls[0], minimize=False)
|
||||
urls[0] = redirect_wrap(urls[0])
|
||||
if wrap:
|
||||
urls[0] = redirect_wrap(urls[0])
|
||||
|
||||
actor.setdefault('id', host_url(domain))
|
||||
actor.update({
|
||||
|
|
|
@ -120,6 +120,42 @@ REPOST_AS1_UNWRAPPED = {
|
|||
'object': 'https://mas.to/toot/id',
|
||||
'actor': ACTOR_AS1_UNWRAPPED,
|
||||
}
|
||||
|
||||
REPOST_HCITE_HTML = """\
|
||||
<html>
|
||||
<body class="h-entry">
|
||||
<a class="u-url" href="https://user.com/repost"></a>
|
||||
<div class="u-repost-of h-cite">
|
||||
<p>Reposted <a class="p-author h-card" href="https://mas.to/@foo">Mr. Foo</a>:</p>
|
||||
<a class="u-url" href="https://mas.to/toot/id">a post</a>
|
||||
</div>
|
||||
<a class="u-author h-card" href="https://user.com/">Ms. ☕ Baz</a>
|
||||
<a href="http://localhost/"></a>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
REPOST_HCITE = requests_response(REPOST_HTML, content_type=CONTENT_TYPE_HTML,
|
||||
url='https://user.com/repost')
|
||||
REPOST_HCITE_AS2 = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'type': 'Announce',
|
||||
'id': 'http://localhost/r/https://user.com/repost',
|
||||
'url': 'http://localhost/r/https://user.com/repost',
|
||||
'object': {
|
||||
'type': 'Note',
|
||||
'id': 'https://mas.to/toot/id',
|
||||
'url': 'https://mas.to/toot/id',
|
||||
'attributedTo': [{
|
||||
'type': 'Person',
|
||||
'url': 'https://mas.to/@foo',
|
||||
'name': 'Mr. Foo',
|
||||
}],
|
||||
'to': [as2.PUBLIC_AUDIENCE],
|
||||
},
|
||||
'to': [as2.PUBLIC_AUDIENCE],
|
||||
'actor': 'http://localhost/user.com',
|
||||
}
|
||||
|
||||
WEBMENTION_REL_LINK = requests_response(
|
||||
'<html><head><link rel="webmention" href="/webmention"></html>')
|
||||
WEBMENTION_NO_REL_LINK = requests_response('<html></html>')
|
||||
|
@ -598,10 +634,8 @@ class WebmentionTest(testutil.TestCase):
|
|||
'target': 'https://fed.brid.gy/',
|
||||
})
|
||||
self.assertEqual(200, got.status_code)
|
||||
|
||||
args, kwargs = mock_post.call_args
|
||||
self.assertEqual(('https://mas.to/inbox',), args)
|
||||
self.assert_equals(REPOST_AS2, json_loads(kwargs['data']))
|
||||
self.assert_deliveries(mock_post, ['https://mas.to/inbox'], REPOST_AS2,
|
||||
ignore=['cc'])
|
||||
|
||||
def test_skip_update_if_content_unchanged(self, mock_get, mock_post):
|
||||
"""https://github.com/snarfed/bridgy-fed/issues/78"""
|
||||
|
@ -649,10 +683,21 @@ class WebmentionTest(testutil.TestCase):
|
|||
self.assertEqual(('https://mas.to/inbox',), args)
|
||||
self.assert_equals(self.as2_create, json_loads(kwargs['data']))
|
||||
|
||||
def test_create_repost(self, mock_get, mock_post):
|
||||
def test_announce_repost(self, mock_get, mock_post):
|
||||
self._test_announce(REPOST_HTML, REPOST_AS2, mock_get, mock_post)
|
||||
|
||||
def test_announce_repost_composite_hcite(self, mock_get, mock_post):
|
||||
self._test_announce(REPOST_HCITE_HTML, REPOST_HCITE_AS2, mock_get, mock_post)
|
||||
|
||||
def _test_announce(self, html, expected_as2, mock_get, mock_post):
|
||||
self.make_followers()
|
||||
|
||||
mock_get.side_effect = [REPOST, self.toot_as2, self.actor]
|
||||
mock_get.side_effect = [
|
||||
requests_response(html, content_type=CONTENT_TYPE_HTML,
|
||||
url='https://user.com/repost'),
|
||||
self.toot_as2,
|
||||
self.actor,
|
||||
]
|
||||
mock_post.return_value = requests_response('abc xyz')
|
||||
|
||||
got = self.client.post('/_ah/queue/webmention', data={
|
||||
|
@ -669,19 +714,20 @@ class WebmentionTest(testutil.TestCase):
|
|||
|
||||
inboxes = ('https://inbox', 'https://public/inbox',
|
||||
'https://shared/inbox', 'https://mas.to/inbox')
|
||||
self.assert_deliveries(mock_post, inboxes, REPOST_AS2, ignore=['cc'])
|
||||
self.assert_deliveries(mock_post, inboxes, expected_as2, ignore=['cc'])
|
||||
|
||||
for args, kwargs in mock_get.call_args_list[1:]:
|
||||
with self.subTest(url=args[0]):
|
||||
rsa_key = kwargs['auth'].header_signer._rsa._key
|
||||
self.assertEqual(self.user.private_pem(), rsa_key.exportKey())
|
||||
|
||||
mf2 = util.parse_mf2(html)['items'][0]
|
||||
self.assert_object('https://user.com/repost',
|
||||
domains=['user.com'],
|
||||
source_protocol='webmention',
|
||||
status='complete',
|
||||
mf2=REPOST_MF2,
|
||||
as1=microformats2.json_to_object(REPOST_MF2),
|
||||
mf2=mf2,
|
||||
as1=microformats2.json_to_object(mf2),
|
||||
delivered=inboxes,
|
||||
type='share',
|
||||
object_ids=['https://mas.to/toot/id'],
|
||||
|
|
Ładowanie…
Reference in New Issue