示例#1
0
    def _handle_logon(self, msg):
        CMClient._handle_logon(self, msg)

        result = EResult(msg.body.eresult)

        if result == EResult.OK:
            self._reconnect_backoff_c = 0
            self.logged_on = True
            self.set_persona(EPersonaState.Online)
            self.emit("logged_on")
            return

        # CM kills the connection on error anyway
        self.disconnect()

        if result in (
                EResult.AccountLogonDenied,
                EResult.InvalidLoginAuthCode,
                EResult.AccountLoginDeniedNeedTwoFactor,
                EResult.TwoFactorCodeMismatch,
        ):

            is_2fa = (result in (
                EResult.AccountLoginDeniedNeedTwoFactor,
                EResult.TwoFactorCodeMismatch,
            ))

            if is_2fa:
                code_mismatch = (result == EResult.TwoFactorCodeMismatch)
            else:
                code_mismatch = (result == EResult.InvalidLoginAuthCode)

            self.emit("auth_code_required", is_2fa, code_mismatch)
示例#2
0
文件: __init__.py 项目: d3r3kk/steam
    def _handle_cm_list(self, msg):
        if (self.cm_servers.last_updated + 3600*24 > time()
           and self.cm_servers.cell_id != 0):
            return

        CMClient._handle_cm_list(self, msg)  # clear and merge

        if self.credential_location:
            filepath = os.path.join(self.credential_location, 'cm_servers.json')

            if os.path.exists(filepath):
                try:
                    with open(filepath, 'r') as f:
                        data = json.load(f)
                except ValueError:
                    self._LOG.error("Failed parsing %s", repr(filepath))
                except IOError as e:
                    self._LOG.error("Failed reading %s (%s)", repr(filepath), str(e))
                else:
                    if data.get('last_updated', 0) + 3600*24 > time():
                        return

                self._LOG.debug("Persisted CM server list is stale")

            data = {
                'cell_id': self.cm_servers.cell_id,
                'last_updated': self.cm_servers.last_updated,
                'servers': list(zip(map(ip_from_int, msg.body.cm_addresses), msg.body.cm_ports)),
            }
            try:
                with open(filepath, 'wb') as f:
                    f.write(json.dumps(data, indent=True).encode('ascii'))
                self._LOG.debug("Saved CM servers to %s" % repr(filepath))
            except IOError as e:
                self._LOG.error("saving %s: %s" % (filepath, str(e)))
示例#3
0
    def _handle_cm_list(self, msg):
        if self._cm_servers_timestamp is None:
            self._cm_servers_timestamp = int(time())

        self.cm_servers.clear()
        CMClient._handle_cm_list(self, msg)  # just merges the list

        if self.credential_location:
            filepath = os.path.join(self.credential_location,
                                    'cm_servers.json')

            if not os.path.exists(filepath) or time() - (
                    3600 * 24) > self._cm_servers_timestamp:
                data = {
                    'timestamp':
                    self._cm_servers_timestamp,
                    'servers':
                    list(
                        zip(map(ip_from_int, msg.body.cm_addresses),
                            msg.body.cm_ports)),
                }
                try:
                    with open(filepath, 'wb') as f:
                        f.write(json.dumps(data, indent=True).encode('ascii'))
                    self._LOG.debug("Saved CM servers to %s" % repr(filepath))
                except IOError as e:
                    self._LOG.error("saving %s: %s" % (filepath, str(e)))
示例#4
0
    def _handle_logon(self, msg):
        CMClient._handle_logon(self, msg)

        result = EResult(msg.body.eresult)

        if result == EResult.OK:
            self._reconnect_backoff_c = 0
            self.logged_on = True
            self.emit(self.EVENT_LOGGED_ON)
            return

        # CM kills the connection on error anyway
        self.disconnect()

        if result == EResult.InvalidPassword:
            self.login_key = None

        if result in (EResult.AccountLogonDenied,
                      EResult.InvalidLoginAuthCode,
                      EResult.AccountLoginDeniedNeedTwoFactor,
                      EResult.TwoFactorCodeMismatch,
                      ):

            is_2fa = (result in (EResult.AccountLoginDeniedNeedTwoFactor,
                                 EResult.TwoFactorCodeMismatch,
                                 ))

            if is_2fa:
                code_mismatch = (result == EResult.TwoFactorCodeMismatch)
            else:
                code_mismatch = (result == EResult.InvalidLoginAuthCode)

            self.emit(self.EVENT_AUTH_CODE_REQUIRED, is_2fa, code_mismatch)
示例#5
0
    def test_connect_auto_discovery_success(self, mock_recv, mock_emit):
        # setup
        self.conn.connect.return_value = True
        self.server_list.__len__.return_value = 0

        def fake_servers(*args, **kwargs):
            self.server_list.__len__.return_value = 10
            return True

        self.server_list.bootstrap_from_webapi.side_effect = fake_servers

        # run
        cm = CMClient()

        with gevent.Timeout(3, False):
            cm.connect(retry=1)

        gevent.idle()

        # verify
        self.server_list.bootstrap_from_webapi.assert_called_once_with()
        self.server_list.bootstrap_from_dns.assert_not_called()
        self.conn.connect.assert_called_once_with((127001, 20000))
        mock_emit.assert_called_once_with('connected')
        mock_recv.assert_called_once_with()
示例#6
0
    def _handle_logon(self, msg):
        CMClient._handle_logon(self, msg)

        result = EResult(msg.body.eresult)

        if result == EResult.OK:
            self._reconnect_backoff_c = 0
            self.logged_on = True
            self.emit(self.EVENT_LOGGED_ON)
            return

        # CM kills the connection on error anyway
        self.disconnect()

        if result == EResult.InvalidPassword:
            self.login_key = None

        if result in (
                EResult.AccountLogonDenied,
                EResult.InvalidLoginAuthCode,
                EResult.AccountLoginDeniedNeedTwoFactor,
                EResult.TwoFactorCodeMismatch,
        ):

            is_2fa = (result in (
                EResult.AccountLoginDeniedNeedTwoFactor,
                EResult.TwoFactorCodeMismatch,
            ))

            if is_2fa:
                code_mismatch = (result == EResult.TwoFactorCodeMismatch)
            else:
                code_mismatch = (result == EResult.InvalidLoginAuthCode)

            self.emit(self.EVENT_AUTH_CODE_REQUIRED, is_2fa, code_mismatch)
示例#7
0
    def test_channel_encrypt_sequence(self):
        # setup
        self.conn.connect.return_value = True

        # run ------------
        cm = CMClient()
        cm.connected = True
        gevent.spawn(cm._recv_messages)

        # recieve ChannelEncryptRequest
        self.conn_in.put(
            b'\x17\x05\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x00\x00\x01\x00\x00\x00'
        )
        gevent.idle()
        gevent.idle()
        gevent.idle()
        gevent.idle()

        self.conn.put_message.assert_called_once_with(
            b'\x18\x05\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x00\x00\x80\x00\x00\x00PUBKEY ENCRYPTED SESSION KEY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h-\xc4@\x00\x00\x00\x00'
        )

        # recieve ChannelEncryptResult (OK)
        self.conn_in.put(
            b'\x19\x05\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x00\x00'
        )

        cm.wait_event('channel_secured', timeout=2, raises=True)
示例#8
0
    def send(self, message):
        """
        Send a message to CM

        :param message: a message instance
        :type message: :class:`steam.core.msg.Msg`, :class:`steam.core.msg.MsgProto`
        """
        if not self.connected:
            raise RuntimeError("Cannot send message while not connected")
        CMClient.send(self, message)
示例#9
0
    def __init__(self):
        CMClient.__init__(self)

        # register listners
        self.on(self.EVENT_DISCONNECTED, self._handle_disconnect)
        self.on(self.EVENT_RECONNECT, self._handle_disconnect)
        self.on(EMsg.ClientNewLoginKey, self._handle_login_key)
        self.on(EMsg.ClientUpdateMachineAuth, self._handle_update_machine_auth)

        #: indicates logged on status. Listen to ``logged_on`` when change to ``True``
        self.logged_on = False

        BuiltinBase.__init__(self)
示例#10
0
    def __init__(self):
        CMClient.__init__(self)

        self._LOG = logging.getLogger("SteamClient")
        # register listners
        self.on(None, self._handle_jobs)
        self.on(self.EVENT_DISCONNECTED, self._handle_disconnect)
        self.on(self.EVENT_RECONNECT, self._handle_disconnect)
        self.on(EMsg.ClientNewLoginKey, self._handle_login_key)
        self.on(EMsg.ClientUpdateMachineAuth, self._handle_update_machine_auth)

        #: indicates logged on status. Listen to ``logged_on`` when change to ``True``
        self.logged_on = False

        BuiltinBase.__init__(self)
示例#11
0
文件: __init__.py 项目: d3r3kk/steam
    def send(self, message, body_params=None):
        """Send a message to CM

        :param message: a message instance
        :type message: :class:`.Msg`, :class:`.MsgProto`
        :param body_params: a dict with params to the body (only :class:`.MsgProto`)
        :type body_params: dict
        """
        if not self.connected:
            self._LOG.debug("Trying to send message when not connected. (discarded)")
        else:
            if body_params and isinstance(message, MsgProto):
                proto_fill_from_dict(message.body, body_params)

            CMClient.send(self, message)
示例#12
0
    def __init__(self):
        CMClient.__init__(self)

        self._LOG = logging.getLogger("SteamClient")
        # register listners
        self.on(None, self._handle_jobs)
        self.on("disconnected", self._handle_disconnect)
        self.on("reconnect", self._handle_disconnect)
        self.on(EMsg.ClientNewLoginKey, self._handle_login_key)
        self.on(EMsg.ClientUpdateMachineAuth, self._handle_update_machine_auth)

        #: indicates logged on status. Listen to ``logged_on`` when change to ``True``
        self.logged_on = False

        BuiltinBase.__init__(self)
示例#13
0
    def test_connect(self, mock_recv, mock_emit):
        # setup
        self.conn.connect.return_value = True

        # run
        cm = CMClient()

        with gevent.Timeout(2, False):
            cm.connect()

        gevent.idle()

        # verify
        self.conn.connect.assert_called_once_with((127001, 1))
        mock_emit.assert_called_once_with('connected')
        mock_recv.assert_called_once_with()
示例#14
0
    def send(self, message, body_params=None):
        """.. versionchanged:: 0.8.4
        Send a message to CM

        :param message: a message instance
        :type message: :class:`.Msg`, :class:`.MsgProto`
        :param body_params: a dict with params to the body (only :class:`.MsgProto`)
        :type body_params: dict
        """
        if not self.connected:
            self._LOG.debug("Trying to send message when not connected. (discarded)")
        else:
            if body_params and isinstance(message, MsgProto):
                proto_fill_from_dict(message.body, body_params)

            CMClient.send(self, message)
示例#15
0
    def _parse_message(self, message):
        result = CMClient._parse_message(self, message)

        if result is None:
            return

        emsg, msg = result

        # emit job events
        if msg.proto:
            jobid = msg.header.jobid_target
        else:
            jobid = msg.header.targetJobID

        if jobid not in (-1, 18446744073709551615):
            jobid = "job_%d" % jobid
            if msg.body is None and self.count_listeners(jobid):
                msg.parse()
            self.emit(jobid, msg)

        # emit UMs
        if emsg in (EMsg.ServiceMethod, EMsg.ServiceMethodResponse,
                    EMsg.ServiceMethodSendToClient):
            if msg.body is None and self.count_listeners(
                    msg.header.target_job_name):
                msg.parse()
            self.emit(msg.header.target_job_name, msg)
示例#16
0
    def test_connect(self, mock_recv, mock_emit):
        # setup
        self.conn.connect.return_value = True

        # run
        cm = CMClient()

        with gevent.Timeout(2, False):
            cm.connect()

        gevent.idle()

        # verify
        self.conn.connect.assert_called_once_with((127001, 1))
        mock_emit.assert_called_once_with('connected')
        mock_recv.assert_called_once_with()
示例#17
0
    def test_connect(self, mock_recv, mock_emit):
        # setup
        self.conn.connect.return_value = True
        self.server_list.__len__.return_value = 10

        # run
        cm = CMClient()

        with gevent.Timeout(2, False):
            cm.connect(retry=1)

        gevent.idle()

        # verify
        self.conn.connect.assert_called_once_with((127001, 20000))
        mock_emit.assert_called_once_with('connected')
        mock_recv.assert_called_once_with()
示例#18
0
    def test_connect_auto_discovery_failing(self, mock_recv, mock_emit):
        # setup
        self.conn.connect.return_value = True
        self.server_list.__len__.return_value = 0

        # run
        cm = CMClient()

        with gevent.Timeout(3, False):
            cm.connect(retry=1)

        gevent.idle()

        # verify
        self.server_list.bootstrap_from_webapi.assert_called_once_with()
        self.server_list.bootstrap_from_dns.assert_called_once_with()
        self.conn.connect.assert_not_called()
示例#19
0
    def test_channel_encrypt_sequence(self):
        # setup
        self.conn.connect.return_value = True

        # run ------------
        cm = CMClient()
        cm.connected = True
        gevent.spawn(cm._recv_messages)

        # recieve ChannelEncryptRequest
        self.conn_in.put(b'\x17\x05\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x00\x00\x01\x00\x00\x00')
        gevent.idle(); gevent.idle(); gevent.idle(); gevent.idle()

        self.conn.put_message.assert_called_once_with(b'\x18\x05\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x00\x00\x80\x00\x00\x00PUBKEY ENCRYPTED SESSION KEY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h-\xc4@\x00\x00\x00\x00')

        # recieve ChannelEncryptResult (OK)
        self.conn_in.put(b'\x19\x05\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x00\x00')

        cm.wait_event('channel_secured', timeout=2, raises=True)
示例#20
0
    def _handle_cm_list(self, msg):
        if self._cm_servers_timestamp is None:
            self._cm_servers_timestamp = int(time())

        self.cm_servers.clear()
        CMClient._handle_cm_list(self, msg)  # just merges the list

        if self.credential_location:
            filepath = os.path.join(self.credential_location, 'cm_servers.json')

            if not os.path.exists(filepath) or time() - (3600*24) > self._cm_servers_timestamp:
                data = {
                    'timestamp': self._cm_servers_timestamp,
                    'servers': list(zip(map(ip_from_int, msg.body.cm_addresses), msg.body.cm_ports)),
                }
                try:
                    with open(filepath, 'wb') as f:
                        f.write(json.dumps(data, indent=True).encode('ascii'))
                    self._LOG.debug("Saved CM servers to %s" % repr(filepath))
                except IOError as e:
                    self._LOG.error("saving %s: %s" % (filepath, str(e)))
示例#21
0
 def disconnect(self, *args, **kwargs):
     """Close connection, see :meth:`.CMClient.disconnect`"""
     self.logged_on = False
     CMClient.disconnect(self, *args, **kwargs)
示例#22
0
 def disconnect(self, *args, **kwargs):
     """Close connection, see :meth:`.CMClient.disconnect`"""
     self.logged_on = False
     CMClient.disconnect(self, *args, **kwargs)
示例#23
0
 def connect(self, *args, **kwargs):
     """Attempt to establish connection, see :meth:`.CMClient.connect`"""
     self._bootstrap_cm_list_from_file()
     return CMClient.connect(self, *args, **kwargs)
示例#24
0
 def connect(self, *args, **kwargs):
     """Attempt to establish connection, see :meth:`.CMClient.connect`"""
     self._bootstrap_cm_list_from_file()
     CMClient.connect(self, *args, **kwargs)