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