Пример #1
0
def _fragment_connect_request(crypto_instance: crypto.Crypto,
                              client_uuid: uuid.UUID,
                              pubkey_type: PublicKeyType,
                              pubkey: bytes,
                              userhash: str,
                              auth_token: str,
                              request_num: int = 0) -> List:
    """
    Internal method to fragment ConnectRequest.

    Args:
        crypto_instance: Instance of :class:`Crypto`
        client_uuid: Client UUID
        pubkey_type Public Key Type
        pubkey: Public Key
        userhash: Xbox Live Account userhash
        auth_token: Xbox Live Account authentication token (XSTS)
        request_num: Request Number

    Returns:
        list: List of ConnectRequest fragments
    """
    messages = []

    # Calculate packet length (without authentication data)
    dummy_msg = factory.connect(client_uuid, pubkey_type, pubkey, b'\x00' * 16,
                                u'', u'', 0, 0, 0)
    dummy_payload_len = packer.payload_length(dummy_msg)

    # Do fragmenting
    total_auth_len = len(userhash + auth_token)
    max_size = 1024 - dummy_payload_len

    fragments = total_auth_len // max_size
    overlap = total_auth_len % max_size

    if overlap > 0:
        fragments += 1

    group_start = request_num
    group_end = group_start + fragments

    if fragments <= 1:
        raise FragmentError('Authentication data too small to fragment')

    auth_position = 0
    for fragment_num in range(fragments):
        available = max_size
        current_hash = u''

        if fragment_num == 0:
            current_hash = userhash
            available -= len(current_hash)

        current_auth = auth_token[auth_position:auth_position + available]
        auth_position += len(current_auth)

        iv = crypto_instance.generate_iv()
        messages.append(
            factory.connect(client_uuid, pubkey_type, pubkey, iv, current_hash,
                            current_auth, request_num + fragment_num,
                            group_start, group_end))

    return messages
Пример #2
0
    async def connect(self,
                      userhash: str,
                      xsts_token: str,
                      client_uuid: uuid.UUID = uuid.uuid4(),
                      request_num: int = 0,
                      retries: int = 3) -> PairedIdentityState:
        """
        Connect to console

        Args:
            userhash: Userhash from Xbox Live Authentication
            xsts_token: XSTS Token from Xbox Live Authentication
            client_uuid: Client UUID (default: Generate random uuid)
            request_num: Request number
            retries: Max. connect attempts

        Returns: Pairing State

        Raises:
            ProtocolError: If connection fails
        """
        if not self.crypto:
            raise ProtocolError("No crypto")

        if isinstance(userhash, type(None)):
            userhash = ''
        if isinstance(xsts_token, type(None)):
            xsts_token = ''

        iv = self.crypto.generate_iv()
        pubkey_type = self.crypto.pubkey_type
        pubkey = self.crypto.pubkey_bytes

        msg = factory.connect(client_uuid, pubkey_type, pubkey, iv, userhash,
                              xsts_token, request_num, request_num,
                              request_num + 1)

        payload_len = packer.payload_length(msg)
        if payload_len < 1024:
            messages = [msg]
        else:
            messages = _fragment_connect_request(self.crypto, client_uuid,
                                                 pubkey_type, pubkey, userhash,
                                                 xsts_token, request_num)

        tries = 0
        result = None
        while tries < retries and not result:
            for m in messages:
                await self.send_message(m)

            result = await self._await_ack('connect')

        if not result:
            raise ProtocolError("Exceeded connect retries")

        connect_result = result.protected_payload.connect_result
        if connect_result != ConnectionResult.Success:
            raise ProtocolError("Connecting failed! Result: %s" %
                                connect_result)

        self.target_participant_id = 0
        self.source_participant_id = result.protected_payload.participant_id

        await self.local_join()

        for channel, target_uuid in CHANNEL_MAP.items():
            await self.start_channel(channel, target_uuid)

        asyncio.create_task(self._heartbeat_task())
        return result.protected_payload.pairing_state
Пример #3
0
    def connect(self,
                userhash,
                xsts_token,
                client_uuid=uuid.uuid4(),
                request_num=0,
                retries=3):
        """
        Connect to console

        Args:
            userhash (str): Userhash from Xbox Live Authentication
            xsts_token (str): XSTS Token from Xbox Live Authentication
            client_uuid (UUID): Client UUID (default: Generate random uuid)
            request_num (int): Request number
            retries (int): Max. connect attempts

        Returns:
            int: Pairing State

        Raises:
            ProtocolError: If connection fails
        """
        if not self.crypto:
            raise ProtocolError("No crypto")

        iv = self.crypto.generate_iv()
        pubkey_type = self.crypto.pubkey_type
        pubkey = self.crypto.pubkey_bytes

        msg = factory.connect(client_uuid, pubkey_type, pubkey, iv, userhash,
                              xsts_token, request_num, request_num,
                              request_num + 1)

        payload_len = packer.payload_length(msg)
        if payload_len < 1024:
            messages = [msg]
        else:
            messages = _fragment_connect_request(self.crypto, client_uuid,
                                                 pubkey_type, pubkey, userhash,
                                                 xsts_token, request_num)

        tries = 0
        result = None
        while tries < retries and not result:
            for m in messages:
                self.send_message(m)

            result = self._await_ack('connect')

        if not result:
            raise ProtocolError("Exceeded connect retries")

        connect_result = result.protected_payload.connect_result
        if connect_result != ConnectionResult.Success:
            raise ProtocolError("Connecting failed! Result: %s" %
                                connect_result)

        self.target_participant_id = 0
        self.source_participant_id = result.protected_payload.participant_id

        self.local_join()

        for channel, target_uuid in CHANNEL_MAP.items():
            self.start_channel(channel, target_uuid)

        gevent.spawn_later(self.HEARTBEAT_INTERVAL, self._heartbeat)
        return result.protected_payload.pairing_state