129 lines
4.1 KiB
Python
129 lines
4.1 KiB
Python
"""iframe 版登录接口策略"""
|
||
|
||
import time
|
||
import urllib.parse
|
||
|
||
from .crypto import encrypt_nickname_or_phone, encrypt_password
|
||
from .login_api import LoginAPIStrategy
|
||
|
||
|
||
class IframeLoginAPI(LoginAPIStrategy):
|
||
"""iframe 版接口策略
|
||
|
||
混合模式(与 e 语言一致):
|
||
- 登录:使用 wgapi 接口
|
||
- 邮箱验证:使用 iframe 接口
|
||
"""
|
||
|
||
@property
|
||
def name(self) -> str:
|
||
return "iframe"
|
||
|
||
@property
|
||
def first_login_url(self) -> str:
|
||
"""第一次登录用 wgapi 接口获取极验参数"""
|
||
return "https://passport.douyu.com/wgapi/member/passport/login"
|
||
|
||
@property
|
||
def login_url(self) -> str:
|
||
"""第二次登录用 wgapi 接口(与 e 语言一致)"""
|
||
return "https://passport.douyu.com/wgapi/member/passport/login"
|
||
|
||
@property
|
||
def send_email_url(self) -> str:
|
||
"""发送邮箱验证用 iframe 接口"""
|
||
return "https://passport.douyu.com/iframe/sendEmail"
|
||
|
||
@property
|
||
def verify_url(self) -> str:
|
||
"""提交验证码用 iframe 接口"""
|
||
return "https://passport.douyu.com/iframe/remoteLogin"
|
||
|
||
def encrypt_username(self, username: str) -> str:
|
||
"""RC4 加密后 URL 编码"""
|
||
encrypted = encrypt_nickname_or_phone(username)
|
||
return urllib.parse.quote(encrypted, safe="")
|
||
|
||
def build_first_login_data(
|
||
self, username: str, password: str, referer: str
|
||
) -> dict:
|
||
"""构建第一次登录参数(获取极验参数)
|
||
|
||
注:第一次登录使用 wgapi 接口,所以用户名用 base64 编码(而非 URL 编码)。
|
||
"""
|
||
# 第一次登录用 wgapi 接口,需要 base64 编码的用户名
|
||
encrypted_username = encrypt_nickname_or_phone(username)
|
||
return {
|
||
"type": "1",
|
||
"nicknameOrPhoneEncrypt": encrypted_username,
|
||
"password": encrypt_password(password),
|
||
"biz_type": "1",
|
||
"room_id": "0",
|
||
"redirect_url": referer,
|
||
"t": str(int(time.time() * 1000)),
|
||
"client_id": "1",
|
||
"did": "",
|
||
"lang": "",
|
||
"isMultiAccount": "0",
|
||
}
|
||
|
||
def build_second_login_data(
|
||
self,
|
||
username: str,
|
||
password: str,
|
||
gt: str,
|
||
challenge: str,
|
||
validate: str,
|
||
seccode: str,
|
||
code_token: str,
|
||
referer: str,
|
||
) -> dict:
|
||
"""构建第二次登录参数(带极验验证)
|
||
|
||
登录使用 wgapi 接口,参数格式与 wgapi 策略一致。
|
||
"""
|
||
# seccode 格式: validate|jordan(requests 会自动 URL 编码)
|
||
seccode_value = validate + "|jordan"
|
||
|
||
# 使用 base64 编码(wgapi 接口要求),而不是 URL 编码
|
||
encrypted_username = encrypt_nickname_or_phone(username)
|
||
|
||
return {
|
||
"type": "1",
|
||
"nicknameOrPhoneEncrypt": encrypted_username,
|
||
"password": encrypt_password(password),
|
||
"room_id": "0",
|
||
"code_type": "1",
|
||
"code_token": code_token,
|
||
"gt_version": "v3",
|
||
"geetest_challenge": challenge,
|
||
"geetest_validate": validate,
|
||
"geetest_seccode": seccode_value,
|
||
"code_data[geetest_challenge]": challenge,
|
||
"code_data[geetest_validate]": validate,
|
||
"code_data[geetest_seccode]": seccode_value,
|
||
"code_data[gt_version]": "v3",
|
||
"code_data[code]": "",
|
||
"redirect_url": referer,
|
||
"t": str(int(time.time() * 1000)),
|
||
"client_id": "1",
|
||
"did": "",
|
||
"lang": "",
|
||
"isMultiAccount": "0",
|
||
"biz_type": "1",
|
||
}
|
||
|
||
def build_send_email_data(self, code: str) -> dict:
|
||
"""构建发送邮箱验证参数"""
|
||
return {"cacheId": code}
|
||
|
||
def build_verify_data(self, code: str, captcha: str) -> dict:
|
||
"""构建提交验证码参数"""
|
||
return {
|
||
"veify_type": "2", # e 语言原文如此,斗鱼接口拼写
|
||
"phoneCaptcha": captcha,
|
||
"client_id": "1",
|
||
"isMultiAccount": "0",
|
||
"cacheId": code,
|
||
}
|