def test_compute_locator(): # The best way of checking that compute locator is correct is by using is_locator for _ in range(100): assert is_locator( compute_locator(get_random_value_hex(LOCATOR_LEN_BYTES))) is True # String of length smaller than LOCATOR_LEN_BYTES bytes must fail for i in range(1, LOCATOR_LEN_BYTES): assert is_locator(compute_locator(get_random_value_hex(i))) is False
def check_locator(locator): """ Checks if the provided ``locator`` is correct. Locators must be 16-byte hex-encoded strings. Args: locator (:obj:`str`): the locator to be checked. Raises: :obj:`InspectionFailed`: if any of the fields is wrong. """ if locator is None: raise InspectionFailed(errors.APPOINTMENT_EMPTY_FIELD, "empty locator received") elif type(locator) != str: raise InspectionFailed( errors.APPOINTMENT_WRONG_FIELD_TYPE, "wrong locator data type ({})".format(type(locator))) elif len(locator) != LOCATOR_LEN_HEX: raise InspectionFailed( errors.APPOINTMENT_WRONG_FIELD_SIZE, "wrong locator size ({})".format(len(locator))) elif not is_locator(locator): raise InspectionFailed(errors.APPOINTMENT_WRONG_FIELD_FORMAT, "wrong locator format ({})".format(locator))
def get_appointment(locator, user_sk, teos_id, teos_url): """ Gets information about an appointment from the tower. Args: locator (:obj:`str`): the appointment locator used to identify it. user_sk (:obj:`PrivateKey`): the user's private key. teos_id (:obj:`PublicKey`): the tower's compressed public key. teos_url (:obj:`str`): the teos base url. Returns: :obj:`dict`: A dictionary containing the appointment data. Raises: :obj:`InvalidParameter`: if `appointment_data` or any of its fields is invalid. :obj:`ConnectionError`: if the client cannot connect to the tower. :obj:`TowerResponseError`: if the tower responded with an error, or the response was invalid. """ # FIXME: All responses from the tower should be signed. Not using teos_id atm. if not is_locator(locator): raise InvalidParameter("The provided locator is not valid", locator=locator) message = "get appointment {}".format(locator) signature = Cryptographer.sign(message.encode("utf-8"), user_sk) data = {"locator": locator, "signature": signature} # Send request to the server. get_appointment_endpoint = "{}/get_appointment".format(teos_url) logger.info("Requesting appointment from the Eye of Satoshi") response = process_post_response(post_request(data, get_appointment_endpoint)) return response
def test_check_locator_format(): # Check that only LOCATOR_LEN_BYTES long string pass the test wrong_inputs = [ None, str(), 213, 46.67, dict(), "A" * (2 * LOCATOR_LEN_BYTES - 1), "C" * (2 * LOCATOR_LEN_BYTES + 1), bytes(), get_random_value_hex(LOCATOR_LEN_BYTES - 1), ] for wtype in wrong_inputs: assert is_locator(wtype) is False for _ in range(100): assert is_locator(get_random_value_hex(LOCATOR_LEN_BYTES)) is True
def parse_get_appointment_arguments(tower_id, locator): """ Parses the arguments of the get_appointment command and checks that they are correct. Args: tower_id (:obj:`str`): the identifier of the tower to connect to (a compressed public key). locator (:obj:`str`): the locator of the appointment to query the tower about. Returns: :obj:`tuple`: the tower id and appointment locator. Raises: :obj:`common.exceptions.InvalidParameter`: if any of the parameters is wrong or missing. """ if not is_compressed_pk(tower_id): raise InvalidParameter( "tower id must be a compressed public key (33-byte hex value)") if not is_locator(locator): raise InvalidParameter("The provided locator is not valid", locator=locator) return tower_id, locator