def test_validate_message_good(self): """ Ensures the validate_message function returns True for a valid message. """ val = Value(1, 1, self.key, self.value, self.timestamp, self.expires, PUBLIC_KEY, self.name, self.meta, self.signature, self.version) expected = (True, None) actual = validate_message(val) self.assertEqual(expected, actual)
def test_validate_message_bad_public_key(self): """ Ensure the correct result is returned if the message is invalid because of a bad public key. """ val = Value(1, 1, self.key, self.value, self.timestamp, self.expires, ALT_PUBLIC_KEY, self.name, self.meta, self.signature, self.version) expected = (False, 6) actual = validate_message(val) self.assertEqual(expected, actual)
def test_validate_message_wrong_meta(self): """ Ensures the validate_message function returns False if the message's meta field has been altered. """ val = Value(1, 1, self.key, self.value, self.timestamp, self.expires, PUBLIC_KEY, self.name, {'bad_meta': 'value'}, self.signature, self.version) expected = (False, 6) actual = validate_message(val) self.assertEqual(expected, actual)
def test_validate_message_wrong_timestamp(self): """ Ensures the validate_message function returns False if the message's timestamp field has been altered. """ val = Value(1, 1, self.key, self.value, 1350544046.084876, self.expires, PUBLIC_KEY, self.name, self.meta, self.signature, self.version) expected = (False, 6) actual = validate_message(val) self.assertEqual(expected, actual)
def test_validate_message_wrong_created_with(self): """ Ensures the validate_message function returns False if the message's created_with field has been altered. """ val = Value(1, 1, self.key, self.value, self.timestamp, self.expires, '1.1.foo', PUBLIC_KEY, self.name, self.meta, self.signature, self.version) expected = (False, 6) actual = validate_message(val) self.assertEqual(expected, actual)
def test_validate_message_bad_key_from_name(self): """ Ensure the correct result is returned if the message is invalid because of an incorrect 'key' value with wrong name. """ key = construct_key(PUBLIC_KEY, 'wrong_name') val = Value(1, 1, key, self.value, self.timestamp, self.expires, PUBLIC_KEY, self.name, self.meta, self.signature, self.version) expected = (False, 7) actual = validate_message(val) self.assertEqual(expected, actual)
def handle_store(self, message, protocol, sender): """ Handles an incoming Store message. Checks the provenance and timeliness of the message before storing locally. If there is a problem, removes the untrustworthy peer from the routing table. Otherwise, at REPLICATE_INTERVAL minutes in the future, the local node will attempt to replicate the Store message elsewhere in the DHT if such time is <= the message's expiry time. Sends a Pong message if successful otherwise replies with an appropriate Error. """ # Check provenance is_valid, err_code = validate_message(message) if is_valid: # Ensure the node doesn't already have a more up-to-date version # of the value. current = self._data_store.get(message.key, False) if current and (message.timestamp < current.timestamp): # The node already has a later version of the value so # return an error. details = { 'new_timestamp': '%d' % current.timestamp } raise ValueError(8, constants.ERRORS[8], details, message.uuid) # Good to go, so store value. self._data_store.set_item(message.key, message) # Reply with a pong so the other end updates its routing table. pong = Pong(message.uuid, self.id, self.version) protocol.sendMessage(pong, True) # At some future time attempt to replicate the Store message # around the network IF it is within the message's expiry time. raise Exception("FIX ME!") # Need to check that callLater is called as part of the tests. reactor.callLater(constants.REPLICATE_INTERVAL, self.republish, message) else: # Remove from the routing table. log.msg('Problem with Store command: %d - %s' % (err_code, constants.ERRORS[err_code])) self._routing_table.blacklist(sender) # Return an error. details = { 'message': 'You have been blacklisted.' } raise ValueError(err_code, constants.ERRORS[err_code], details, message.uuid)
def test_validate_message_bad_sig(self): """ Ensure the correct result is returned if the message is invalid because of a bad signature. """ bad_signature = ('\x1c\x10s\x1b\x83@r\x11\x83*2\xa1l\x0f\xba*\xd7C' + '\xd4\xa7\x07\xe3\x90\xcc\xc4\x16\xe9 \xadg\x03\xbf' + '\x9c\\\xe2\xfe\x88\xdb\\=,-\xd1/\xa9I2\xc2S\xe7' + '\x07c\xf9X%\x1c\x939\xe6\xa8\x10_\xf3\xeeRlj\xc5i~' + '\x94\xcd\xbd\xb24ujq\xa9Nw\xd0\xad\xa7\xde_\x9cpxj' + '\xdd\x8a\xe8\xfd\xaf\xcbRn\xb7C\xb1q\x13c\xc9' + '\x89@w\xac\xc4\xf8\x87\x9ct\x1a\xa6') val = Value(1, 1, self.key, self.value, self.timestamp, self.expires, PUBLIC_KEY, self.name, self.meta, bad_signature, self.version) expected = (False, 6) actual = validate_message(val) self.assertEqual(expected, actual)
def handle_value(self, message, sender): """ Handles an incoming Value message containing a value retrieved from another node on the DHT. Ensures the message is valid and calls the referenced deferred to signal the arrival of the value. TODO: How to handle invalid messages and errback the deferred. """ # Check provenance is_valid, err_code = validate_message(message) if is_valid: self.trigger_deferred(message) else: log.msg('Problem with incoming Value: %d - %s' % (err_code, constants.ERRORS[err_code])) log.msg(message) # Remove the remote node from the routing table. self._routing_table.remove_contact(sender.id, True) error = ValueError(constants.ERRORS[err_code]) self.trigger_deferred(message, error)