def register(plugin, tower_id, host=None, port=None):
    """
    Registers the user to the tower.

    Args:
        plugin (:obj:`Plugin`): this plugin.
        tower_id (:obj:`str`): the identifier of the tower to connect to (a compressed public key).
        host (:obj:`str`): the ip or hostname to connect to, optional.
        port (:obj:`int`): the port to connect to, optional.

    Accepted tower_id formats:
        - tower_id@host:port
        - tower_id host port
        - tower_id@host (will default port to DEFAULT_PORT)
        - tower_id host (will default port to DEFAULT_PORT)

    Returns:
        :obj:`dict`: a dictionary containing the subscription data.
    """

    try:
        tower_id, tower_netaddr = arg_parser.parse_register_arguments(
            tower_id, host, port, plugin.wt_client.config)

        # Defaulting to http hosts for now
        if not tower_netaddr.startswith("http"):
            tower_netaddr = "http://" + tower_netaddr

        # Send request to the server.
        register_endpoint = f"{tower_netaddr}/register"
        data = {"public_key": plugin.wt_client.user_id}

        plugin.log(f"Registering in the Eye of Satoshi (tower_id={tower_id})")

        response = process_post_response(
            post_request(data, register_endpoint, tower_id))
        plugin.log(
            f"Registration succeeded. Available slots: {response.get('available_slots')}"
        )

        # Save data
        tower_info = TowerInfo(tower_netaddr, response.get("available_slots"))
        plugin.wt_client.lock.acquire()
        plugin.wt_client.towers[tower_id] = tower_info.get_summary()
        plugin.wt_client.db_manager.store_tower_record(tower_id, tower_info)
        plugin.wt_client.lock.release()

        return response

    except (InvalidParameter, TowerConnectionError, TowerResponseError) as e:
        plugin.log(str(e), level="warn")
        return e.to_json()
Example #2
0
    def update_tower_state(self, tower_id, tower_update):
        """
        Updates the state of a tower both in memory and disk.

        Access if restricted thought a lock to prevent race conditions.

        Args:
            tower_id (:obj:`str`): the identifier of the tower to be updated.
            tower_update (:obj:`dict`): a dictionary containing the data to be added / removed.
        """

        self.lock.acquire()
        tower_info = TowerInfo.from_dict(self.db_manager.load_tower_record(tower_id))

        if "status" in tower_update:
            tower_info.status = tower_update.get("status")
        if "appointment" in tower_update:
            locator, signature = tower_update.get("appointment")
            tower_info.appointments[locator] = signature
            tower_info.available_slots = tower_update.get("available_slots")
        if "pending_appointment" in tower_update:
            data, action = tower_update.get("pending_appointment")
            if action == "add":
                tower_info.pending_appointments.append(list(data))
            else:
                tower_info.pending_appointments.remove(list(data))
        if "invalid_appointment" in tower_update:
            tower_info.invalid_appointments.append(list(tower_update.get("invalid_appointment")))

        if "misbehaving_proof" in tower_update:
            tower_info.misbehaving_proof = tower_update.get("misbehaving_proof")

        self.towers[tower_id] = tower_info.get_summary()
        self.db_manager.store_tower_record(tower_id, tower_info)
        self.lock.release()
def get_tower_info(plugin, tower_id):
    """
    Gets information about a given tower. Data comes from disk (DB), so all stored data is provided.

    Args:
        plugin (:obj:`Plugin`): this plugin.
        tower_id: (:obj:`str`): the identifier of the queried tower.

    Returns:
        :obj:`dict`: a dictionary containing all data about the queried tower.
    """

    tower_info = TowerInfo.from_dict(
        plugin.wt_client.db_manager.load_tower_record(tower_id))
    pending_appointments = [{
        "appointment": appointment,
        "signature": signature
    } for appointment, signature in tower_info.pending_appointments]
    invalid_appointments = [{
        "appointment": appointment,
        "tower_signature": signature
    } for appointment, signature in tower_info.invalid_appointments]
    tower_info.pending_appointments = pending_appointments
    tower_info.invalid_appointments = invalid_appointments
    return {"id": tower_id, **tower_info.to_dict()}
Example #4
0
    def __init__(self, sk, user_id, config):
        self.sk = sk
        self.user_id = user_id
        self.towers = {}
        self.db_manager = TowersDBM(config.get("TOWERS_DB"), plugin)
        self.retrier = Retrier(config.get("MAX_RETRIES"), Queue())
        self.config = config
        self.lock = Lock()

        # Populate the towers dict with data from the db
        for tower_id, tower_info in self.db_manager.load_all_tower_records().items():
            self.towers[tower_id] = TowerInfo.from_dict(tower_info).get_summary()

        Thread(target=self.retrier.manage_retry, args=[plugin], daemon=True).start()
Example #5
0
def register(plugin, tower_id, host=None, port=None):
    """
    Registers the user to the tower.

    Args:
        plugin (:obj:`Plugin`): this plugin.
        tower_id (:obj:`str`): the identifier of the tower to connect to (a compressed public key).
        host (:obj:`str`): the ip or hostname to connect to, optional.
        port (:obj:`int`): the port to connect to, optional.

    Accepted tower_id formats:
        - tower_id@host:port
        - tower_id host port
        - tower_id@host (will default port to DEFAULT_PORT)
        - tower_id host (will default port to DEFAULT_PORT)

    Returns:
        :obj:`dict`: a dictionary containing the subscription data.
    """

    try:
        tower_id, tower_netaddr = arg_parser.parse_register_arguments(tower_id, host, port, plugin.wt_client.config)

        # Defaulting to http hosts for now
        if not tower_netaddr.startswith("http"):
            tower_netaddr = "http://" + tower_netaddr

        # Send request to the server.
        register_endpoint = f"{tower_netaddr}/register"
        data = {"public_key": plugin.wt_client.user_id}

        plugin.log(f"Registering in the Eye of Satoshi (tower_id={tower_id})")

        response = process_post_response(post_request(data, register_endpoint, tower_id))
        available_slots = response.get("available_slots")
        subscription_expiry = response.get("subscription_expiry")
        tower_signature = response.get("subscription_signature")

        if available_slots is None or not isinstance(available_slots, int):
            raise TowerResponseError(f"available_slots is missing or of wrong type ({available_slots})")
        if subscription_expiry is None or not isinstance(subscription_expiry, int):
            raise TowerResponseError(f"subscription_expiry is missing or of wrong type ({subscription_expiry})")
        if tower_signature is None or not isinstance(tower_signature, str):
            raise TowerResponseError(f"signature is missing or of wrong type ({tower_signature})")

        # Check tower signature
        registration_receipt = receipts.create_registration_receipt(
            plugin.wt_client.user_id, available_slots, subscription_expiry
        )
        Cryptographer.recover_pk(registration_receipt, tower_signature)

        plugin.log(f"Registration succeeded. Available slots: {available_slots}")

        # Save data
        tower_info = TowerInfo(tower_netaddr, available_slots)
        plugin.wt_client.lock.acquire()
        plugin.wt_client.towers[tower_id] = tower_info.get_summary()
        plugin.wt_client.db_manager.store_tower_record(tower_id, tower_info)
        plugin.wt_client.lock.release()

        return response

    except (InvalidParameter, TowerConnectionError, TowerResponseError, SignatureError) as e:
        plugin.log(str(e), level="warn")
        return e.to_json()