def send_um(self, method_name, params=None):
        """Send service method request

        :param method_name: method name (e.g. ``Player.GetGameBadgeLevels#1``)
        :type  method_name: :class:`str`
        :param params: message parameters
        :type  params: :class:`dict`
        :return: ``job_id`` identifier
        :rtype: :class:`str`

        Listen for ``jobid`` on this object to catch the response.
        """
        proto = get_um(method_name)

        if proto is None:
            raise ValueError("Failed to find method named: %s" % method_name)

        message = MsgProto(EMsg.ServiceMethodCallFromClient)
        message.header.target_job_name = method_name
        message.body = proto()

        if params:
            proto_fill_from_dict(message.body, params)

        return self.send_job(message)
Beispiel #2
0
    def get_web_session_cookies(self):
        """Get web authentication cookies via WebAPI's ``AuthenticateUser``

        .. note::
            A session is only valid during the current steam session.

        :return: dict with authentication cookies
        :rtype: :class:`dict`, :class:`None`
        """
        if not self.logged_on: return None

        resp = self.send_job_and_wait(MsgProto(EMsg.ClientRequestWebAPIAuthenticateUserNonce), timeout=5)

        if resp is None: return None

        skey, ekey = generate_session_key()

        data = {
            'steamid': self.steam_id,
            'sessionkey': ekey,
            'encrypted_loginkey': symmetric_encrypt(resp.webapi_authenticate_user_nonce.encode('ascii'), skey),
        }

        try:
            resp = webapi.post('ISteamUserAuth', 'AuthenticateUser', 1, params=data)
        except Exception as exp:
            self._logger.debug("get_web_session_cookies error: %s" % str(exp))
            return None

        return {
            'steamLogin': resp['authenticateuser']['token'],
            'steamLoginSecure': resp['authenticateuser']['tokensecure'],
        }
Beispiel #3
0
    def set_persona(self, state=None, name=None):
        """
        Set persona state and/or name

        :param state: persona state flag
        :type state: :class:`steam.enums.common.EPersonaState`
        :param name: profile name
        :type name: :class:`str`
        """
        if state is None and name is None:
            return

        message = MsgProto(EMsg.ClientChangeStatus)

        if state:
            if not isinstance(state, EPersonaState):
                raise ValueError(
                    "Expected state to be instance of EPersonaState")

            message.body.persona_state = state

        if name:
            message.body.player_name = name

        self.send(message)
Beispiel #4
0
    def get_leaderboard(self, app_id, name):
        """.. versionadded:: 0.8.2

        Find a leaderboard

        :param app_id: application id
        :type app_id: :class:`int`
        :param name: leaderboard name
        :type name: :class:`str`
        :return: leaderboard instance
        :rtype: :class:`SteamLeaderboard`
        :raises: :class:`LookupError` on message timeout or error
        """
        message = MsgProto(EMsg.ClientLBSFindOrCreateLB)
        message.header.routing_appid = app_id
        message.body.app_id = app_id
        message.body.leaderboard_name = name
        message.body.create_if_not_found = False

        resp = self.send_job_and_wait(message, timeout=15)

        if not resp:
            raise LookupError("Didn't receive response within 15seconds :(")
        if resp.eresult != EResult.OK:
            raise LookupError(EResult(resp.eresult))

        return SteamLeaderboard(self, app_id, name, resp)
Beispiel #5
0
    def get_entries(self,
                    start=0,
                    end=0,
                    data_request=ELeaderboardDataRequest.Global):
        """Get leaderboard entries.

        :param start: start entry, not index (e.g. rank 1 is `start=1`)
        :type start: :class:`int`
        :param end: end entry, not index (e.g. only one entry then `start=1,end=1`)
        :type end: :class:`int`
        :param data_request: data being requested
        :type data_request: :class:`steam.enums.common.ELeaderboardDataRequest`
        :return: a list of entries, see `CMsgClientLBSGetLBEntriesResponse`
        :rtype: :class:`list`
        :raises: :class:`LookupError` on message timeout or error
        """
        message = MsgProto(EMsg.ClientLBSGetLBEntries)
        message.body.app_id = self.app_id
        message.body.leaderboard_id = self.id
        message.body.range_start = start
        message.body.range_end = end
        message.body.leaderboard_data_request = data_request

        resp = self._steam.send_job_and_wait(message, timeout=15)

        if not resp:
            raise LookupError("Didn't receive response within 15seconds :(")
        if resp.eresult != EResult.OK:
            raise LookupError(EResult(resp.eresult))

        return resp.entries
Beispiel #6
0
    def change_email(self, password, email, code=''):
        """Change account's email address

        :param password: current account password
        :type  password: :class:`str`
        :param email: new email address
        :type  email: :class:`str`
        :param code: email code
        :type  code: :class:`str`
        :return: result
        :rtype: :class:`.EResult`

        .. note::
            To change email, first call without ``code``
            and then with, to finalize the change
        """
        message = MsgProto(EMsg.ClientEmailChange4)
        message.body.password = password
        message.body.email = email

        if code:
            message.body.code = code

        message.body.final = not not code
        message.body.newmethod = True
        message.body.client_supports_sms = True

        resp = self.send_job_and_wait(message, timeout=10)

        if resp is None:
            return EResult.Timeout
        else:
            return EResult(resp.eresult)
Beispiel #7
0
    def send(self, message, params=None):
        """Send service method request

        :param message:
            proto message instance (use :meth:`SteamUnifiedMessages.get`)
            or method name (e.g. ``Player.GetGameBadgeLevels#1``)
        :type message: :class:`str`, proto message instance
        :param params: message parameters
        :type params: :class:`dict`
        :return: ``jobid`` event identifier
        :rtype: :class:`str`

        Listen for ``jobid`` on this object to catch the response.

        .. note::
            If you listen for ``jobid`` on the client instance you will get the encapsulated message
        """
        if isinstance(message, str):
            message = self.get(message)
        if message not in self._data:
            raise ValueError("Supplied message is invalid. Use 'get' method.")

        if params:
            proto_fill_from_dict(message, params)

        capsule = MsgProto(EMsg.ClientServiceMethod)
        capsule.body.method_name = self._data[message]
        capsule.body.serialized_method = message.SerializeToString()

        return self._steam.send_job(capsule)
Beispiel #8
0
    def create_account(self, account_name, password, email=''):
        """Create a new Steam account

        :param account_name: desired account name
        :type  account_name: :class:`str`
        :param password: desired password
        :type  password: :class:`str`
        :param email: desired email
        :type  email: :class:`str`
        :return: (EResult, SteamID)
        :rtype: :class:`tuple`
        """
        message = MsgProto(EMsg.ClientCreateAccountProto)
        message.body.account_name = account_name
        message.body.password = password

        if email:
            message.body.email = email

        resp = self.send_job_and_wait(message, timeout=10)

        if resp is None:
            return EResult.Timeout, None
        else:
            return EResult(
                resp.eresult), SteamID(resp.steamid) if resp.steamid else None
Beispiel #9
0
    def get_product_info(self, appids=[], packageids=[]):
        try:
            resp = self.steam.send_job_and_wait(MsgProto(EMsg.ClientPICSProductInfoRequest),
                                                {
                'apps': map(lambda x: {'appid': x}, appids),
                'packages': map(lambda x: {'packageid': x}, packageids),
            },
                timeout=10
            )

            if not resp:
                return {}

            resp = proto_to_dict(resp)

            for app in resp.get('apps', []):
                app['appinfo'] = vdf.loads(
                    app.pop('buffer')[:-1].decode('utf-8', 'replace'))['appinfo']
                app['sha'] = hexlify(app['sha']).decode('utf-8')
            for pkg in resp.get('packages', []):
                pkg['appinfo'] = vdf.binary_loads(pkg.pop('buffer')[4:])[
                    str(pkg['packageid'])]
                pkg['sha'] = hexlify(pkg['sha']).decode('utf-8')

            return resp
        except Exception as e:
            print('get_product_info() exception: ' + str(e))
            return {}
Beispiel #10
0
    def check_beta_password(self, app_id, password):
        """Check branch beta password to unlock encrypted branches

        :param app_id: App ID
        :type  app_id: int
        :param password: beta password
        :type  password: str
        :returns: result
        :rtype: :class:`.EResult`
        """
        resp = self.steam.send_job_and_wait(
            MsgProto(EMsg.ClientCheckAppBetaPassword), {
                'app_id': app_id,
                'betapassword': password
            })

        if resp.eresult == EResult.OK:
            self._LOG.debug(
                "Unlocked following beta branches: %s",
                ', '.join(map(lambda x: x.betaname.lower(),
                              resp.betapasswords)))
            for entry in resp.betapasswords:
                self.beta_passwords[(app_id,
                                     entry.betaname.lower())] = unhexlify(
                                         entry.betapassword)
        else:
            self._LOG.debug("App beta password check failed. %r" %
                            EResult(resp.eresult))

        return EResult(resp.eresult)
Beispiel #11
0
    def _parse_message(self, message):
        emsg_id, = struct.unpack_from("<I", message)
        emsg = EMsg(clear_proto_bit(emsg_id))

        if not self.connected and emsg != EMsg.ClientLogOnResponse:
            return

        if emsg in (
                EMsg.ChannelEncryptRequest,
                EMsg.ChannelEncryptResponse,
                EMsg.ChannelEncryptResult,
        ):

            msg = Msg(emsg, message)
        else:
            try:
                if is_proto(emsg_id):
                    msg = MsgProto(emsg, message)
                else:
                    msg = Msg(emsg, message, extended=True)
            except Exception as e:
                self._LOG.fatal(
                    "Failed to deserialize message: %s (is_proto: %s)",
                    str(emsg), is_proto(emsg_id))
                self._LOG.exception(e)

        if self.verbose_debug:
            self._LOG.debug("Incoming: %s\n%s" % (repr(msg), str(msg)))
        else:
            self._LOG.debug("Incoming: %s", repr(msg))

        self.emit(emsg, msg)
Beispiel #12
0
    def get_change_number(self, appids=None):
        if not appids:
            appids = []
        else:
            appids = [appids]

        packageids = []

        resp = self.steam.send_job_and_wait(
            MsgProto(EMsg.ClientPICSProductInfoRequest), {
                'apps': map(lambda x: {'appid': x}, appids),
                'packages': map(lambda x: {'packageid': x}, packageids),
            },
            timeout=10)

        if not resp:
            return {}

        resp = proto_to_dict(resp)

        for app in resp.get('apps', []):
            app['appinfo'] = vdf.loads(
                app.pop('buffer').rstrip('\x00'))['appinfo']
            app['sha'] = hexlify(app['sha'])
        for pkg in resp.get('packages', []):
            pkg['appinfo'] = vdf.binary_loads(pkg.pop('buffer')[4:])[str(
                pkg['packageid'])]
            pkg['sha'] = hexlify(pkg['sha'])

        return resp['apps'][0]['change_number']
Beispiel #13
0
    def get_access_tokens(self, app_ids=[], package_ids=[]):
        """Get access tokens

        :param app_ids: list of app ids
        :type  app_ids: :class:`list`
        :param package_ids: list of package ids
        :type  package_ids: :class:`list`
        :return: dict with ``apps`` and ``packages`` containing their access tokens, see example below
        :rtype: :class:`dict`, :class:`None`

        .. code:: python

            {'apps':     {123: 8888888886, ...},
             'packages': {456: 6666666666, ...}
            }
        """
        if not app_ids and not package_ids:
            return

        resp = self.send_job_and_wait(MsgProto(EMsg.ClientPICSAccessTokenRequest),
                                      {
                                       'appids': map(int, app_ids),
                                       'packageids': map(int, package_ids),
                                      },
                                      timeout=10
                                      )

        if resp:
            return {'apps': dict(map(lambda app: (app.appid, app.access_token), resp.app_access_tokens)),
                    'packages': dict(map(lambda pkg: (pkg.appid, pkg.access_token), resp.package_access_tokens)),
                    }
Beispiel #14
0
    def remove(self, steamid):
        """
        Remove a friend

        :param steamid: their steamid
        :type steamid: :class:`int`, :class:`.SteamID`, :class:`.SteamUser`
        """
        self._steam.send(MsgProto(EMsg.ClientRemoveFriend), {'friendid': steamid})
Beispiel #15
0
    def query(self, filter_text, max_servers=10, timeout=30, **kw):
        r"""
        Query game servers

        https://developer.valvesoftware.com/wiki/Master_Server_Query_Protocol

        .. note::
            When specifying ``filter_text`` use *raw strings* otherwise python won't treat backslashes
            as literal characters (e.g. ``query(r'\appid\730\white\1')``)

        :param filter_text: filter for servers
        :type  filter_text: str
        :param max_servers: (optional) number of servers to return
        :type  max_servers: int
        :param timeout: (optional) timeout for request in seconds
        :type  timeout: int
        :param app_id: (optional) app id
        :type  app_id: int
        :param geo_location_ip: (optional) ip (e.g. '1.2.3.4')
        :type  geo_location_ip: str
        :returns: list of servers, see below. (``None`` is returned steam doesn't respond)
        :rtype: :class:`list`, :class:`None`

        Sample response:

        .. code:: python

            [{'auth_players': 0, 'server_ip': '1.2.3.4', 'query_port': 27015},
             {'auth_players': 6, 'server_ip': '1:2:3:4::5', 'query_port': 27016},
             ...
            ]
        """
        if 'geo_location_ip' in kw:
            kw['geo_location_ip'] = ip4_to_int(kw['geo_location_ip'])

        kw['filter_text'] = filter_text
        kw['max_servers'] = max_servers

        resp = self._s.send_job_and_wait(
            MsgProto(EMsg.ClientGMSServerQuery),
            kw,
            timeout=timeout,
        )

        if resp is None:
            return None

        resp = proto_to_dict(resp)

        for server in resp['servers']:
            server.pop('deprecated_server_ip', None)  # no point returning this

            if 'v4' in server['server_ip']:
                server['server_ip'] = ip4_from_int(server['server_ip']['v4'])
            else:
                server['server_ip'] = ip6_from_bytes(server['server_ip']['v6'])

        return resp['servers']
Beispiel #16
0
    def get_product_info(self, apps=[], packages=[], timeout=15):
        """Get product info for apps and packages

        :param apps: items in the list should be either just ``app_id``, or ``(app_id, access_token)``
        :type apps: :class:`list`
        :param packages: items in the list should be either just ``package_id``, or ``(package_id, access_token)``
        :type packages: :class:`list`
        :return: dict with ``apps`` and ``packages`` containing their info, see example below
        :rtype: :class:`dict`, :class:`None`

        .. code:: python

            {'apps':     {570: {...}, ...},
             'packages': {123: {...}, ...}
            }
        """
        if not apps and not packages: return

        message = MsgProto(EMsg.ClientPICSProductInfoRequest)

        for app in apps:
            app_info = message.body.apps.add()
            app_info.only_public = False
            if isinstance(app, tuple):
                app_info.appid, app_info.access_token = app
            else:
                app_info.appid = app

        for package in packages:
            package_info = message.body.packages.add()
            if isinstance(package, tuple):
                package_info.appid, package_info.access_token = package
            else:
                package_info.packageid = package

        message.body.meta_data_only = False

        job_id = self.send_job(message)

        data = dict(apps={}, packages={})

        while True:
            chunk = self.wait_event(job_id, timeout=timeout)

            if chunk is None: return
            chunk = chunk[0].body

            for app in chunk.apps:
                data['apps'][app.appid] = vdf.loads(app.buffer[:-1].decode(
                    'utf-8', 'replace'))['appinfo']
            for pkg in chunk.packages:
                data['packages'][pkg.packageid] = vdf.binary_loads(
                    pkg.buffer[4:])[str(pkg.packageid)]

            if not chunk.response_pending:
                break

        return data
Beispiel #17
0
    def change_status(self, persona_state, player_name):
        """Changes user's status according to passed value.
        Can also change profile name.
        """
        sendmsg = MsgProto(EMsg.ClientChangeStatus)
        sendmsg.body.persona_state = persona_state
        sendmsg.body.player_name = player_name

        self.client.send(sendmsg)
Beispiel #18
0
    def _handle_login_key(self, message):
        resp = MsgProto(EMsg.ClientNewLoginKeyAccepted)
        resp.body.unique_id = message.body.unique_id

        if self.logged_on:
            self.send(resp)
            self.idle()
            self.login_key = message.body.login_key
            self.emit(self.EVENT_NEW_LOGIN_KEY)
Beispiel #19
0
 def get_product_changes(self, since_change_number):
     resp = self.steam.send_job_and_wait(MsgProto(
         EMsg.ClientPICSChangesSinceRequest), {
             'since_change_number': since_change_number,
             'send_app_info_changes': True,
             'send_package_info_changes': True,
         },
                                         timeout=10)
     return proto_to_dict(resp) or {}
Beispiel #20
0
 def Send_Friend_Request(self, friend_steam_id):
     """
     Send a friend request to a friend!
     friend_steam_id type: int
     friend_steam_id example: 77777777777777777
     """
     
     msg = MsgProto(EMsg.ClientAddFriend)
     msg.body.steamid_to_add = friend_steam_id
     self.client.send_message_and_wait(msg, None)
Beispiel #21
0
    def send_msg(self, steamid, msg):
        """Sends a message to a steam user.
        """
        sendmsg = MsgProto(EMsg.ClientFriendMsg)
        sendmsg.body.steamid = steamid
        sendmsg.body.chat_entry_type = 1
        sendmsg.body.message = msg
        sendmsg.body.rtime32_server_timestamp = int(time.time())

        self.client.send(sendmsg)
Beispiel #22
0
    def set_ui_mode(self, uimode):
        """
        Set UI mode. Show little icon next to name in friend list. (e.g phone, controller, other)

        :param uimode: UI mode integer
        :type  uimode: :class:`EClientUIMode`

        These app ids will be recorded in :attr:`current_games_played`.
        """
        self.send(MsgProto(EMsg.ClientCurrentUIMode), {'uimode': EClientUIMode(uimode)})
Beispiel #23
0
    def remove(self, steamid):
        """
        Remove a friend

        :param steamid: their steamid
        :type steamid: :class:`int`, :class:`steam.steamid.SteamID`, :class:`SteamUser`
        """
        m = MsgProto(EMsg.ClientRemoveFriend)
        m.body.friendid = steamid
        self._steam.send(m)
Beispiel #24
0
    def send_message(self, message):
        """Send chat message to this steam user

        :param message: message to send
        :type message: str
        """
        self._steam.send(MsgProto(EMsg.ClientFriendMsg), {
            'steamid': self.steam_id,
            'chat_entry_type': EChatEntryType.ChatMsg,
            'message': message.encode('utf8'),
            })
Beispiel #25
0
    def logout(self):
        """
        Logout from steam. Doesn't nothing if not logged on.

        .. note::
            The server will drop the connection immediatelly upon logout.
        """
        if self.logged_on:
            self.logged_on = False
            self.send(MsgProto(EMsg.ClientLogOff))
            self.wait_event('disconnected')
Beispiel #26
0
    def get_app_ticket(self, app_id):
        """Get app ownership ticket

        :param app_id: app id
        :type app_id: :class:`int`
        :return: `CMsgClientGetAppOwnershipTicketResponse <https://github.com/ValvePython/steam/blob/39627fe883feeed2206016bacd92cf0e4580ead6/protobufs/steammessages_clientserver.proto#L158-L162>`_
        :rtype: proto message
        """
        return self.send_job_and_wait(MsgProto(
            EMsg.ClientGetAppOwnershipTicket), {'app_id': app_id},
                                      timeout=10)
Beispiel #27
0
    def request_persona_state(self, steam_ids, state_flags=863):
        """Request persona state data

        :param steam_ids: list of steam ids
        :type  steam_ids: :class:`list`
        :param state_flags: client state flags
        :type  state_flags: :class:`.EClientPersonaStateFlag`
        """
        m = MsgProto(EMsg.ClientRequestFriendData)
        m.body.persona_state_requested = state_flags
        m.body.friends.extend(steam_ids)
        self.send(m)
Beispiel #28
0
 def get_encrypted_app_ticket(self, app_id, userdata):
     """Gets the encrypted app ticket
     :param app_id: app id
     :type  app_id: :class:`int`
     :param userdata: userdata
     :type  userdata: :class:`bytes`
     :return: `EncryptedAppTicket <https://github.com/ValvePython/steam/blob/39627fe883feeed2206016bacd92cf0e4580ead6/protobufs/encrypted_app_ticket.proto>_`
     :rtype: proto message
     """
     return self.send_job_and_wait(MsgProto(EMsg.ClientRequestEncryptedAppTicket),
                                   {'app_id': app_id, 'userdata': userdata},
                                   timeout=10
                                   )
Beispiel #29
0
 def get_product_changes(self, since_change_number):
     try:
         resp = self.steam.send_job_and_wait(MsgProto(EMsg.ClientPICSChangesSinceRequest),
                                             {
             'since_change_number': since_change_number,
             'send_app_info_changes': True,
             'send_package_info_changes': True,
         },
             timeout=10
         )
         return proto_to_dict(resp) or {}
     except Exception as e:
         print('get_product_changes() exception: ' + str(e))
         return {}
Beispiel #30
0
 def Send_Friend_Msg(self, friend_steam_id, message):
     """
     Send a message to a friend with his steamID!
     friend_steam_id type: int
     friend_steam_id example: 77777777777777777
     message type: string
     message example: 'Hello'
     """
     
     msg = MsgProto(EMsg.ClientFriendMsg)
     msg.body.steamid = friend_steam_id
     msg.body.chat_entry_type = 1
     msg.body.message = message.encode('utf-8')
     self.client.send_message_and_wait(msg, None)