Disable SliderCaptcha. #745

This commit is contained in:
Karlatemp 2020-12-24 00:34:13 +08:00
parent dffade2a92
commit 5db71cd299
No known key found for this signature in database
GPG Key ID: 21FBDDF664FF06F8
6 changed files with 55 additions and 14 deletions

View File

@ -61,6 +61,11 @@ public class NoStandardInputForCaptchaException @MiraiInternalApi constructor(
@MiraiExperimentalApi("Will be removed when SMS login is supported")
public class UnsupportedSMSLoginException(message: String?) : LoginFailedException(true, message)
/**
* 无法完成滑块验证
*/
public class NotSupportedSliderCaptchaException(message: String?) : LoginFailedException(true, message)
/**
* mirai 实现的异常
*/

View File

@ -45,6 +45,10 @@ public abstract class LoginSolver {
*/
public abstract suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String?
// TODO: 2020-12-24 滑动验证码支持
@MiraiInternalApi
public open val isSliderCaptchaSupport: Boolean get() = false
/**
* 处理滑动验证码.
* 返回 null 以表示无法处理验证码, 将会刷新验证码或重试登录.
@ -89,6 +93,7 @@ public abstract class LoginSolver {
public fun getDefault(): LoginSolver = Default
?: error("LoginSolver is not provided by default on your platform. Please specify by BotConfiguration.loginSolver")
}
}
/**

View File

@ -93,7 +93,7 @@ internal class QQAndroidBot constructor(
@Throws(LoginFailedException::class) // only
override suspend fun relogin(cause: Throwable?) {
client.useNextServers { host, port ->
network.closeEverythingAndRelogin(host, port, cause)
network.closeEverythingAndRelogin(host, port, cause, 0)
}
}

View File

@ -73,7 +73,7 @@ internal abstract class BotNetworkHandler : CoroutineScope {
*/
@Suppress("SpellCheckingInspection")
@MiraiInternalApi
abstract suspend fun closeEverythingAndRelogin(host: String, port: Int, cause: Throwable? = null)
abstract suspend fun closeEverythingAndRelogin(host: String, port: Int, cause: Throwable? = null, step: Int)
/**
* 初始化获取好友列表等值.

View File

@ -40,10 +40,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin
import net.mamoe.mirai.internal.utils.*
import net.mamoe.mirai.internal.utils.io.readPacketExact
import net.mamoe.mirai.network.ForceOfflineException
import net.mamoe.mirai.network.RetryLaterException
import net.mamoe.mirai.network.UnsupportedSMSLoginException
import net.mamoe.mirai.network.WrongPasswordException
import net.mamoe.mirai.network.*
import net.mamoe.mirai.utils.*
import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.coroutines.CoroutineContext
@ -114,10 +111,14 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
}.also { heartbeatJob = it }
}
override suspend fun closeEverythingAndRelogin(host: String, port: Int, cause: Throwable?) {
// @param step
// 0 -> 初始状态, 其他函数调用应永远传入 0
// 1 -> 代表滑块验证已禁用
override suspend fun closeEverythingAndRelogin(host: String, port: Int, cause: Throwable?, step: Int) {
heartbeatJob?.cancel(CancellationException("relogin", cause))
heartbeatJob?.join()
_packetReceiverJob?.cancel(CancellationException("relogin", cause))
_packetReceiverJob?.join()
if (::channel.isInitialized) {
// if (channel.isOpen) {
// kotlin.runCatching {
@ -161,14 +162,20 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
return this
}
val isSliderCaptchaSupport = bot.configuration.loginSolver?.isSliderCaptchaSupport ?: false
val allowSlider = isSliderCaptchaSupport
|| bot.configuration.protocol == BotConfiguration.MiraiProtocol.ANDROID_PHONE
|| step == 0
fun loginSolverNotNull() = bot.configuration.loginSolver.notnull()
var response: WtLogin.Login.LoginPacketResponse = WtLogin.Login.SubCommand9(bot.client).sendAndExpect()
var response: WtLogin.Login.LoginPacketResponse =
WtLogin.Login.SubCommand9(bot.client, allowSlider).sendAndExpect()
mainloop@ while (true) {
when (response) {
is WtLogin.Login.LoginPacketResponse.UnsafeLogin -> {
loginSolverNotNull().onSolveUnsafeDeviceLoginVerify(bot, response.url)
response = WtLogin.Login.SubCommand9(bot.client).sendAndExpect()
response = WtLogin.Login.SubCommand9(bot.client, allowSlider).sendAndExpect()
}
is WtLogin.Login.LoginPacketResponse.Captcha -> when (response) {
@ -183,6 +190,21 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
continue@mainloop
}
is WtLogin.Login.LoginPacketResponse.Captcha.Slider -> {
if (!isSliderCaptchaSupport) {
if (step == 0) {
return closeEverythingAndRelogin(host, port, cause, 1)
}
throw NotSupportedSliderCaptchaException(
buildString {
append("Mirai 无法完成滑块验证.")
if (allowSlider) {
append(" 使用协议 ")
append(bot.configuration.protocol)
append(" 强制要求滑块验证, 请更换协议后重试")
}
}
)
}
val ticket = loginSolverNotNull().onSolveSliderCaptcha(bot, response.url).orEmpty()
response = WtLogin.Login.SubCommand2.SubmitSliderCaptcha(bot.client, ticket).sendAndExpect()
continue@mainloop
@ -193,7 +215,13 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
if (response.message.contains("0x9a")) { //Error(title=登录失败, message=请你稍后重试。(0x9a), errorInfo=)
throw RetryLaterException()
}
throw WrongPasswordException(response.toString())
val msg = response.toString()
throw WrongPasswordException(buildString(capacity = msg.length) {
append(msg)
if (msg.contains("当前上网环境异常")) { // Error(title=禁止登录, message=当前上网环境异常,请更换网络环境或在常用设备上登录或稍后再试。, errorInfo=)
append(", tips=若频繁出现, 请尝试开启设备锁")
}
})
}
is WtLogin.Login.LoginPacketResponse.DeviceLockLogin -> {

View File

@ -123,12 +123,13 @@ internal class WtLogin {
private const val appId = 16L
operator fun invoke(
client: QQAndroidClient
client: QQAndroidClient,
allowSlider: Boolean
): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId ->
writeSsoPacket(client, client.subAppId, commandName, sequenceId = sequenceId) {
writeOicqRequestPacket(client, EncryptMethodECDH(client.ecdh), 0x0810) {
writeShort(9) // subCommand
writeShort(0x18) // count of TLVs, probably ignored by server?
writeShort(if (allowSlider) 0x18 else 0x17) // count of TLVs, probably ignored by server?
//writeShort(LoginType.PASSWORD.value.toShort())
t18(appId, client.appClientVersion, client.uin)
@ -231,7 +232,9 @@ internal class WtLogin {
t187(client.device.macAddress)
t188(client.device.androidId)
t194(client.device.imsiMd5)
if (allowSlider) {
t191()
}
/*
t201(N = byteArrayOf())*/