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)
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]
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)
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.")