diff --git a/activitypub.py b/activitypub.py index 3621511..e7c1608 100644 --- a/activitypub.py +++ b/activitypub.py @@ -336,8 +336,8 @@ class ActivityPub(User, Protocol): # AP implementations choke on objects. # https://github.com/snarfed/bridgy-fed/issues/658 # - # TODO: expand this to general purpose compact() function and use elsewhere, - # eg in models.resolve_id + # TODO: expand this to general purpose compact() function and use + # elsewhere, eg in models.resolve_id for o in translated, as1.get_object(translated): for field in 'actor', 'attributedTo', 'author': actors = as1.get_objects(o, field) @@ -345,9 +345,16 @@ class ActivityPub(User, Protocol): o[field] = ids[0] if len(ids) == 1 else ids converted = as2.from_as1(translated) + if obj.source_protocol in ('ap', 'activitypub'): return converted + if converted.get('type') == 'Person': + return postprocess_as2_actor(converted) + + if as1.get_object(converted).get('type') == 'Person': + converted['object'] = postprocess_as2_actor(converted['object']) + return postprocess_as2(converted, **kwargs) @classmethod @@ -549,25 +556,6 @@ def postprocess_as2(activity, orig_obj=None, wrap=True): type = activity.get('type') - # actor objects - if type == 'Person': - postprocess_as2_actor(activity) - if g.user and not activity.get('publicKey'): - # underspecified, inferred from this issue and Mastodon's implementation: - # https://github.com/w3c/activitypub/issues/203#issuecomment-297553229 - # https://github.com/tootsuite/mastodon/blob/bc2c263504e584e154384ecc2d804aeb1afb1ba3/app/services/activitypub/process_account_service.rb#L77 - actor_url = g.user.ap_actor() - activity.update({ - 'publicKey': { - 'id': f'{actor_url}#key', - 'owner': actor_url, - 'publicKeyPem': g.user.public_pem().decode(), - }, - '@context': (util.get_list(activity, '@context') + - ['https://w3id.org/security/v1']), - }) - return activity - # inReplyTo: singly valued, prefer id over url # TODO: ignore orig_obj, do for all inReplyTo orig_id = orig_obj.get('id') if orig_obj else None @@ -714,7 +702,7 @@ def postprocess_as2_actor(actor, wrap=True): return g.user.ap_actor() return redirect_wrap(actor) - url = g.user.web_url() if g.user else None + url = g.user.web_url() urls = util.get_list(actor, 'url') if not urls and url: urls = [url] @@ -722,7 +710,7 @@ def postprocess_as2_actor(actor, wrap=True): urls[0] = redirect_wrap(urls[0]) id = actor.get('id') - if g.user and (not id or g.user.is_web_url(id)): + if not id or g.user.is_web_url(id): actor['id'] = g.user.ap_actor() actor['url'] = urls[0] if len(urls) == 1 else urls @@ -754,6 +742,22 @@ def postprocess_as2_actor(actor, wrap=True): # required by pixelfed. https://github.com/snarfed/bridgy-fed/issues/39 actor.setdefault('summary', '') + + if not actor.get('publicKey'): + # underspecified, inferred from this issue and Mastodon's implementation: + # https://github.com/w3c/activitypub/issues/203#issuecomment-297553229 + # https://github.com/tootsuite/mastodon/blob/bc2c263504e584e154384ecc2d804aeb1afb1ba3/app/services/activitypub/process_account_service.rb#L77 + actor_url = g.user.ap_actor() + actor.update({ + 'publicKey': { + 'id': f'{actor_url}#key', + 'owner': actor_url, + 'publicKeyPem': g.user.public_pem().decode(), + }, + '@context': (util.get_list(actor, '@context') + + ['https://w3id.org/security/v1']), + }) + return actor @@ -799,7 +803,7 @@ def actor(handle_or_id): '@context': [as2.CONTEXT], 'type': 'Person', } - actor = postprocess_as2(actor) + actor = postprocess_as2_actor(actor) actor.update({ 'id': user.ap_actor(), 'inbox': user.ap_actor('inbox'), diff --git a/tests/test_activitypub.py b/tests/test_activitypub.py index 37dda31..a9ffd8e 100644 --- a/tests/test_activitypub.py +++ b/tests/test_activitypub.py @@ -22,7 +22,12 @@ from werkzeug.exceptions import BadGateway from .testutil import Fake, TestCase import activitypub -from activitypub import ActivityPub, default_signature_user, postprocess_as2 +from activitypub import ( + ActivityPub, + default_signature_user, + postprocess_as2, + postprocess_as2_actor, +) from atproto import ATProto import common from models import Follower, Object @@ -1773,9 +1778,9 @@ class ActivityPubUtilsTest(TestCase): ], })) - def test_postprocess_as2_url_attachments(self): + def test_postprocess_as2_actor_url_attachments(self): g.user = self.user - got = postprocess_as2(as2.from_as1({ + got = postprocess_as2_actor(as2.from_as1({ 'objectType': 'person', 'urls': [ { @@ -1813,12 +1818,12 @@ class ActivityPubUtilsTest(TestCase): 'value': 'two', }], got['attachment']) - def test_postprocess_as2_preserves_preferredUsername(self): + def test_postprocess_as2_actor_preserves_preferredUsername(self): # preferredUsername stays y.z despite user's username. since Mastodon # queries Webfinger for preferredUsername@fed.brid.gy # https://github.com/snarfed/bridgy-fed/issues/77#issuecomment-949955109 g.user = self.user - self.assertEqual('user.com', postprocess_as2({ + self.assertEqual('user.com', postprocess_as2_actor({ 'type': 'Person', 'url': 'https://user.com/about-me', 'preferredUsername': 'nick', diff --git a/tests/test_web.py b/tests/test_web.py index aee698d..8f5b147 100644 --- a/tests/test_web.py +++ b/tests/test_web.py @@ -1592,6 +1592,7 @@ class WebTest(TestCase): **ACTOR_AS2, 'attachment': ACTOR_AS2_FULL['attachment'], 'updated': NOW.isoformat(), + 'to': ['https://www.w3.org/ns/activitystreams#Public'], }, 'to': ['https://www.w3.org/ns/activitystreams#Public'], }