コード例 #1
0
def test_is_256b_hex_str():
    # Only 32-byte hex encoded strings should pass the test
    wrong_inputs = [
        None,
        str(), 213, 46.67,
        dict(), "A" * 63, "C" * 65,
        bytes(),
        get_random_value_hex(31)
    ]
    for wtype in wrong_inputs:
        assert is_256b_hex_str(wtype) is False

    for v in range(100):
        assert is_256b_hex_str(get_random_value_hex(32)) is True
コード例 #2
0
def create_appointment(appointment_data):
    """
    Creates an appointment object from an appointment data dictionary provided by the user. Performs all the required
    sanity checks on the input data:

        - Check that the given commitment_txid is correct (proper format and not missing)
        - Check that the transaction is correct (not missing)

    Args:
        appointment_data (:obj:`dict`): a dictionary containing the appointment data.

    Returns:
        :obj:`common.appointment.Appointment`: An appointment built from the appointment data provided by the user.
    """

    tx_id = appointment_data.get("tx_id")
    tx = appointment_data.get("tx")

    if not tx_id:
        raise InvalidParameter("Missing tx_id, locator cannot be computed")
    elif not is_256b_hex_str(tx_id):
        raise InvalidParameter("Wrong tx_id, locator cannot be computed")
    elif not tx:
        raise InvalidParameter("The tx field is missing in the provided data")
    elif not isinstance(tx, str):
        raise InvalidParameter("The provided tx field is not a string")

    appointment_data["locator"] = compute_locator(tx_id)
    appointment_data["encrypted_blob"] = Cryptographer.encrypt(tx, tx_id)

    return Appointment.from_dict(appointment_data)
コード例 #3
0
ファイル: arg_parser.py プロジェクト: talaia-labs/python-teos
def parse_add_appointment_arguments(kwargs):
    """
    Parses the arguments of the add_appointment command and checks that they are correct.

    The expected arguments are a commitment transaction id (32-byte hex string) and the penalty transaction.

    Args:
        kwargs (:obj:`dict`): a dictionary of arguments.

    Returns:
        :obj:`tuple`: the commitment transaction id and the penalty transaction.

    Raises:
        :obj:`common.exceptions.InvalidParameter`: if any of the parameters is wrong or missing.
    """

    # Arguments to add_appointment come from c-lightning and they have been sanitised. Checking this just in case.
    commitment_txid = kwargs.get("commitment_txid")
    penalty_tx = kwargs.get("penalty_tx")

    if commitment_txid is None:
        raise InvalidParameter("missing required parameter: commitment_txid")

    if penalty_tx is None:
        raise InvalidParameter("missing required parameter: penalty_tx")

    if not is_256b_hex_str(commitment_txid):
        raise InvalidParameter("commitment_txid has invalid format")

    # Checking the basic stuff for the penalty transaction for now
    if type(penalty_tx) is not str or re.search(r"^[0-9A-Fa-f]+$",
                                                penalty_tx) is None:
        raise InvalidParameter("penalty_tx has invalid format")

    return commitment_txid, penalty_tx
コード例 #4
0
    def check_data_key_format(data, secret):
        """
        Checks that the data and secret that will be used to by ``encrypt`` / ``decrypt`` are properly formatted.

        Args:
              data(:obj:`str`): the data to be encrypted.
              secret(:obj:`str`): the secret used to derive the encryption key.

        Raises:
              :obj:`InvalidParameter`: if either the ``key`` and/or ``data`` are not properly formatted.
        """

        if len(data) % 2:
            raise InvalidParameter("Incorrect (Odd-length) data", data=data)

        if not is_256b_hex_str(secret):
            raise InvalidParameter(
                "Secret must be a 32-byte hex value (64 hex chars)",
                secret=secret)
コード例 #5
0
def add_appointment(appointment_data, user_sk, teos_id, teos_url):
    """
    Manages the add_appointment command.

    The life cycle of the function is as follows:
        - Check that the given commitment_txid is correct (proper format and not missing)
        - Check that the transaction is correct (not missing)
        - Create the appointment locator and encrypted blob from the commitment_txid and the penalty_tx
        - Sign the appointment
        - Send the appointment to the tower
        - Wait for the response
        - Check the tower's response and signature

    Args:
        appointment_data (:obj:`dict`): a dictionary containing the appointment data.
        user_sk (:obj:`PrivateKey`): the user's private key.
        teos_id (:obj:`str`): the tower's compressed public key.
        teos_url (:obj:`str`): the teos base url.

    Returns:
        :obj:`tuple`: A tuple (`:obj:Appointment <common.appointment.Appointment>`, :obj:`str`) containing the
        appointment and the tower's signature.

    Raises:
        :obj:`InvalidParameter <cli.exceptions.InvalidParameter>`: if `appointment_data` or any of its fields is
        invalid.
        :obj:`ValueError`: if the appointment cannot be signed.
        :obj:`ConnectionError`: if the client cannot connect to the tower.
        :obj:`TowerResponseError <cli.exceptions.TowerResponseError>`: if the tower responded with an error, or the
        response was invalid.
    """

    if not appointment_data:
        raise InvalidParameter("The provided appointment JSON is empty")

    tx_id = appointment_data.get("tx_id")
    tx = appointment_data.get("tx")

    if not is_256b_hex_str(tx_id):
        raise InvalidParameter("The provided locator is wrong or missing")

    if not tx:
        raise InvalidParameter("The provided data is missing the transaction")

    appointment_data["locator"] = compute_locator(tx_id)
    appointment_data["encrypted_blob"] = Cryptographer.encrypt(tx, tx_id)
    appointment = Appointment.from_dict(appointment_data)
    signature = Cryptographer.sign(appointment.serialize(), user_sk)

    data = {"appointment": appointment.to_dict(), "signature": signature}

    # Send appointment to the server.
    logger.info("Sending appointment to the Eye of Satoshi")
    add_appointment_endpoint = "{}/add_appointment".format(teos_url)
    response = process_post_response(
        post_request(data, add_appointment_endpoint))

    tower_signature = response.get("signature")
    # Check that the server signed the appointment as it should.
    if not tower_signature:
        raise TowerResponseError(
            "The response does not contain the signature of the appointment")

    rpk = Cryptographer.recover_pk(appointment.serialize(), tower_signature)
    if teos_id != Cryptographer.get_compressed_pk(rpk):
        raise TowerResponseError(
            "The returned appointment's signature is invalid")

    logger.info("Appointment accepted and signed by the Eye of Satoshi")
    logger.info("Remaining slots: {}".format(response.get("available_slots")))
    logger.info("Start block: {}".format(response.get("start_block")))

    return appointment, tower_signature