diff --git a/activitypub.py b/activitypub.py index 64c2109..425931f 100644 --- a/activitypub.py +++ b/activitypub.py @@ -706,21 +706,16 @@ def postprocess_as2_actor(actor, wrap=True): # source protocol in subdomain. # WARNING: the user page handler in pages.py overrides this for fediverse # addresses with leading @ character. be careful when changing this route! -@app.get(f'/ap/', defaults={'protocol': None}) -# source protocol in path; primarily for localhost testing -@app.get(f'/ap//') +@app.get(f'/ap/') +# source protocol in path; primarily for backcompat +@app.get(f'/ap/web/') # special case Web users without /ap/web/ prefix, for backward compatibility -@app.get(f'/', defaults={'protocol': 'web'}) +@app.get(f'/') @flask_util.cached(cache, CACHE_TIME) -def actor(protocol, handle_or_id): +def actor(handle_or_id): """Serves a user's AS2 actor from the datastore.""" - if protocol: - cls = PROTOCOLS[protocol] - else: - cls = Protocol.for_request(fed=None) - - if not cls: - error(f"Couldn't determine protocol") + cls = Protocol.for_request(fed=PROTOCOLS['web']) + assert cls if cls.owns_id(handle_or_id) is False: if cls.owns_handle(handle_or_id) is False: @@ -778,11 +773,12 @@ def actor(protocol, handle_or_id): # note that this path overlaps with the /ap/ actor route above, # but doesn't collide because this is POST and that one is GET. @app.post('/ap/sharedInbox') -@app.post(f'/ap///inbox') +# TODO: protocol in subdomain +@app.post(f'/ap///inbox') # special case Web users without /ap/web/ prefix, for backward compatibility @app.post('/inbox') -@app.post(f'//inbox', defaults={'protocol': 'web'}) -def inbox(protocol=None, domain=None): +@app.post(f'//inbox') +def inbox(protocol='web', id=None): """Handles ActivityPub inbox delivery.""" # parse and validate AS2 activity try: @@ -799,23 +795,23 @@ def inbox(protocol=None, domain=None): # load receiving user obj_id = as1.get_object(redirect_unwrap(activity)).get('id') - receiving_proto = receiving_user_id = None + to_proto = None if protocol: - receiving_proto = PROTOCOLS[protocol] + to_proto = PROTOCOLS[protocol] elif type == 'Follow': - receiving_proto = Protocol.for_id(obj_id) + to_proto = Protocol.for_id(obj_id) - if receiving_proto: - if domain: - assert receiving_proto is web.Web, 'https://github.com/snarfed/bridgy-fed/issues/611' - receiving_user_id = domain + if to_proto: + to_user_id = None + if id: + to_user_id = id else: - receiving_key = receiving_proto.key_for(obj_id) - if receiving_key: - receiving_user_id = receiving_key.id() + to_key = to_proto.key_for(obj_id) + if to_key: + to_user_id = to_key.id() - if receiving_user_id: - g.user = receiving_proto.get_or_create(receiving_user_id, direct=False) + if to_user_id: + g.user = to_proto.get_or_create(to_user_id, direct=False) logger.info(f'Setting g.user to {g.user.key}') if not g.user.direct and actor_id: # this is a deliberate interaction with an indirect receiving user; @@ -849,21 +845,25 @@ def inbox(protocol=None, domain=None): return ActivityPub.receive(obj) -@app.get(f'/ap///') +# protocol in subdomain +@app.get(f'/ap//') +# source protocol in path; primarily for backcompat +@app.get(f'/ap/web//') # special case Web users without /ap/web/ prefix, for backward compatibility -@app.get(f'//', - defaults={'protocol': 'web'}) +@app.get(f'//') @flask_util.cached(cache, CACHE_TIME) -def follower_collection(protocol, domain, collection): +def follower_collection(id, collection): """ActivityPub Followers and Following collections. - https://www.w3.org/TR/activitypub/#followers - https://www.w3.org/TR/activitypub/#collections - https://www.w3.org/TR/activitystreams-core/#paging + * https://www.w3.org/TR/activitypub/#followers + * https://www.w3.org/TR/activitypub/#collections + * https://www.w3.org/TR/activitystreams-core/#paging """ - g.user = PROTOCOLS[protocol].get_by_id(domain) + protocol = Protocol.for_request(fed=PROTOCOLS['web']) + assert protocol + g.user = protocol.get_by_id(id) if not g.user: - return f'{protocol} user {domain} not found', 404 + return f'{protocol} user {id} not found', 404 # page followers, new_before, new_after = Follower.fetch_page(collection) @@ -896,7 +896,7 @@ def follower_collection(protocol, domain, collection): '@context': 'https://www.w3.org/ns/activitystreams', 'id': request.base_url, 'type': 'Collection', - 'summary': f"{domain}'s {collection}", + 'summary': f"{id}'s {collection}", 'totalItems': count, 'first': page, } @@ -904,14 +904,19 @@ def follower_collection(protocol, domain, collection): return collection, {'Content-Type': as2.CONTENT_TYPE} -@app.get(f'/ap///outbox') +# protocol in subdomain +@app.get(f'/ap//outbox') +# source protocol in path; primarily for backcompat +@app.get(f'/ap/web//outbox') # special case Web users without /ap/web/ prefix, for backward compatibility -@app.get(f'//outbox', defaults={'protocol': 'web'}) -def outbox(protocol, domain): +@app.get(f'//outbox') +def outbox(id): + protocol = Protocol.for_request(fed=PROTOCOLS['web']) + assert protocol return { '@context': 'https://www.w3.org/ns/activitystreams', 'id': request.url, - 'summary': f"{domain}'s outbox", + 'summary': f"{id}'s outbox", 'type': 'OrderedCollection', 'totalItems': 0, 'first': { diff --git a/tests/test_activitypub.py b/tests/test_activitypub.py index bc14ecd..ffb38b7 100644 --- a/tests/test_activitypub.py +++ b/tests/test_activitypub.py @@ -1340,17 +1340,18 @@ class ActivityPubTest(TestCase): def test_followers_collection_fake(self, *_): self.make_user('foo.com', cls=Fake) - resp = self.client.get('/ap/fake/foo.com/followers') + resp = self.client.get('/ap/foo.com/followers', + base_url='https://fa.brid.gy') self.assertEqual(200, resp.status_code) self.assertEqual({ '@context': 'https://www.w3.org/ns/activitystreams', - 'id': 'http://localhost/ap/fake/foo.com/followers', + 'id': 'https://fa.brid.gy/ap/foo.com/followers', 'type': 'Collection', 'summary': "foo.com's followers", 'totalItems': 0, 'first': { 'type': 'CollectionPage', - 'partOf': 'http://localhost/ap/fake/foo.com/followers', + 'partOf': 'https://fa.brid.gy/ap/foo.com/followers', 'items': [], }, }, resp.json) @@ -1471,17 +1472,18 @@ class ActivityPubTest(TestCase): def test_outbox_fake(self, *_): self.make_user('foo.com', cls=Fake) - resp = self.client.get(f'/ap/fake/foo.com/outbox') + resp = self.client.get(f'/ap/foo.com/outbox', + base_url='https://fa.brid.gy') self.assertEqual(200, resp.status_code) self.assertEqual({ '@context': 'https://www.w3.org/ns/activitystreams', - 'id': 'http://localhost/ap/fake/foo.com/outbox', + 'id': 'https://fa.brid.gy/ap/foo.com/outbox', 'summary': "foo.com's outbox", 'type': 'OrderedCollection', 'totalItems': 0, 'first': { 'type': 'CollectionPage', - 'partOf': 'http://localhost/ap/fake/foo.com/outbox', + 'partOf': 'https://fa.brid.gy/ap/foo.com/outbox', 'items': [], }, }, resp.json)