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 inboxes
pull/470/head
Ryan Barrett 2023-03-29 12:48:50 -07:00
rodzic f7d1a3fd96
commit e6be9cabb8
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
4 zmienionych plików z 35 dodań i 11 usunięć

Wyświetl plik

@ -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,

Wyświetl plik

@ -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

Wyświetl plik

@ -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()

Wyświetl plik

@ -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()