Commit 0ede4989 authored by Karlatemp's avatar Karlatemp Committed by GitHub

LoginSolver swing (#257)

* LoginSolver, gui support

* make `internal`,`object`, and rename.
parent 03cffb89
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.utils
/**
* @author Karlatemp <karlatemp@vip.qq.com> <https://github.com/Karlatemp>
*/
import kotlinx.coroutines.CompletableDeferred
import java.awt.BorderLayout
import java.awt.Desktop
import java.awt.event.KeyEvent
import java.awt.event.KeyListener
import java.awt.event.WindowAdapter
import java.awt.event.WindowEvent
import javax.swing.JFrame
import javax.swing.JTextField
internal class WindowInitialzier(private val initializer: WindowInitialzier.(JFrame) -> Unit) {
private lateinit var frame0: JFrame
val frame: JFrame get() = frame0
fun java.awt.Component.append() {
frame.add(this, BorderLayout.NORTH);
}
fun java.awt.Component.last() {
frame.add(this);
}
internal fun init(frame: JFrame) {
this.frame0 = frame;
initializer(frame)
}
}
internal suspend fun openWindow(title: String = "", initializer: WindowInitialzier.(JFrame) -> Unit = {}): String {
return openWindow(title, WindowInitialzier(initializer))
}
internal suspend fun openWindow(title: String = "", initializer: WindowInitialzier = WindowInitialzier {}): String {
val frame = JFrame()
val value = JTextField()
val def = CompletableDeferred<String>()
value.addKeyListener(object : KeyListener {
override fun keyTyped(e: KeyEvent?) {
}
override fun keyPressed(e: KeyEvent?) {
when (e!!.keyCode) {
27, 10 -> {
def.complete(value.text)
}
}
}
override fun keyReleased(e: KeyEvent?) {
}
})
frame.layout = BorderLayout(10, 5)
frame.add(value, BorderLayout.SOUTH)
initializer.init(frame)
frame.pack()
frame.defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE
frame.addWindowListener(object : WindowAdapter() {
override fun windowClosing(e: WindowEvent?) {
def.complete(value.text)
}
})
frame.setLocationRelativeTo(null)
frame.title = title
frame.isVisible = true
val result = def.await()
frame.dispose()
return result
}
......@@ -22,19 +22,46 @@ import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import kotlinx.io.core.use
import net.mamoe.mirai.Bot
import net.mamoe.mirai.network.BotNetworkHandler
import java.awt.Desktop
import java.awt.Image
import java.awt.image.BufferedImage
import java.io.File
import java.io.RandomAccessFile
import javax.imageio.ImageIO
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
actual typealias Throws = kotlin.jvm.Throws
@MiraiExperimentalAPI
class DefaultLoginSolver(
val input: suspend () -> String,
val overrideLogger: MiraiLogger? = null
) : LoginSolver() {
private val degelate: LoginSolver
init {
if (Desktop.isDesktopSupported()) {
degelate = SwingSolver
} else {
degelate = DefaultLoginSolverImpl(input, overrideLogger)
}
}
override suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String? {
return degelate.onSolvePicCaptcha(bot, data)
}
override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? {
return degelate.onSolveSliderCaptcha(bot, url)
}
override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? {
return degelate.onSolveUnsafeDeviceLoginVerify(bot, url)
}
}
@MiraiExperimentalAPI
class DefaultLoginSolverImpl(
private val input: suspend () -> String,
private val overrideLogger: MiraiLogger? = null
) : LoginSolver() {
......@@ -106,7 +133,14 @@ actual abstract class LoginSolver {
actual companion object {
actual val Default: LoginSolver
@OptIn(MiraiExperimentalAPI::class)
get() = DefaultLoginSolver(input = { withContext(Dispatchers.IO) { readLine() } ?: error("No standard input") })
get() {
if (Desktop.isDesktopSupported()) {
return SwingSolver
}
return DefaultLoginSolverImpl(input = {
withContext(Dispatchers.IO) { readLine() } ?: error("No standard input")
})
}
}
}
......@@ -149,7 +183,8 @@ private fun BufferedImage.createCharImg(outputWidth: Int = 100, ignoreRate: Doub
return (r * 30 + g * 59 + b * 11 + 50) / 100
}
fun grayCompare(g1: Int, g2: Int): Boolean = kotlin.math.min(g1, g2).toDouble() / kotlin.math.max(g1, g2) >= ignoreRate
fun grayCompare(g1: Int, g2: Int): Boolean =
kotlin.math.min(g1, g2).toDouble() / kotlin.math.max(g1, g2) >= ignoreRate
val background = gray(image.getRGB(0, 0))
......
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.utils
import net.mamoe.mirai.Bot
import java.awt.Desktop
import java.net.URI
import javax.imageio.ImageIO
import javax.swing.ImageIcon
import javax.swing.JLabel
import javax.swing.JTextField
/**
* @author Karlatemp <karlatemp@vip.qq.com> <https://github.com/Karlatemp>
*/
@MiraiExperimentalAPI
object SwingSolver : LoginSolver() {
override suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String? {
return openWindow("Mirai PicCaptcha(${bot.id})") {
val image = ImageIO.read(data.inputStream())
JLabel(ImageIcon(image)).append()
}
}
override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? {
return openWindow("Mirai SliderCaptcha(${bot.id})") {
JLabel("需要滑动验证码, 完成后请关闭该窗口").append()
Desktop.getDesktop().browse(URI(url))
}
}
override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? {
return openWindow("Mirai UnsafeDeviceLoginVerify(${bot.id})") {
JLabel("需要进行账户安全认证").last()
JLabel("该账户有[设备锁]/[不常用登录地点]/[不常用设备登录]的问题").last()
JLabel("完成以下账号认证即可成功登录|理论本认证在mirai每个账户中最多出现1次").last()
JTextField(url).append()
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment