kopia lustrzana https://github.com/snarfed/bridgy-fed
incoming AP: when we can't load the keyId, store a deleted Object
prevents re-fetching the same failing keyId actor over and over when we get the same Delete actor activity sent to all of our inboxespull/470/head
rodzic
f7d1a3fd96
commit
e6be9cabb8
|
@ -152,7 +152,7 @@ class ActivityPub(Protocol):
|
|||
logger.info(f'Headers: {json_dumps(dict(request.headers), indent=2)}')
|
||||
|
||||
# parse_signature_header lower-cases all keys
|
||||
keyId = parse_signature_header(sig).get('keyid')
|
||||
keyId = fragmentless(parse_signature_header(sig).get('keyid'))
|
||||
if not keyId:
|
||||
error('HTTP Signature missing keyId', status=401)
|
||||
|
||||
|
@ -165,16 +165,21 @@ class ActivityPub(Protocol):
|
|||
error('Invalid Digest header, required for HTTP Signature', status=401)
|
||||
|
||||
try:
|
||||
key_actor = cls.get_object(keyId).as2
|
||||
key_actor = cls.get_object(keyId)
|
||||
except BadGateway:
|
||||
obj_id = as1.get_object(activity).get('id')
|
||||
if (activity.get('type') == 'Delete' and obj_id and
|
||||
fragmentless(keyId) == fragmentless(obj_id)):
|
||||
logging.info("Object/actor being deleted is also keyId; ignoring")
|
||||
abort(202, 'OK')
|
||||
raise
|
||||
keyId == fragmentless(obj_id)):
|
||||
logging.info('Object/actor being deleted is also keyId')
|
||||
key_actor = Object(id=keyId, source_protocol='activitypub', deleted=True)
|
||||
key_actor.put()
|
||||
else:
|
||||
raise
|
||||
|
||||
key = key_actor.get("publicKey", {}).get('publicKeyPem')
|
||||
if key_actor.deleted:
|
||||
abort(202, f'Ignoring, signer {keyId} is already deleted')
|
||||
|
||||
key = key_actor.as2.get("publicKey", {}).get('publicKeyPem')
|
||||
logger.info(f'Verifying signature for {request.path} with key {key}')
|
||||
try:
|
||||
verified = HeaderVerifier(request.headers, key,
|
||||
|
|
|
@ -386,7 +386,7 @@ class Protocol:
|
|||
id = util.fragmentless(id)
|
||||
logger.info(f'Loading Object {id}')
|
||||
obj = models.Object.get_by_id(id)
|
||||
if obj and obj.as1:
|
||||
if obj and (obj.as1 or obj.deleted):
|
||||
logger.info(' got from datastore')
|
||||
return obj
|
||||
|
||||
|
|
|
@ -234,7 +234,8 @@ class ActivityPubTest(testutil.TestCase):
|
|||
'owner': 'http://own/er',
|
||||
'publicKeyPem': self.user.public_pem().decode(),
|
||||
},
|
||||
}).put()
|
||||
})
|
||||
self.key_id_obj.put()
|
||||
|
||||
def assert_object(self, id, **props):
|
||||
return super().assert_object(id, delivered_protocol='webmention', **props)
|
||||
|
@ -829,7 +830,7 @@ class ActivityPubTest(testutil.TestCase):
|
|||
def test_inbox_verify_http_signature(self, mock_common_log, mock_activitypub_log,
|
||||
_, mock_get, ___):
|
||||
# actor with a public key
|
||||
self.key_id_obj.delete()
|
||||
self.key_id_obj.key.delete()
|
||||
Protocol.get_object.cache.clear()
|
||||
mock_get.return_value = self.as2_resp({
|
||||
**ACTOR,
|
||||
|
@ -907,13 +908,23 @@ class ActivityPubTest(testutil.TestCase):
|
|||
self.assertEqual('active', other.key.get().status)
|
||||
|
||||
def test_delete_actor_not_fetchable(self, _, mock_get, ___):
|
||||
self.key_id_obj.delete()
|
||||
self.key_id_obj.key.delete()
|
||||
Protocol.get_object.cache.clear()
|
||||
|
||||
mock_get.return_value = requests_response(status=410)
|
||||
got = self.post('/inbox', json={**DELETE, 'object': 'http://my/key/id'})
|
||||
self.assertEqual(202, got.status_code)
|
||||
|
||||
def test_delete_actor_empty_deleted_object(self, _, mock_get, ___):
|
||||
self.key_id_obj.as2 = None
|
||||
self.key_id_obj.deleted = True
|
||||
self.key_id_obj.put()
|
||||
Protocol.get_object.cache.clear()
|
||||
|
||||
got = self.post('/inbox', json={**DELETE, 'object': 'http://my/key/id'})
|
||||
self.assertEqual(202, got.status_code)
|
||||
mock_get.assert_not_called()
|
||||
|
||||
def test_delete_note(self, _, mock_get, ___):
|
||||
obj = Object(id='http://an/obj', as2={})
|
||||
obj.put()
|
||||
|
|
|
@ -71,3 +71,11 @@ class ProtocolTest(testutil.TestCase):
|
|||
stored.put()
|
||||
self.assert_entities_equal(stored, FakeProtocol.get_object('foo'))
|
||||
self.assertEqual([], FakeProtocol.fetched)
|
||||
|
||||
@patch('requests.get')
|
||||
def test_get_object_empty_deleted(self, mock_get):
|
||||
stored = Object(id='foo', deleted=True)
|
||||
stored.put()
|
||||
|
||||
self.assert_entities_equal(stored, FakeProtocol.get_object('foo'))
|
||||
mock_get.assert_not_called()
|
||||
|
|
Ładowanie…
Reference in New Issue