Exemple #1
0
    def decode_response(cls, uin: int, seq: int, ret_code: int,
                        command_name: str, data: bytes) -> "OICQResponse":
        """Decode login response and wrap main info of the response.

        Note:
            Source: oicq.wlogin_sdk.request.WtloginHelper.GetStWithPasswd

        Args:
            uin (int): User QQ
            seq (int): Sequence number of the response packet.
            ret_code (int): Return code of the response.
            command_name (str): Command name of the response.
            data (bytes): Payload data of the response.

        Returns:
            LoginSuccess: Login success.
            NeedCaptcha: Captcha image needed.
            AccountFrozen: Account is frozen.
            DeviceLocked: Device lock detected.
            TooManySMSRequest: Too many SMS messages were sent.
            DeviceLockLogin: More login packet needed.
            UnknownLoginStatus: Unknown login status.
            OICQResponse: Invalid login response.
        """
        if ret_code != 0 or not data:
            return OICQResponse(uin, seq, ret_code, command_name)

        data_ = Packet(data)

        sub_command, status, _tlv_bytes = (
            data_.start().uint16().uint8().offset(2).remain().execute())

        _tlv_map = TlvDecoder.decode(_tlv_bytes)

        if status == 0:
            return LoginSuccess(uin, seq, ret_code, command_name, sub_command,
                                status, _tlv_map)
        elif status == 2:
            return NeedCaptcha(uin, seq, ret_code, command_name, sub_command,
                               status, _tlv_map)
        elif status == 40:
            return AccountFrozen(uin, seq, ret_code, command_name, sub_command,
                                 status, _tlv_map)
        elif status == 160 or status == 239:
            return DeviceLocked(uin, seq, ret_code, command_name, sub_command,
                                status, _tlv_map)
        elif status == 162:
            return TooManySMSRequest(uin, seq, ret_code, command_name,
                                     sub_command, status, _tlv_map)
        elif status == 204:
            return DeviceLockLogin(uin, seq, ret_code, command_name,
                                   sub_command, status, _tlv_map)
        else:
            return UnknownLoginStatus(uin, seq, ret_code, command_name,
                                      sub_command, status, _tlv_map)
Exemple #2
0
 def __init__(
     self,
     uin: int,
     seq: int,
     ret_code: int,
     command_name: str,
     sub_command: int,
     status: int,
     _tlv_map: Dict[int, Any],
 ):
     super().__init__(uin, seq, ret_code, command_name, sub_command, status,
                      _tlv_map)
     self.sms_phone = None
     self.verify_url = _tlv_map.get(0x204, b"").decode() or None
     self.message = _tlv_map.get(0x17E, b"").decode() or None
     self.rand_seed = _tlv_map.get(0x403)
     self.t104 = _tlv_map.get(0x104)
     self.t174 = _tlv_map.get(0x174)
     if self.t174:
         t178 = Packet(_tlv_map[0x178])
         self.sms_phone = t178.start().string(4).execute()[0]
Exemple #3
0
 def __init__(
     self,
     uin: int,
     seq: int,
     ret_code: int,
     command_name: str,
     sub_command: int,
     status: int,
     _tlv_map: Dict[int, Any],
 ):
     super().__init__(uin, seq, ret_code, command_name, sub_command, status,
                      _tlv_map)
     self.t104 = _tlv_map[0x104]
     self.captcha_image = bytes()
     self.captcha_sign = bytes()
     self.verify_url = _tlv_map.get(0x192, b"").decode()
     if 0x165 in _tlv_map:
         data = Packet(_tlv_map[0x165])
         sign, image = (data.start().bytes_with_length(
             2, 4).remain().execute())
         self.captcha_sign = sign[2:]
         self.captcha_image = bytes(image)
Exemple #4
0
    async def _handle_login_response(self,
                                     response: Command,
                                     try_times: int = 1) -> LoginSuccess:
        if not isinstance(response, OICQResponse):
            raise RuntimeError("Invalid login response type!")

        if not isinstance(response, UnknownLoginStatus):
            raise ApiResponseError(
                response.uin,
                response.seq,
                response.ret_code,
                response.command_name,
            )

        if isinstance(response, LoginSuccess):
            logger.info(f"{self.nick}({self.uin}) 登录成功!")
            await self._init()
            return response
        elif isinstance(response, NeedCaptcha):
            if response.verify_url:
                logger.info(f"登录失败!请前往 {response.verify_url} 获取 ticket")
                raise LoginSliderNeeded(response.uin, response.verify_url)
            elif response.captcha_image:
                logger.info(f"登录失败!需要根据图片输入验证码")
                raise LoginCaptchaNeeded(response.uin, response.captcha_image,
                                         response.captcha_sign)
            else:
                raise LoginException(
                    response.uin,
                    response.status,
                    "Cannot get verify_url or captcha_image from the response!",
                )
        elif isinstance(response, AccountFrozen):
            logger.info("账号已被冻结!")
            raise LoginAccountFrozen(response.uin)
        elif isinstance(response, DeviceLocked):
            msg = "账号已开启设备锁!"
            if response.sms_phone:
                msg += f"向手机{response.sms_phone}发送验证码 "
            if response.verify_url:
                msg += f"或前往{response.verify_url}扫码验证"
            logger.info(msg + ". " + str(response.message))

            raise LoginDeviceLocked(
                response.uin,
                response.sms_phone,
                response.verify_url,
                response.message,
            )
        elif isinstance(response, TooManySMSRequest):
            logger.info("验证码发送频繁!")
            raise LoginSMSRequestError(response.uin)
        elif isinstance(response, DeviceLockLogin):
            if try_times:
                seq = self.next_seq()
                packet = encode_login_request20(
                    seq,
                    self._key,
                    self._session_id,
                    self._ksid,
                    self.uin,
                    self._t104,
                    self._siginfo.g,
                )
                response = await self.send_and_wait(seq, "wtlogin.login",
                                                    packet)
                return await self._handle_login_response(
                    response, try_times - 1)
            else:
                raise LoginException(
                    response.uin,
                    response.status,
                    "Maximum number of login attempts exceeded!",
                )
        elif isinstance(response, UnknownLoginStatus):
            t146 = response._tlv_map.get(0x146)
            t149 = response._tlv_map.get(0x149)
            if t146:
                packet_ = Packet(t146)
                msg = packet_.start(4).string(2).execute()[0]
            elif t149:
                packet_ = Packet(t149)
                msg = packet_.start(2).string(2).execute()[0]
            else:
                msg = ""
            logger.info(f"未知的登录返回码 {response.status}! {msg}")
            raise LoginException(response.uin, response.status,
                                 "Unknown login status.")