diff --git a/kepi/bowler_pub/validation.py b/kepi/bowler_pub/validation.py index 2effd2a..f3172d3 100644 --- a/kepi/bowler_pub/validation.py +++ b/kepi/bowler_pub/validation.py @@ -144,20 +144,6 @@ def _run_validation( message_id, ): - """ - Validates a message. Don't call this function directly; - call validate(), above. - - If the message is successfully validated, we will - ... - - message_id -- the primary key of an IncomingMessage - that was generated by validate(). - """ - - logger.info('%s: begin validation', - message_id) - try: message = IncomingMessage.objects.get(id=message_id) except django.core.exceptions.ValidationError: @@ -166,28 +152,62 @@ def _run_validation( # primitive types. raise ValueError("_run_validation()'s message_id parameter takes a UUID string") + valid = _run_validation_inner(message) + + if valid: + result = create(message) + return result + + return None + +def _run_validation_inner( + message, + ): + + """ + Validates a message. Don't call this function directly; + call validate(), above. + + Returns True iff the message is valid. + + message_id -- the primary key of an IncomingMessage + that was generated by validate(). + """ + + logger.info('%s: begin validation', + message) + try: key_id = message.key_id except ValueError: logger.warn('%s: message is unsigned; dropping', message) - return None + return False - # XXX how do we look up an actor? trilby will have a way. try: actor = fetch_user(message.actor) except json.decoder.JSONDecodeError as jde: logger.info('%s: invalid JSON; dropping: %s', message, jde) - return None + return False except UnicodeDecodeError: logger.info('%s: invalid UTF-8; dropping', message) - return None + return False - if actor is None: - logger.info('%s: actor does not exist; dropping message', + if actor is None or actor.status==404: + logger.info('%s: remote actor does not exist; dropping message', message) - return None + return False + elif actor.status==410: + logger.info('%s: remote actor has Gone', + message) + # FIXME: If this message is an instruction to delete a remote user, + # it's valid if the remote user is Gone. + return False + elif actor.status!=200: + logger.info('%s: remote actor could not be fetched (status %d)', + message, actor.status) + return False logger.debug('%s: message signature is: %s', message, message.signature) @@ -205,7 +225,7 @@ def _run_validation( logger.info('%s: actor has an invalid public key (%s); dropping message', message, te, ) - return None + return False logger.debug('Verifying; key=%s, path=%s, host=%s', key, message.path, message.host) @@ -243,10 +263,8 @@ def _run_validation( if not hv.verify(): logger.info('%s: spoofing attempt; message dropped', message) - return None + return False logger.debug('%s: validation passed!', message) - result = create(message) - - return result + return True