예제 #1
0
파일: __init__.py 프로젝트: baidumail/steam
    def anonymous_login(self):
        """Login as anonymous user

        :return: logon result, see `CMsgClientLogonResponse.eresult <https://github.com/ValvePython/steam/blob/513c68ca081dc9409df932ad86c66100164380a6/protobufs/steammessages_clientserver.proto#L95-L118>`_
        :rtype: :class:`.EResult`
        """
        self._LOG.debug("Attempting Anonymous login")

        self._pre_login()

        self.username = None
        self.login_key = None

        message = MsgProto(EMsg.ClientLogon)
        message.header.steamid = SteamID(type='AnonUser', universe='Public')
        message.body.protocol_version = 65579
        self.send(message)

        resp = self.wait_msg(EMsg.ClientLogOnResponse, timeout=30)
        return EResult(resp.body.eresult) if resp else EResult.Fail
예제 #2
0
파일: apps.py 프로젝트: philippj/steam
    def request_free_license(self, app_ids):
        """ Request license for free app(s)

        :param app_ids: list of app ids
        :type  app_ids: :class:`list`
        :return: format (:class:`.EResult`, result_details, receipt_info)
        :rtype: :class:`tuple`
        """
        resp = self.send_job_and_wait(
            MsgProto(EMsg.ClientRequestFreeLicense),
            {'appids': map(int, app_ids)},
            timeout=10,
        )

        if resp:
            return EResult(
                resp.eresult), resp.granted_appids, resp.granted_packageids

        else:
            return EResult.Timeout, None, None
예제 #3
0
파일: apps.py 프로젝트: moonberries/steam
    def get_cdn_auth_token(self, depot_id, hostname):
        """Get CDN authentication token

        .. note::
            This token is no longer needed for access to CDN files

        :param depot_id: depot id
        :type  depot_id: :class:`int`
        :param hostname: cdn hostname
        :type  hostname: :class:`str`
        :return: `CMsgClientGetCDNAuthTokenResponse <https://github.com/ValvePython/steam/blob/39627fe883feeed2206016bacd92cf0e4580ead6/protobufs/steammessages_clientserver_2.proto#L585-L589>`_
        :rtype: proto message
        """
        return self.send_job_and_wait(MsgProto(EMsg.ClientGetCDNAuthToken),
                                      {
                                       'depot_id': depot_id,
                                       'host_name': hostname,
                                      },
                                      timeout=10
                                      )
예제 #4
0
파일: user.py 프로젝트: ValvePython/steam
    def send_message(self, message):
        """Send chat message to this steam user

        :param message: message to send
        :type message: str
        """
        # new chat
        if self._steam.chat_mode == 2:
            self._steam.send_um("FriendMessages.SendMessage#1", {
                'steamid': self.steam_id,
                'message': message,
                'chat_entry_type': EChatEntryType.ChatMsg,
                })
        # old chat
        else:
            self._steam.send(MsgProto(EMsg.ClientFriendMsg), {
                'steamid': self.steam_id,
                'chat_entry_type': EChatEntryType.ChatMsg,
                'message': message.encode('utf8'),
                })
예제 #5
0
    def get_changes_since(self, change_number, app_changes=True, package_changes=False):
        """Get changes since a change number

        :param change_number: change number to use as stating point
        :type change_number: :class:`int`
        :param app_changes: whether to inclued app changes
        :type app_changes: :class:`bool`
        :param package_changes: whether to inclued package changes
        :type package_changes: :class:`bool`
        :return: `CMsgClientPICSChangesSinceResponse <https://github.com/ValvePython/steam/blob/39627fe883feeed2206016bacd92cf0e4580ead6/protobufs/steammessages_clientserver.proto#L1171-L1191>`_
        :rtype: proto message instance, or :class:`None` on timeout
        """
        return self.send_job_and_wait(MsgProto(EMsg.ClientPICSChangesSinceRequest),
                                      {
                                       'since_change_number': change_number,
                                       'send_app_info_changes': app_changes,
                                       'send_package_info_changes': package_changes,
                                      },
                                      timeout=10
                                      )
예제 #6
0
    def _handle_friends_list(self, message):
        incremental = message.body.bincremental
        if incremental == False:
            self._fr.clear()

        pstate_check = set()

        # update internal friends list
        for friend in message.body.friends:
            steamid = friend.ulfriendid
            rel = EFriendRelationship(friend.efriendrelationship)

            if steamid not in self._fr:
                suser = SteamUser(steamid, rel)
                self._fr[suser] = suser

                if rel in (2, 4):
                    if incremental == False:
                        pstate_check.add(steamid)

                    if rel == EFriendRelationship.RequestRecipient:
                        self.emit('friend_invite', suser)
            else:
                oldrel = self._fr[steamid]._data['relationship']
                self._fr[steamid]._data['relationship'] = rel

                if rel == EFriendRelationship.No:
                    self.emit('friend_removed', self._fr.pop(steamid))
                elif oldrel in (2, 4) and rel == EFriendRelationship.Friend:
                    self.emit('friend_new', self._fr[steamid])

        # request persona state for any new entries
        if pstate_check:
            m = MsgProto(EMsg.ClientRequestFriendData)
            m.body.persona_state_requested = 4294967295  # request all possible flags
            m.body.friends.extend(pstate_check)
            self._steam.send(m)

        if not self.ready:
            self.ready = True
            self.emit('ready')
예제 #7
0
파일: cm.py 프로젝트: oczkers/steam-httpx
    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:
            self._LOG.debug("Dropped unexpected message: %s (is_proto: %s)",
                            repr(emsg),
                            is_proto(emsg_id),
                            )
            return

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

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

        if self.count_listeners(emsg) or self.verbose_debug:
            msg.parse()

        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)
        return emsg, msg
예제 #8
0
    def add(self, steamid_or_accountname_or_email):
        """
        Add/Accept a steam user to be your friend.
        When someone sends you an invite, use this method to accept it.

        :param steamid_or_accountname_or_email: steamid, account name, or email
        :type steamid_or_accountname_or_email: :class:`int`, :class:`.SteamID`, :class:`.SteamUser`, :class:`str`

        .. note::
            Adding by email doesn't not work. It's only mentioned for the sake of completeness.
        """
        m = MsgProto(EMsg.ClientAddFriend)

        if isinstance(steamid_or_accountname_or_email, (intBase, int)):
            m.body.steamid_to_add = steamid_or_accountname_or_email
        elif isinstance(steamid_or_accountname_or_email, SteamUser):
            m.body.steamid_to_add = steamid_or_accountname_or_email.steam_id
        else:
            m.body.accountname_or_email_to_add = steamid_or_accountname_or_email

        self._steam.send_job(m)
예제 #9
0
파일: user.py 프로젝트: ValvePython/steam
    def change_status(self, **kwargs):
        """
        Set name, persona state, flags

        .. note::
            Changing persona state will also change :attr:`persona_state`

        :param persona_state: persona state (Online/Offline/Away/etc)
        :type persona_state: :class:`.EPersonaState`
        :param player_name: profile name
        :type player_name: :class:`str`
        :param persona_state_flags: persona state flags
        :type persona_state_flags: :class:`.EPersonaStateFlag`
        """
        if not kwargs: return

        self.persona_state = kwargs.get('persona_state', self.persona_state)

        message = MsgProto(EMsg.ClientChangeStatus)
        proto_fill_from_dict(message.body, kwargs)
        self.send(message)
예제 #10
0
    def get_product_info(self, 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')[:-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
예제 #11
0
    def send(self, message):
        """Send service method request

        :param message: proto message instance (use :meth:`SteamUnifiedMessages.get`)
        :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 message not in self._data:
            raise ValueError(
                "Supplied message seems to be invalid. Did you use 'get' method?"
            )

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

        return self._steam.send_job(capsule)
예제 #12
0
파일: apps.py 프로젝트: philippj/steam
    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.packageid, pkg.access_token),
                        resp.package_access_tokens)),
            }
예제 #13
0
    def get_entries(self, start=0, end=0, data_request=None, steam_ids=None):
        """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`
        :param steam_ids: list of steam ids when using :attr:`.ELeaderboardDataRequest.Users`
        :type steamids: :class:`list`
        :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 = self.data_request if data_request is None else data_request

        if steam_ids:
            message.body.steamids.extend(steam_ids)

        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))

        if resp.HasField('leaderboard_entry_count'):
            self.entry_count = resp.leaderboard_entry_count

        return resp.entries
예제 #14
0
    def login(self,
              username,
              password='',
              login_key=None,
              auth_code=None,
              two_factor_code=None,
              login_id=None):
        """Login as a specific user

        :param username: username
        :type  username: :class:`str`
        :param password: password
        :type  password: :class:`str`
        :param login_key: login key, instead of password
        :type  login_key: :class:`str`
        :param auth_code: email authentication code
        :type  auth_code: :class:`str`
        :param two_factor_code: 2FA authentication code
        :type  two_factor_code: :class:`str`
        :param login_id: number used for identifying logon session
        :type  login_id: :class:`int`
        :return: logon result, see `CMsgClientLogonResponse.eresult <https://github.com/ValvePython/steam/blob/513c68ca081dc9409df932ad86c66100164380a6/protobufs/steammessages_clientserver.proto#L95-L118>`_
        :rtype: :class:`.EResult`

        .. note::
            Failure to login will result in the server dropping the connection, ``error`` event is fired

        ``auth_code_required`` event is fired when 2FA or Email code is needed.
        Here is example code of how to handle the situation.

        .. code:: python

            @steamclient.on(steamclient.EVENT_AUTH_CODE_REQUIRED)
            def auth_code_prompt(is_2fa, code_mismatch):
                if is_2fa:
                    code = input("Enter 2FA Code: ")
                    steamclient.login(username, password, two_factor_code=code)
                else:
                    code = input("Enter Email Code: ")
                    steamclient.login(username, password, auth_code=code)

        Codes are required every time a user logins if sentry is not setup.
        See :meth:`set_credential_location`
        """
        self._LOG.debug("Attempting login")

        eresult = self._pre_login()

        if eresult != EResult.OK:
            return eresult

        self.username = username

        message = MsgProto(EMsg.ClientLogon)
        message.header.steamid = SteamID(type='Individual', universe='Public')
        message.body.protocol_version = 65580
        message.body.client_package_version = 1561159470
        message.body.client_os_type = EOSType.Windows10
        message.body.client_language = "english"
        message.body.should_remember_password = True
        message.body.supports_rate_limit_response = True
        message.body.chat_mode = self.chat_mode

        if login_id is None:
            message.body.obfuscated_private_ip.v4 = ip_to_int(
                self.connection.local_address) ^ 0xF00DBAAD
        else:
            message.body.obfuscated_private_ip.v4 = login_id

        message.body.account_name = username

        if login_key:
            message.body.login_key = login_key
        else:
            message.body.password = password

        sentry = self.get_sentry(username)
        if sentry is None:
            message.body.eresult_sentryfile = EResult.FileNotFound
        else:
            message.body.eresult_sentryfile = EResult.OK
            message.body.sha_sentryfile = sha1_hash(sentry)

        if auth_code:
            message.body.auth_code = auth_code
        if two_factor_code:
            message.body.two_factor_code = two_factor_code

        self.send(message)

        resp = self.wait_msg(EMsg.ClientLogOnResponse, timeout=30)

        if resp and resp.body.eresult == EResult.OK:
            self.sleep(0.5)

        return EResult(resp.body.eresult) if resp else EResult.Fail
예제 #15
0
 def get_player_count(self, appid):
     resp = self.steam.send_job_and_wait(MsgProto(
         EMsg.ClientGetNumberOfCurrentPlayersDP), {'appid': appid},
                                         timeout=10)
     return proto_to_dict(resp) or {}
예제 #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 :class:`dict`
        :type apps: :class:`list`
        :param packages: items in the list should be either just ``package_id``, or :class:`dict`
        :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: {...}, ...}
            }

        Access token is needed to access full information for certain apps, and also package info.
        Each app and package has its' own access token.
        If a token is required then ``_missing_token=True`` in the response.

        App access tokens are obtained by calling :meth:`get_access_tokens`, and are returned only
        when the account has a license for the specified app. Example code:

        .. code:: python

            result = client.get_product_info(apps=[123])

            if result['apps'][123]['_missing_token']:
                tokens = client.get_access_token(apps=[123])

                result = client.get_product_info(apps=[{'appid': 123,
                                                        'access_token': tokens['apps'][123]
                                                        }])

        .. note::
            It is best to just request access token for all apps, before sending a product info
            request.

        Package tokens are located in the account license list. See :attr:`.licenses`

        .. code:: python

            result = client.get_product_info(packages=[{'packageid': 123,
                                                        'access_token': client.licenses[123].access_token,
                                                        }])
        """
        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, dict):
                        proto_fill_from_dict(app_info, app)
                else:
                        app_info.appid = app

        for package in packages:
                package_info = message.body.packages.add()
                if isinstance(package, dict):
                        proto_fill_from_dict(package_info, 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, raises=True)

            chunk = chunk[0].body

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

            if not chunk.response_pending:
                break

        return data
예제 #17
0
파일: cm.py 프로젝트: jackma92/steam
    def __heartbeat(self, interval):
        message = MsgProto(EMsg.ClientHeartBeat)

        while True:
            self.sleep(interval)
            self.send(message)
예제 #18
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 :class:`dict`
        :type apps: :class:`list`
        :param packages: items in the list should be either just ``package_id``, or :class:`dict`
        :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: {...}, ...}
            }

        When a token is needed to access the full info (e.g. branches and depots) the ``_missing_token``
        will be set to ``True``. The token can be obtained by calling :meth:`get_access_tokens` if
        the account has a license.

        .. code:: python
            result = client.get_product_info(apps=[123])

            if result['apps'][123]['_missing_token']:
                tokens = client.get_access_token(apps=[123])

                result = client.get_product_info(apps={'appid': 123,
                                                       'access_token': tokens['apps'][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, dict):
                        proto_fill_from_dict(app_info, app)
                else:
                        app_info.appid = app

        for package in packages:
                package_info = message.body.packages.add()
                if isinstance(package, dict):
                        proto_fill_from_dict(package_info, 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, raises=True)

            chunk = chunk[0].body

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

            if not chunk.response_pending:
                break

        return data
예제 #19
0
 def _handle_login_key(self, message):
     self.login_key = message.body.login_key
     resp = MsgProto(EMsg.ClientNewLoginKeyAccepted)
     resp.body.unique_id = message.body.unique_id
     self.send(resp)
예제 #20
0
파일: apps.py 프로젝트: philippj/steam
    def get_product_info(self,
                         apps=[],
                         packages=[],
                         meta_data_only=False,
                         raw=False,
                         auto_access_tokens=True,
                         timeout=15):
        """Get product info for apps and packages

        :param apps: items in the list should be either just ``app_id``, or :class:`dict`
        :type  apps: :class:`list`
        :param packages: items in the list should be either just ``package_id``, or :class:`dict`
        :type  packages: :class:`list`
        :param meta_data_only: only meta data will be returned in the reponse (e.g. change number, missing_token, sha1)
        :type  meta_data_only: :class:`bool`
        :param raw: Data buffer for each app is returned as bytes in its' original form. Apps buffer is text VDF, and package buffer is binary VDF
        :type  raw: :class:`bool`
        :param auto_access_token: automatically request and fill access tokens
        :type  auto_access_token: :class:`bool`
        :return: dict with ``apps`` and ``packages`` containing their info, see example below
        :rtype: :class:`dict`, :class:`None`

        .. code:: python

            {'apps':     {570: {...}, ...},
             'packages': {123: {...}, ...}
            }

        Access token is needed to access full information for certain apps, and also package info.
        Each app and package has its' own access token.
        If a token is required then ``_missing_token=True`` in the response.

        App access tokens are obtained by calling :meth:`get_access_tokens`, and are returned only
        when the account has a license for the specified app. Example code:

        .. code:: python

            result = client.get_product_info(apps=[123])

            if result['apps'][123]['_missing_token']:
                tokens = client.get_access_token(apps=[123])

                result = client.get_product_info(apps=[{'appid': 123,
                                                        'access_token': tokens['apps'][123]
                                                        }])

        .. note::
            It is best to just request access token for all apps, before sending a product info
            request.

        Package tokens are located in the account license list. See :attr:`.licenses`

        .. code:: python

            result = client.get_product_info(packages=[{'packageid': 123,
                                                        'access_token': client.licenses[123].access_token,
                                                        }])
        """
        if not apps and not packages:
            return

        if auto_access_tokens:
            tokens = self.get_access_tokens(
                app_ids=list(
                    map(
                        lambda app: app['appid']
                        if isinstance(app, dict) else app, apps)),
                package_ids=list(
                    map(
                        lambda pkg: pkg['packageid']
                        if isinstance(pkg, dict) else pkg, packages)))
        else:
            tokens = None

        message = MsgProto(EMsg.ClientPICSProductInfoRequest)

        for app in apps:
            app_info = message.body.apps.add()

            if tokens:
                app_info.access_token = tokens['apps'].get(
                    app['appid'] if isinstance(app, dict) else app, 0)

            if isinstance(app, dict):
                proto_fill_from_dict(app_info, app)
            else:
                app_info.appid = app

        for package in packages:
            package_info = message.body.packages.add()

            if tokens:
                package_info.access_token = tokens['packages'].get(
                    package['packageid']
                    if isinstance(package, dict) else package, 0)

            if isinstance(package, dict):
                proto_fill_from_dict(package_info, package)
            else:
                package_info.packageid = package

        message.body.meta_data_only = meta_data_only
        message.body.num_prev_failed = 0
        message.body.supports_package_tokens = 1

        job_id = self.send_job(message)

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

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

            chunk = chunk[0].body

            for app in chunk.apps:
                if app.buffer and not raw:
                    data['apps'][app.appid] = vdf.loads(app.buffer[:-1].decode(
                        'utf-8', 'replace'))['appinfo']
                else:
                    data['apps'][app.appid] = {}

                data['apps'][app.appid]['_missing_token'] = app.missing_token
                data['apps'][app.appid]['_change_number'] = app.change_number
                data['apps'][app.appid]['_sha'] = hexlify(
                    app.sha).decode('ascii')
                data['apps'][app.appid]['_size'] = app.size

                if app.buffer and raw:
                    data['apps'][app.appid]['_buffer'] = app.buffer

            for pkg in chunk.packages:
                if pkg.buffer and not raw:
                    data['packages'][pkg.packageid] = vdf.binary_loads(
                        pkg.buffer[4:]).get(str(pkg.packageid), {})
                else:
                    data['packages'][pkg.packageid] = {}

                data['packages'][
                    pkg.packageid]['_missing_token'] = pkg.missing_token
                data['packages'][
                    pkg.packageid]['_change_number'] = pkg.change_number
                data['packages'][pkg.packageid]['_sha'] = hexlify(
                    pkg.sha).decode('ascii')
                data['packages'][pkg.packageid]['_size'] = pkg.size

                if pkg.buffer and raw:
                    data['packages'][pkg.packageid]['_buffer'] = pkg.buffer

            if not chunk.response_pending:
                break

        return data
예제 #21
0
    def login(self,
              username,
              password='',
              login_key=None,
              auth_code=None,
              two_factor_code=None):
        """
        Login as a specific user

        :param username: username
        :type username: :class:`str`
        :param password: password
        :type password: :class:`str`
        :param login_key: login key, instead of password
        :type login_key: :class:`str`
        :param auth_code: email authentication code
        :type auth_code: :class:`str`
        :param two_factor_code: 2FA authentication code
        :type two_factor_code: :class:`str`

        .. note::
            Failure to login will result in the server dropping the connection, ``error`` event is fired

        ``auth_code_required`` event is fired when 2FA or Email code is needed.
        Here is example code of how to handle the situation.

        .. code:: python

            @steamclient.on('auth_code_required')
            def auth_code_prompt(is_2fa, code_mismatch):
                if is_2fa:
                    code = raw_input("Enter 2FA Code: ")
                    steamclient.login(username, password, two_factor_code=code)
                else:
                    code = raw_input("Enter Email Code: ")
                    steamclient.login(username, password, auth_code=code)

        Codes are required every time a user logins if sentry is not setup.
        See :meth:`set_credential_location`
        """
        self._LOG.debug("Attempting login")

        self._pre_login()

        self.username = username

        message = MsgProto(EMsg.ClientLogon)
        message.header.steamid = SteamID(type='Individual', universe='Public')
        message.body.protocol_version = 65579
        message.body.client_package_version = 1771
        message.body.client_os_type = EOSType.Win10
        message.body.client_language = "english"
        message.body.should_remember_password = True

        message.body.account_name = username

        if login_key:
            message.body.login_key = login_key
        else:
            message.body.password = password

        sentry = self.get_sentry(username)
        if sentry is None:
            message.body.eresult_sentryfile = EResult.FileNotFound
        else:
            message.body.eresult_sentryfile = EResult.OK
            message.body.sha_sentryfile = sha1_hash(sentry)

        if auth_code:
            message.body.auth_code = auth_code
        if two_factor_code:
            message.body.two_factor_code = two_factor_code

        self.send(message)