kopia lustrzana https://github.com/snarfed/bridgy-fed
rodzic
5f4d6757e7
commit
9c62786f06
|
@ -474,6 +474,7 @@ class Protocol:
|
||||||
|
|
||||||
# fetch actor if necessary so we have name, profile photo, etc
|
# fetch actor if necessary so we have name, profile photo, etc
|
||||||
if actor and actor.keys() == set(['id']):
|
if actor and actor.keys() == set(['id']):
|
||||||
|
logger.info('Fetching actor so we have name, profile photo, etc')
|
||||||
actor_obj = cls.load(actor['id'])
|
actor_obj = cls.load(actor['id'])
|
||||||
if actor_obj.as1:
|
if actor_obj.as1:
|
||||||
obj.our_as1 = {**obj.as1, 'actor': actor_obj.as1}
|
obj.our_as1 = {**obj.as1, 'actor': actor_obj.as1}
|
||||||
|
@ -481,6 +482,7 @@ class Protocol:
|
||||||
# fetch object if necessary so we can render it in feeds
|
# fetch object if necessary so we can render it in feeds
|
||||||
if obj.type == 'share' and inner_obj_as1.keys() == set(['id']):
|
if obj.type == 'share' and inner_obj_as1.keys() == set(['id']):
|
||||||
if not inner_obj and cls.owns_id(inner_obj_id):
|
if not inner_obj and cls.owns_id(inner_obj_id):
|
||||||
|
logger.info('Fetching object so we can render it in feeds')
|
||||||
inner_obj = cls.load(inner_obj_id)
|
inner_obj = cls.load(inner_obj_id)
|
||||||
if inner_obj and inner_obj.as1:
|
if inner_obj and inner_obj.as1:
|
||||||
obj.our_as1 = {
|
obj.our_as1 = {
|
||||||
|
@ -673,7 +675,7 @@ class Protocol:
|
||||||
sent = protocol.send(obj, target.uri, log_data=log_data)
|
sent = protocol.send(obj, target.uri, log_data=log_data)
|
||||||
if sent:
|
if sent:
|
||||||
add(obj.delivered, target)
|
add(obj.delivered, target)
|
||||||
obj.undelivered.remove(target)
|
obj.undelivered.remove(target)
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
code, body = util.interpret_http_exception(e)
|
code, body = util.interpret_http_exception(e)
|
||||||
if not code and not body:
|
if not code and not body:
|
||||||
|
|
|
@ -276,6 +276,8 @@ class ActivityPubTest(TestCase):
|
||||||
|
|
||||||
self.user = self.make_user('user.com', has_hcard=True, has_redirects=True,
|
self.user = self.make_user('user.com', has_hcard=True, has_redirects=True,
|
||||||
obj_as2={**ACTOR, 'id': 'https://user.com/'})
|
obj_as2={**ACTOR, 'id': 'https://user.com/'})
|
||||||
|
self.swentel_key = ndb.Key(ActivityPub, 'https://mas.to/users/swentel')
|
||||||
|
self.user_actor_key = ndb.Key(ActivityPub, 'https://user.com/actor')
|
||||||
|
|
||||||
ACTOR_BASE['publicKey']['publicKeyPem'] = self.user.public_pem().decode()
|
ACTOR_BASE['publicKey']['publicKeyPem'] = self.user.public_pem().decode()
|
||||||
|
|
||||||
|
@ -396,7 +398,8 @@ class ActivityPubTest(TestCase):
|
||||||
self._test_inbox_reply(reply, {
|
self._test_inbox_reply(reply, {
|
||||||
'as2': reply,
|
'as2': reply,
|
||||||
'type': 'post',
|
'type': 'post',
|
||||||
'labels': ['activity', 'notification'],
|
'labels': ['activity', 'user', 'notification'],
|
||||||
|
'users': [self.user.key, self.user_actor_key],
|
||||||
}, mock_head, mock_get, mock_post)
|
}, mock_head, mock_get, mock_post)
|
||||||
|
|
||||||
self.assert_user(ActivityPub, 'https://user.com/actor',
|
self.assert_user(ActivityPub, 'https://user.com/actor',
|
||||||
|
@ -427,7 +430,7 @@ class ActivityPubTest(TestCase):
|
||||||
{'as2': REPLY,
|
{'as2': REPLY,
|
||||||
'type': 'post',
|
'type': 'post',
|
||||||
'object_ids': [REPLY_OBJECT['id']],
|
'object_ids': [REPLY_OBJECT['id']],
|
||||||
'labels': ['notification', 'activity'],
|
'labels': ['notification', 'activity', 'user'],
|
||||||
},
|
},
|
||||||
mock_head, mock_get, mock_post)
|
mock_head, mock_get, mock_post)
|
||||||
self.assert_object(REPLY_OBJECT['id'],
|
self.assert_object(REPLY_OBJECT['id'],
|
||||||
|
@ -435,7 +438,8 @@ class ActivityPubTest(TestCase):
|
||||||
our_as1=as2.to_as1(REPLY_OBJECT),
|
our_as1=as2.to_as1(REPLY_OBJECT),
|
||||||
type='comment')
|
type='comment')
|
||||||
|
|
||||||
def _test_inbox_reply(self, reply, expected_props, mock_head, mock_get, mock_post):
|
def _test_inbox_reply(self, reply, expected_props, mock_head, mock_get,
|
||||||
|
mock_post):
|
||||||
mock_head.return_value = requests_response(url='https://user.com/post')
|
mock_head.return_value = requests_response(url='https://user.com/post')
|
||||||
mock_get.side_effect = (
|
mock_get.side_effect = (
|
||||||
(list(mock_get.side_effect) if mock_get.side_effect else [])
|
(list(mock_get.side_effect) if mock_get.side_effect else [])
|
||||||
|
@ -461,12 +465,14 @@ class ActivityPubTest(TestCase):
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assert_object(reply['id'],
|
expected_props = {
|
||||||
users=[self.user.key],
|
'users': [self.user.key, self.swentel_key],
|
||||||
source_protocol='activitypub',
|
'source_protocol': 'activitypub',
|
||||||
status='complete',
|
'status': 'complete',
|
||||||
delivered=['https://user.com/post'],
|
'delivered': ['https://user.com/post'],
|
||||||
**expected_props)
|
**expected_props,
|
||||||
|
}
|
||||||
|
self.assert_object(reply['id'], **expected_props)
|
||||||
|
|
||||||
def test_inbox_reply_to_self_domain(self, *mocks):
|
def test_inbox_reply_to_self_domain(self, *mocks):
|
||||||
self._test_inbox_ignore_reply_to('http://localhost/mas.to', *mocks)
|
self._test_inbox_ignore_reply_to('http://localhost/mas.to', *mocks)
|
||||||
|
@ -480,14 +486,15 @@ class ActivityPubTest(TestCase):
|
||||||
|
|
||||||
mock_head.return_value = requests_response(url='http://mas.to/')
|
mock_head.return_value = requests_response(url='http://mas.to/')
|
||||||
mock_get.side_effect = [
|
mock_get.side_effect = [
|
||||||
|
# actor fetch
|
||||||
|
self.as2_resp(ACTOR),
|
||||||
# protocol inference
|
# protocol inference
|
||||||
requests_response(test_web.NOTE_HTML),
|
requests_response(test_web.NOTE_HTML),
|
||||||
requests_response(test_web.NOTE_HTML),
|
requests_response(test_web.NOTE_HTML),
|
||||||
]
|
]
|
||||||
|
|
||||||
got = self.post('/user.com/inbox', json=reply)
|
got = self.post('/user.com/inbox', json=reply)
|
||||||
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
|
self.assertEqual(204, got.status_code, got.get_data(as_text=True))
|
||||||
|
|
||||||
mock_post.assert_not_called()
|
mock_post.assert_not_called()
|
||||||
|
|
||||||
def test_individual_inbox_create_obj(self, *mocks):
|
def test_individual_inbox_create_obj(self, *mocks):
|
||||||
|
@ -566,24 +573,25 @@ class ActivityPubTest(TestCase):
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
repost['object'] = note
|
|
||||||
del repost['object']['to']
|
|
||||||
del repost['object']['cc']
|
|
||||||
self.assert_object(REPOST_FULL['id'],
|
self.assert_object(REPOST_FULL['id'],
|
||||||
source_protocol='activitypub',
|
source_protocol='activitypub',
|
||||||
status='complete',
|
status='complete',
|
||||||
our_as1=as2.to_as1(repost),
|
as2={
|
||||||
users=[self.user.key],
|
**REPOST,
|
||||||
|
'actor': ACTOR,
|
||||||
|
'object': orig_url,
|
||||||
|
},
|
||||||
|
users=[self.swentel_key],
|
||||||
delivered=['https://user.com/orig'],
|
delivered=['https://user.com/orig'],
|
||||||
type='share',
|
type='share',
|
||||||
labels=['activity', 'feed', 'notification'],
|
labels=['activity', 'user', 'feed'],
|
||||||
object_ids=['https://user.com/orig'])
|
object_ids=['https://user.com/orig'])
|
||||||
|
|
||||||
def test_shared_inbox_repost_of_fediverse(self, mock_head, mock_get, mock_post):
|
def test_shared_inbox_repost_of_fediverse(self, mock_head, mock_get, mock_post):
|
||||||
Follower.get_or_create(to=ActivityPub.get_or_create(ACTOR['id']),
|
Follower.get_or_create(to=ActivityPub.get_or_create(ACTOR['id']),
|
||||||
from_=self.user)
|
from_=self.user)
|
||||||
Follower.get_or_create(to=ActivityPub.get_or_create(ACTOR['id']),
|
baz = Fake.get_or_create('http://baz')
|
||||||
from_=Fake.get_or_create('http://baz'))
|
Follower.get_or_create(to=ActivityPub.get_or_create(ACTOR['id']), from_=baz)
|
||||||
Follower.get_or_create(to=ActivityPub.get_or_create(ACTOR['id']),
|
Follower.get_or_create(to=ActivityPub.get_or_create(ACTOR['id']),
|
||||||
from_=Fake.get_or_create('http://baj'),
|
from_=Fake.get_or_create('http://baj'),
|
||||||
status='inactive')
|
status='inactive')
|
||||||
|
@ -599,7 +607,7 @@ class ActivityPubTest(TestCase):
|
||||||
]
|
]
|
||||||
|
|
||||||
got = self.post('/ap/sharedInbox', json=REPOST)
|
got = self.post('/ap/sharedInbox', json=REPOST)
|
||||||
self.assertEqual(200, got.status_code, got.get_data(as_text=True))
|
self.assertEqual(204, got.status_code, got.get_data(as_text=True))
|
||||||
|
|
||||||
mock_post.assert_not_called() # no webmention
|
mock_post.assert_not_called() # no webmention
|
||||||
|
|
||||||
|
@ -607,7 +615,7 @@ class ActivityPubTest(TestCase):
|
||||||
source_protocol='activitypub',
|
source_protocol='activitypub',
|
||||||
status='ignored',
|
status='ignored',
|
||||||
our_as1=as2.to_as1(REPOST_FULL),
|
our_as1=as2.to_as1(REPOST_FULL),
|
||||||
users=[self.user.key, Fake(id='http://baz').key],
|
users=[self.user.key, baz, self.swentel_key],
|
||||||
type='share',
|
type='share',
|
||||||
labels=['activity', 'feed'],
|
labels=['activity', 'feed'],
|
||||||
object_ids=[REPOST['object']])
|
object_ids=[REPOST['object']])
|
||||||
|
@ -623,8 +631,11 @@ class ActivityPubTest(TestCase):
|
||||||
HTML,
|
HTML,
|
||||||
]
|
]
|
||||||
|
|
||||||
got = self.post('/ap/sharedInbox', json={**LIKE, 'object': 'http://nope.com/post'})
|
got = self.post('/ap/sharedInbox', json={
|
||||||
self.assertEqual(200, got.status_code)
|
**LIKE,
|
||||||
|
'object': 'http://nope.com/post',
|
||||||
|
})
|
||||||
|
self.assertEqual(204, got.status_code)
|
||||||
|
|
||||||
self.assert_object('http://mas.to/like#ok',
|
self.assert_object('http://mas.to/like#ok',
|
||||||
# no nope.com Web user key since it didn't exist
|
# no nope.com Web user key since it didn't exist
|
||||||
|
@ -744,7 +755,7 @@ class ActivityPubTest(TestCase):
|
||||||
}, kwargs['data'])
|
}, kwargs['data'])
|
||||||
|
|
||||||
self.assert_object('http://mas.to/like#ok',
|
self.assert_object('http://mas.to/like#ok',
|
||||||
users=[self.user.key],
|
users=[self.user.key, self.user_actor_key],
|
||||||
source_protocol='activitypub',
|
source_protocol='activitypub',
|
||||||
status='complete',
|
status='complete',
|
||||||
our_as1=as2.to_as1(LIKE_WITH_ACTOR),
|
our_as1=as2.to_as1(LIKE_WITH_ACTOR),
|
||||||
|
@ -764,14 +775,14 @@ class ActivityPubTest(TestCase):
|
||||||
obj_as2=LIKE_ACTOR, direct=True)
|
obj_as2=LIKE_ACTOR, direct=True)
|
||||||
|
|
||||||
def test_inbox_follow_accept_with_id(self, *mocks):
|
def test_inbox_follow_accept_with_id(self, *mocks):
|
||||||
self._test_inbox_follow_accept(FOLLOW_WRAPPED, ACCEPT, *mocks)
|
self._test_inbox_follow_accept(FOLLOW_WRAPPED, ACCEPT, 200, *mocks)
|
||||||
|
|
||||||
follow = {
|
follow = {
|
||||||
**FOLLOW_WITH_ACTOR,
|
**FOLLOW_WITH_ACTOR,
|
||||||
'url': 'https://mas.to/users/swentel#followed-https://user.com/',
|
'url': 'https://mas.to/users/swentel#followed-https://user.com/',
|
||||||
}
|
}
|
||||||
self.assert_object('https://mas.to/6d1a',
|
self.assert_object('https://mas.to/6d1a',
|
||||||
users=[self.user.key],
|
users=[self.user.key, self.swentel_key],
|
||||||
source_protocol='activitypub',
|
source_protocol='activitypub',
|
||||||
status='complete',
|
status='complete',
|
||||||
our_as1=as2.to_as1(follow),
|
our_as1=as2.to_as1(follow),
|
||||||
|
@ -788,14 +799,14 @@ class ActivityPubTest(TestCase):
|
||||||
'url': FOLLOW['object'],
|
'url': FOLLOW['object'],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
self._test_inbox_follow_accept(follow, ACCEPT, *mocks)
|
self._test_inbox_follow_accept(follow, ACCEPT, 200, *mocks)
|
||||||
|
|
||||||
follow.update({
|
follow.update({
|
||||||
'actor': ACTOR,
|
'actor': ACTOR,
|
||||||
'url': 'https://mas.to/users/swentel#followed-https://user.com/',
|
'url': 'https://mas.to/users/swentel#followed-https://user.com/',
|
||||||
})
|
})
|
||||||
self.assert_object('https://mas.to/6d1a',
|
self.assert_object('https://mas.to/6d1a',
|
||||||
users=[self.user.key],
|
users=[self.user.key, self.swentel_key],
|
||||||
source_protocol='activitypub',
|
source_protocol='activitypub',
|
||||||
status='complete',
|
status='complete',
|
||||||
our_as1=as2.to_as1(follow),
|
our_as1=as2.to_as1(follow),
|
||||||
|
@ -804,29 +815,28 @@ class ActivityPubTest(TestCase):
|
||||||
labels=['notification', 'activity'],
|
labels=['notification', 'activity'],
|
||||||
object_ids=[FOLLOW['object']])
|
object_ids=[FOLLOW['object']])
|
||||||
|
|
||||||
def test_inbox_follow_accept_webmention_fails(self, mock_head, mock_get, mock_post):
|
def test_inbox_follow_accept_webmention_fails(self, mock_head, mock_get,
|
||||||
|
mock_post):
|
||||||
mock_post.side_effect = [
|
mock_post.side_effect = [
|
||||||
requests_response(), # AP Accept
|
requests_response(), # AP Accept
|
||||||
requests.ConnectionError(), # webmention
|
requests.ConnectionError(), # webmention
|
||||||
]
|
]
|
||||||
self._test_inbox_follow_accept(FOLLOW_WRAPPED, ACCEPT,
|
self._test_inbox_follow_accept(FOLLOW_WRAPPED, ACCEPT, 304,
|
||||||
mock_head, mock_get, mock_post)
|
mock_head, mock_get, mock_post)
|
||||||
|
|
||||||
follow = {
|
url = 'https://mas.to/users/swentel#followed-https://user.com/'
|
||||||
**FOLLOW_WITH_ACTOR,
|
|
||||||
'url': 'https://mas.to/users/swentel#followed-https://user.com/',
|
|
||||||
}
|
|
||||||
self.assert_object('https://mas.to/6d1a',
|
self.assert_object('https://mas.to/6d1a',
|
||||||
users=[self.user.key],
|
users=[self.user.key, self.swentel_key],
|
||||||
source_protocol='activitypub',
|
source_protocol='activitypub',
|
||||||
status='complete',
|
status='failed',
|
||||||
our_as1=as2.to_as1(follow),
|
our_as1=as2.to_as1({**FOLLOW_WITH_ACTOR, 'url': url}),
|
||||||
delivered=[],
|
delivered=[],
|
||||||
|
failed=['https://user.com/'],
|
||||||
type='follow',
|
type='follow',
|
||||||
labels=['notification', 'activity'],
|
labels=['notification', 'activity', 'user'],
|
||||||
object_ids=[FOLLOW['object']])
|
object_ids=[FOLLOW['object']])
|
||||||
|
|
||||||
def _test_inbox_follow_accept(self, follow_as2, accept_as2,
|
def _test_inbox_follow_accept(self, follow_as2, accept_as2, expected_status,
|
||||||
mock_head, mock_get, mock_post):
|
mock_head, mock_get, mock_post):
|
||||||
# this should makes us make the follower ActivityPub as direct=True
|
# this should makes us make the follower ActivityPub as direct=True
|
||||||
self.user.direct = False
|
self.user.direct = False
|
||||||
|
@ -842,7 +852,7 @@ class ActivityPubTest(TestCase):
|
||||||
mock_post.return_value = requests_response()
|
mock_post.return_value = requests_response()
|
||||||
|
|
||||||
got = self.post('/user.com/inbox', json=follow_as2)
|
got = self.post('/user.com/inbox', json=follow_as2)
|
||||||
self.assertEqual(200, got.status_code)
|
self.assertEqual(expected_status, got.status_code)
|
||||||
|
|
||||||
mock_get.assert_has_calls((
|
mock_get.assert_has_calls((
|
||||||
self.as2_req(FOLLOW['actor']),
|
self.as2_req(FOLLOW['actor']),
|
||||||
|
@ -889,7 +899,7 @@ class ActivityPubTest(TestCase):
|
||||||
mock_post.return_value = requests_response()
|
mock_post.return_value = requests_response()
|
||||||
|
|
||||||
got = self.post('/user.com/inbox', json=FOLLOW_WRAPPED)
|
got = self.post('/user.com/inbox', json=FOLLOW_WRAPPED)
|
||||||
self.assertEqual(200, got.status_code)
|
self.assertEqual(204, got.status_code)
|
||||||
|
|
||||||
follower = Follower.query().get()
|
follower = Follower.query().get()
|
||||||
self.assert_entities_equal(
|
self.assert_entities_equal(
|
||||||
|
@ -994,23 +1004,29 @@ class ActivityPubTest(TestCase):
|
||||||
|
|
||||||
id = 'https://mas.to/users/tmichellemoore#likes/56486252'
|
id = 'https://mas.to/users/tmichellemoore#likes/56486252'
|
||||||
bad_url = 'http://localhost/r/Testing \u2013 Brid.gy \u2013 Post to Mastodon 3'
|
bad_url = 'http://localhost/r/Testing \u2013 Brid.gy \u2013 Post to Mastodon 3'
|
||||||
got = self.post('/user.com/inbox', json={
|
bad = {
|
||||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
'id': id,
|
'id': id,
|
||||||
'type': 'Like',
|
'type': 'Like',
|
||||||
'actor': ACTOR['id'],
|
'actor': ACTOR['id'],
|
||||||
'object': bad_url,
|
'object': bad_url,
|
||||||
})
|
}
|
||||||
|
got = self.post('/user.com/inbox', json=bad)
|
||||||
|
|
||||||
# bad object, should ignore activity
|
# bad object, should ignore activity
|
||||||
self.assertEqual(200, got.status_code)
|
self.assertEqual(204, got.status_code)
|
||||||
mock_post.assert_not_called()
|
mock_post.assert_not_called()
|
||||||
|
|
||||||
obj = Object.get_by_id(id)
|
self.assert_object(id,
|
||||||
self.assertEqual(['activity'], obj.labels)
|
our_as1={
|
||||||
self.assertEqual([], obj.users)
|
**as2.to_as1(bad),
|
||||||
self.assertEqual([], obj.domains)
|
'actor': as2.to_as1(ACTOR),
|
||||||
|
},
|
||||||
|
labels=['activity', 'user'],
|
||||||
|
users=[self.swentel_key],
|
||||||
|
source_protocol='activitypub',
|
||||||
|
status='ignored',
|
||||||
|
)
|
||||||
self.assertIsNone(Object.get_by_id(bad_url))
|
self.assertIsNone(Object.get_by_id(bad_url))
|
||||||
|
|
||||||
@patch('activitypub.logger.info', side_effect=logging.info)
|
@patch('activitypub.logger.info', side_effect=logging.info)
|
||||||
|
@ -1034,7 +1050,7 @@ class ActivityPubTest(TestCase):
|
||||||
body = json_dumps(NOTE)
|
body = json_dumps(NOTE)
|
||||||
headers = self.sign('/ap/sharedInbox', json_dumps(NOTE))
|
headers = self.sign('/ap/sharedInbox', json_dumps(NOTE))
|
||||||
resp = self.client.post('/ap/sharedInbox', data=body, headers=headers)
|
resp = self.client.post('/ap/sharedInbox', data=body, headers=headers)
|
||||||
self.assertEqual(200, resp.status_code, resp.get_data(as_text=True))
|
self.assertEqual(204, resp.status_code, resp.get_data(as_text=True))
|
||||||
mock_get.assert_has_calls((
|
mock_get.assert_has_calls((
|
||||||
self.as2_req('http://my/key/id'),
|
self.as2_req('http://my/key/id'),
|
||||||
))
|
))
|
||||||
|
@ -1133,7 +1149,6 @@ class ActivityPubTest(TestCase):
|
||||||
self.assertEqual(204, resp.status_code)
|
self.assertEqual(204, resp.status_code)
|
||||||
self.assertTrue(obj.key.get().deleted)
|
self.assertTrue(obj.key.get().deleted)
|
||||||
self.assert_object(delete['id'],
|
self.assert_object(delete['id'],
|
||||||
as2=delete,
|
|
||||||
our_as1={
|
our_as1={
|
||||||
**as2.to_as1(delete),
|
**as2.to_as1(delete),
|
||||||
'actor': as2.to_as1(ACTOR),
|
'actor': as2.to_as1(ACTOR),
|
||||||
|
@ -1162,21 +1177,29 @@ class ActivityPubTest(TestCase):
|
||||||
]
|
]
|
||||||
|
|
||||||
resp = self.post('/ap/sharedInbox', json=UPDATE_NOTE)
|
resp = self.post('/ap/sharedInbox', json=UPDATE_NOTE)
|
||||||
self.assertEqual(200, resp.status_code)
|
self.assertEqual(204, resp.status_code)
|
||||||
|
|
||||||
|
note_as1 = as2.to_as1({
|
||||||
|
**UPDATE_NOTE['object'],
|
||||||
|
'author': {'id': 'https://mas.to/users/swentel'},
|
||||||
|
})
|
||||||
self.assert_object('https://a/note',
|
self.assert_object('https://a/note',
|
||||||
type='note',
|
type='note',
|
||||||
our_as1=as2.to_as1({
|
our_as1=note_as1,
|
||||||
**UPDATE_NOTE['object'],
|
|
||||||
'author': {'id': 'https://mas.to/users/swentel'},
|
|
||||||
}),
|
|
||||||
source_protocol='activitypub')
|
source_protocol='activitypub')
|
||||||
|
|
||||||
|
update_as1 = {
|
||||||
|
**as2.to_as1(UPDATE_NOTE),
|
||||||
|
'object': note_as1,
|
||||||
|
'actor': as2.to_as1(ACTOR),
|
||||||
|
}
|
||||||
self.assert_object(UPDATE_NOTE['id'],
|
self.assert_object(UPDATE_NOTE['id'],
|
||||||
source_protocol='activitypub',
|
source_protocol='activitypub',
|
||||||
type='update',
|
type='update',
|
||||||
status='complete',
|
status='ignored',
|
||||||
as2=UPDATE_NOTE,
|
our_as1=update_as1,
|
||||||
labels=['activity'])
|
labels=['activity', 'user'],
|
||||||
|
users=[self.swentel_key])
|
||||||
|
|
||||||
self.assert_entities_equal(Object.get_by_id('https://a/note'),
|
self.assert_entities_equal(Object.get_by_id('https://a/note'),
|
||||||
protocol.objects_cache['https://a/note'])
|
protocol.objects_cache['https://a/note'])
|
||||||
|
@ -1208,22 +1231,22 @@ class ActivityPubTest(TestCase):
|
||||||
]
|
]
|
||||||
|
|
||||||
got = self.post('/user.com/inbox', json=LIKE)
|
got = self.post('/user.com/inbox', json=LIKE)
|
||||||
self.assertEqual(200, got.status_code)
|
self.assertEqual(204, got.status_code)
|
||||||
|
|
||||||
self.assert_object('http://mas.to/like#ok',
|
self.assert_object('http://mas.to/like#ok',
|
||||||
users=[self.user.key],
|
users=[self.user.key, self.user_actor_key],
|
||||||
source_protocol='activitypub',
|
source_protocol='activitypub',
|
||||||
status='complete',
|
status='ignored',
|
||||||
our_as1=as2.to_as1(LIKE_WITH_ACTOR),
|
our_as1=as2.to_as1(LIKE_WITH_ACTOR),
|
||||||
type='like',
|
type='like',
|
||||||
labels=['activity', 'notification'],
|
labels=['activity', 'user', 'notification'],
|
||||||
object_ids=[LIKE['object']])
|
object_ids=[LIKE['object']])
|
||||||
|
|
||||||
def test_inbox_id_already_seen(self, *mocks):
|
def test_inbox_id_already_seen(self, *mocks):
|
||||||
obj_key = Object(id=FOLLOW_WRAPPED['id'], as2={}).put()
|
obj_key = Object(id=FOLLOW_WRAPPED['id'], as2={}).put()
|
||||||
|
|
||||||
got = self.post('/user.com/inbox', json=FOLLOW_WRAPPED)
|
got = self.post('/user.com/inbox', json=FOLLOW_WRAPPED)
|
||||||
self.assertEqual(200, got.status_code)
|
self.assertEqual(204, got.status_code)
|
||||||
self.assertEqual(0, Follower.query().count())
|
self.assertEqual(0, Follower.query().count())
|
||||||
|
|
||||||
# second time should use in memory cache
|
# second time should use in memory cache
|
||||||
|
|
|
@ -279,13 +279,7 @@ class ProtocolReceiveTest(TestCase):
|
||||||
def assert_object(self, id, **props):
|
def assert_object(self, id, **props):
|
||||||
props.setdefault('source_protocol', 'fake')
|
props.setdefault('source_protocol', 'fake')
|
||||||
props.setdefault('delivered_protocol', 'fake')
|
props.setdefault('delivered_protocol', 'fake')
|
||||||
|
return super().assert_object(id, **props)
|
||||||
ignore = []
|
|
||||||
for field in 'as2', 'bsky', 'mf2':
|
|
||||||
if 'our_as1' in props and field not in props:
|
|
||||||
ignore.append(field)
|
|
||||||
|
|
||||||
return super().assert_object(id, ignore=ignore, **props)
|
|
||||||
|
|
||||||
def make_followers(self):
|
def make_followers(self):
|
||||||
Follower.get_or_create(to=self.user, from_=self.alice)
|
Follower.get_or_create(to=self.user, from_=self.alice)
|
||||||
|
|
|
@ -300,6 +300,7 @@ class TestCase(unittest.TestCase, testutil.Asserts):
|
||||||
mock.assert_any_call(url, **kwargs)
|
mock.assert_any_call(url, **kwargs)
|
||||||
|
|
||||||
def assert_object(self, id, delivered_protocol=None, **props):
|
def assert_object(self, id, delivered_protocol=None, **props):
|
||||||
|
ignore = props.pop('ignore', [])
|
||||||
got = Object.get_by_id(id)
|
got = Object.get_by_id(id)
|
||||||
assert got, id
|
assert got, id
|
||||||
|
|
||||||
|
@ -308,6 +309,12 @@ class TestCase(unittest.TestCase, testutil.Asserts):
|
||||||
props[field] = [Target(uri=uri, protocol=delivered_protocol)
|
props[field] = [Target(uri=uri, protocol=delivered_protocol)
|
||||||
for uri in props.get(field, [])]
|
for uri in props.get(field, [])]
|
||||||
|
|
||||||
|
if 'our_as1' in props:
|
||||||
|
assert 'as2' not in props
|
||||||
|
assert 'bsky' not in props
|
||||||
|
assert 'mf2' not in props
|
||||||
|
ignore.extend(['as2', 'bsky', 'mf2'])
|
||||||
|
|
||||||
mf2 = props.get('mf2')
|
mf2 = props.get('mf2')
|
||||||
if mf2 and 'items' in mf2:
|
if mf2 and 'items' in mf2:
|
||||||
props['mf2'] = mf2['items'][0]
|
props['mf2'] = mf2['items'][0]
|
||||||
|
@ -329,7 +336,6 @@ class TestCase(unittest.TestCase, testutil.Asserts):
|
||||||
for target in got.delivered:
|
for target in got.delivered:
|
||||||
del target.key
|
del target.key
|
||||||
|
|
||||||
ignore = props.pop('ignore', [])
|
|
||||||
self.assert_entities_equal(Object(id=id, **props), got,
|
self.assert_entities_equal(Object(id=id, **props), got,
|
||||||
ignore=['as1', 'created', 'expire',
|
ignore=['as1', 'created', 'expire',
|
||||||
'object_ids', 'type', 'updated'
|
'object_ids', 'type', 'updated'
|
||||||
|
|
15
web.py
15
web.py
|
@ -270,23 +270,20 @@ class Web(User, Protocol):
|
||||||
|
|
||||||
See :meth:`Protocol.send` for details.
|
See :meth:`Protocol.send` for details.
|
||||||
|
|
||||||
*Does not* propagate HTTP errors, DNS or connection failures, or other
|
Returns true if the target URL doesn't advertise a webmention endpoint,
|
||||||
exceptions, since webmention support is optional for web recipients.
|
since webmention support itself is optional for web recipients.
|
||||||
https://fed.brid.gy/docs#error-handling
|
https://fed.brid.gy/docs#error-handling
|
||||||
"""
|
"""
|
||||||
source_url = obj.proxy_url()
|
source_url = obj.proxy_url()
|
||||||
logger.info(f'Sending webmention from {source_url} to {url}')
|
logger.info(f'Sending webmention from {source_url} to {url}')
|
||||||
|
|
||||||
endpoint = common.webmention_discover(url).endpoint
|
endpoint = common.webmention_discover(url).endpoint
|
||||||
try:
|
if not endpoint:
|
||||||
if endpoint:
|
|
||||||
webmention.send(endpoint, source_url, url)
|
|
||||||
return True
|
|
||||||
except RequestException as e:
|
|
||||||
# log exception, then ignore it
|
|
||||||
util.interpret_http_exception(e)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
webmention.send(endpoint, source_url, url)
|
||||||
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fetch(cls, obj, gateway=False, check_backlink=False, **kwargs):
|
def fetch(cls, obj, gateway=False, check_backlink=False, **kwargs):
|
||||||
"""Fetches a URL over HTTP and extracts its microformats2.
|
"""Fetches a URL over HTTP and extracts its microformats2.
|
||||||
|
|
Ładowanie…
Reference in New Issue