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") @MiraiExperimentalApi("Will be removed when SMS login is supported")
public class UnsupportedSMSLoginException(message: String?) : LoginFailedException(true, message) public class UnsupportedSMSLoginException(message: String?) : LoginFailedException(true, message)
/**
* 无法完成滑块验证
*/
public class NotSupportedSliderCaptchaException(message: String?) : LoginFailedException(true, message)
/** /**
* mirai 实现的异常 * mirai 实现的异常
*/ */

View File

@ -45,6 +45,10 @@ public abstract class LoginSolver {
*/ */
public abstract suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String? public abstract suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String?
// TODO: 2020-12-24 滑动验证码支持
@MiraiInternalApi
public open val isSliderCaptchaSupport: Boolean get() = false
/** /**
* 处理滑动验证码. * 处理滑动验证码.
* 返回 null 以表示无法处理验证码, 将会刷新验证码或重试登录. * 返回 null 以表示无法处理验证码, 将会刷新验证码或重试登录.
@ -89,6 +93,7 @@ public abstract class LoginSolver {
public fun getDefault(): LoginSolver = Default public fun getDefault(): LoginSolver = Default
?: error("LoginSolver is not provided by default on your platform. Please specify by BotConfiguration.loginSolver") ?: 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 @Throws(LoginFailedException::class) // only
override suspend fun relogin(cause: Throwable?) { override suspend fun relogin(cause: Throwable?) {
client.useNextServers { host, port -> 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") @Suppress("SpellCheckingInspection")
@MiraiInternalApi @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.network.protocol.packet.login.WtLogin
import net.mamoe.mirai.internal.utils.* import net.mamoe.mirai.internal.utils.*
import net.mamoe.mirai.internal.utils.io.readPacketExact import net.mamoe.mirai.internal.utils.io.readPacketExact
import net.mamoe.mirai.network.ForceOfflineException import net.mamoe.mirai.network.*
import net.mamoe.mirai.network.RetryLaterException
import net.mamoe.mirai.network.UnsupportedSMSLoginException
import net.mamoe.mirai.network.WrongPasswordException
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -114,10 +111,14 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
}.also { heartbeatJob = it } }.also { heartbeatJob = it }
} }
// @param step
override suspend fun closeEverythingAndRelogin(host: String, port: Int, cause: Throwable?) { // 0 -> 初始状态, 其他函数调用应永远传入 0
// 1 -> 代表滑块验证已禁用
override suspend fun closeEverythingAndRelogin(host: String, port: Int, cause: Throwable?, step: Int) {
heartbeatJob?.cancel(CancellationException("relogin", cause)) heartbeatJob?.cancel(CancellationException("relogin", cause))
heartbeatJob?.join() heartbeatJob?.join()
_packetReceiverJob?.cancel(CancellationException("relogin", cause))
_packetReceiverJob?.join()
if (::channel.isInitialized) { if (::channel.isInitialized) {
// if (channel.isOpen) { // if (channel.isOpen) {
// kotlin.runCatching { // kotlin.runCatching {
@ -161,14 +162,20 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
return this 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() 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) { mainloop@ while (true) {
when (response) { when (response) {
is WtLogin.Login.LoginPacketResponse.UnsafeLogin -> { is WtLogin.Login.LoginPacketResponse.UnsafeLogin -> {
loginSolverNotNull().onSolveUnsafeDeviceLoginVerify(bot, response.url) 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) { is WtLogin.Login.LoginPacketResponse.Captcha -> when (response) {
@ -183,6 +190,21 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
continue@mainloop continue@mainloop
} }
is WtLogin.Login.LoginPacketResponse.Captcha.Slider -> { 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() val ticket = loginSolverNotNull().onSolveSliderCaptcha(bot, response.url).orEmpty()
response = WtLogin.Login.SubCommand2.SubmitSliderCaptcha(bot.client, ticket).sendAndExpect() response = WtLogin.Login.SubCommand2.SubmitSliderCaptcha(bot.client, ticket).sendAndExpect()
continue@mainloop continue@mainloop
@ -193,7 +215,13 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
if (response.message.contains("0x9a")) { //Error(title=登录失败, message=请你稍后重试。(0x9a), errorInfo=) if (response.message.contains("0x9a")) { //Error(title=登录失败, message=请你稍后重试。(0x9a), errorInfo=)
throw RetryLaterException() 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 -> { is WtLogin.Login.LoginPacketResponse.DeviceLockLogin -> {

View File

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