From 22c2d17c67bef44275d1da10aec2107553e5374a Mon Sep 17 00:00:00 2001 From: xiluo Date: Sun, 19 Feb 2023 01:32:56 +0800 Subject: [PATCH] Finish --- .run/RunMiraiKt.run.xml | 10 -- build.gradle.kts | 10 +- .../example/mirai/plugin/JavaPluginMain.java | 91 -------------- src/main/kotlin/PluginMain.kt | 118 ------------------ .../ltd/guimc/mirai/groupverify/PluginMain.kt | 44 +++++++ .../guimc/mirai/groupverify/config/Config.kt | 12 ++ .../groupverify/listener/MemberListener.kt | 69 ++++++++++ .../guimc/mirai/groupverify/utils/APIUtils.kt | 53 ++++++++ .../mirai/groupverify/utils/HashUtils.kt | 11 ++ ...t.mamoe.mirai.console.plugin.jvm.JvmPlugin | 2 +- src/test/kotlin/RunMirai.kt | 36 ------ 11 files changed, 199 insertions(+), 257 deletions(-) delete mode 100644 .run/RunMiraiKt.run.xml delete mode 100644 src/main/java/org/example/mirai/plugin/JavaPluginMain.java delete mode 100644 src/main/kotlin/PluginMain.kt create mode 100644 src/main/kotlin/ltd/guimc/mirai/groupverify/PluginMain.kt create mode 100644 src/main/kotlin/ltd/guimc/mirai/groupverify/config/Config.kt create mode 100644 src/main/kotlin/ltd/guimc/mirai/groupverify/listener/MemberListener.kt create mode 100644 src/main/kotlin/ltd/guimc/mirai/groupverify/utils/APIUtils.kt create mode 100644 src/main/kotlin/ltd/guimc/mirai/groupverify/utils/HashUtils.kt delete mode 100644 src/test/kotlin/RunMirai.kt diff --git a/.run/RunMiraiKt.run.xml b/.run/RunMiraiKt.run.xml deleted file mode 100644 index ce3fef7..0000000 --- a/.run/RunMiraiKt.run.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index c125345..7f194de 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - val kotlinVersion = "1.6.10" + val kotlinVersion = "1.6.21" kotlin("jvm") version kotlinVersion kotlin("plugin.serialization") version kotlinVersion @@ -9,9 +9,17 @@ plugins { group = "ltd.guimc.mirai-group-verify" version = "0.1.0" +dependencies { + implementation("org.json:json:20200518") +} + repositories { if (System.getenv("CI")?.toBoolean() != true) { maven("https://maven.aliyun.com/repository/public") // 阿里云国内代理仓库 } mavenCentral() } + +mirai { + jvmTarget = JavaVersion.VERSION_11 +} diff --git a/src/main/java/org/example/mirai/plugin/JavaPluginMain.java b/src/main/java/org/example/mirai/plugin/JavaPluginMain.java deleted file mode 100644 index a32d52e..0000000 --- a/src/main/java/org/example/mirai/plugin/JavaPluginMain.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.example.mirai.plugin; - -import kotlin.Lazy; -import kotlin.LazyKt; -import net.mamoe.mirai.console.permission.*; -import net.mamoe.mirai.console.plugin.jvm.JavaPlugin; -import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription; -import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescriptionBuilder; -import net.mamoe.mirai.contact.Member; -import net.mamoe.mirai.contact.User; -import net.mamoe.mirai.event.Event; -import net.mamoe.mirai.event.EventChannel; -import net.mamoe.mirai.event.GlobalEventChannel; -import net.mamoe.mirai.event.events.FriendMessageEvent; -import net.mamoe.mirai.event.events.GroupMessageEvent; - - -/** - * 使用 Java 请把 - * {@code /src/main/resources/META-INF.services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin} - * 文件内容改成 {@code org.example.mirai.plugin.JavaPluginMain}
- * 也就是当前主类全类名 - *

- * 使用 Java 可以把 kotlin 源集删除且不会对项目有影响 - *

- * 在 {@code settings.gradle.kts} 里改构建的插件名称、依赖库和插件版本 - *

- * 在该示例下的 {@link JvmPluginDescription} 修改插件名称,id 和版本等 - *

- * 可以使用 {@code src/test/kotlin/RunMirai.kt} 在 IDE 里直接调试, - * 不用复制到 mirai-console-loader 或其他启动器中调试 - */ - -public final class JavaPluginMain extends JavaPlugin { - public static final JavaPluginMain INSTANCE = new JavaPluginMain(); - - private JavaPluginMain() { - super(new JvmPluginDescriptionBuilder("org.example.mirai-example", "0.1.0") - .info("EG") - .build()); - } - - @Override - public void onEnable() { - getLogger().info("日志"); - EventChannel eventChannel = GlobalEventChannel.INSTANCE.parentScope(this); - eventChannel.subscribeAlways(GroupMessageEvent.class, g -> { - //监听群消息 - getLogger().info(g.getMessage().contentToString()); - - }); - eventChannel.subscribeAlways(FriendMessageEvent.class, f -> { - //监听好友消息 - getLogger().info(f.getMessage().contentToString()); - }); - - myCustomPermission.getValue(); // 注册权限 - } - - // region mirai-console 权限系统示例 - public static final Lazy myCustomPermission = LazyKt.lazy(() -> { // Lazy: Lazy 是必须的, console 不允许提前访问权限系统 - // 注册一条权限节点 org.example.mirai-example:my-permission - // 并以 org.example.mirai-example:* 为父节点 - - - // @param: parent: 父权限 - // 在 Console 内置权限系统中, 如果某人拥有父权限 - // 那么意味着此人也拥有该权限 (org.example.mirai-example:my-permission) - // @func: PermissionIdNamespace.permissionId: 根据插件 id 确定一条权限 id - try { - return PermissionService.getInstance().register( - INSTANCE.permissionId("my-permission"), - "一条自定义权限", - INSTANCE.getParentPermission() - ); - } catch (PermissionRegistryConflictException e) { - throw new RuntimeException(e); - } - }); - - public static boolean hasCustomPermission(User usr) { - PermitteeId pid; - if (usr instanceof Member) { - pid = new AbstractPermitteeId.ExactMember(((Member) usr).getGroup().getId(), usr.getId()); - } else { - pid = new AbstractPermitteeId.ExactUser(usr.getId()); - } - return PermissionService.hasPermission(pid, myCustomPermission.getValue()); - } - // endregion -} diff --git a/src/main/kotlin/PluginMain.kt b/src/main/kotlin/PluginMain.kt deleted file mode 100644 index c5fcbab..0000000 --- a/src/main/kotlin/PluginMain.kt +++ /dev/null @@ -1,118 +0,0 @@ -package org.example.mirai.plugin - -import net.mamoe.mirai.console.permission.AbstractPermitteeId -import net.mamoe.mirai.console.permission.PermissionService -import net.mamoe.mirai.console.permission.PermissionService.Companion.hasPermission -import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription -import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin -import net.mamoe.mirai.contact.Member -import net.mamoe.mirai.contact.User -import net.mamoe.mirai.event.GlobalEventChannel -import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent -import net.mamoe.mirai.event.events.FriendMessageEvent -import net.mamoe.mirai.event.events.GroupMessageEvent -import net.mamoe.mirai.event.events.NewFriendRequestEvent -import net.mamoe.mirai.message.data.Image -import net.mamoe.mirai.message.data.Image.Key.queryUrl -import net.mamoe.mirai.message.data.PlainText -import net.mamoe.mirai.utils.info - -/** - * 使用 kotlin 版请把 - * `src/main/resources/META-INF.services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin` - * 文件内容改成 `org.example.mirai.plugin.PluginMain` 也就是当前主类全类名 - * - * 使用 kotlin 可以把 java 源集删除不会对项目有影响 - * - * 在 `settings.gradle.kts` 里改构建的插件名称、依赖库和插件版本 - * - * 在该示例下的 [JvmPluginDescription] 修改插件名称,id和版本,etc - * - * 可以使用 `src/test/kotlin/RunMirai.kt` 在 ide 里直接调试, - * 不用复制到 mirai-console-loader 或其他启动器中调试 - */ - -object PluginMain : KotlinPlugin( - JvmPluginDescription( - id = "org.example.mirai-example", - name = "插件示例", - version = "0.1.0" - ) { - author("作者名称或联系方式") - info( - """ - 这是一个测试插件, - 在这里描述插件的功能和用法等. - """.trimIndent() - ) - // author 和 info 可以删除. - } -) { - override fun onEnable() { - logger.info { "Plugin loaded" } - //配置文件目录 "${dataFolder.absolutePath}/" - val eventChannel = GlobalEventChannel.parentScope(this) - eventChannel.subscribeAlways { - //群消息 - //复读示例 - if (message.contentToString().startsWith("复读")) { - group.sendMessage(message.contentToString().replace("复读", "")) - } - if (message.contentToString() == "hi") { - //群内发送 - group.sendMessage("hi") - //向发送者私聊发送消息 - sender.sendMessage("hi") - //不继续处理 - return@subscribeAlways - } - //分类示例 - message.forEach { - //循环每个元素在消息里 - if (it is Image) { - //如果消息这一部分是图片 - val url = it.queryUrl() - group.sendMessage("图片,下载地址$url") - } - if (it is PlainText) { - //如果消息这一部分是纯文本 - group.sendMessage("纯文本,内容:${it.content}") - } - } - } - eventChannel.subscribeAlways { - //好友信息 - sender.sendMessage("hi") - } - eventChannel.subscribeAlways { - //自动同意好友申请 - accept() - } - eventChannel.subscribeAlways { - //自动同意加群申请 - accept() - } - - myCustomPermission // 注册权限 - } - - // region console 权限系统示例 - private val myCustomPermission by lazy { // Lazy: Lazy 是必须的, console 不允许提前访问权限系统 - // 注册一条权限节点 org.example.mirai-example:my-permission - // 并以 org.example.mirai-example:* 为父节点 - - // @param: parent: 父权限 - // 在 Console 内置权限系统中, 如果某人拥有父权限 - // 那么意味着此人也拥有该权限 (org.example.mirai-example:my-permission) - // @func: PermissionIdNamespace.permissionId: 根据插件 id 确定一条权限 id - PermissionService.INSTANCE.register(permissionId("my-permission"), "一条自定义权限", parentPermission) - } - - public fun hasCustomPermission(sender: User): Boolean { - return when (sender) { - is Member -> AbstractPermitteeId.ExactMember(sender.group.id, sender.id) - else -> AbstractPermitteeId.ExactUser(sender.id) - }.hasPermission(myCustomPermission) - } - // endregion -} diff --git a/src/main/kotlin/ltd/guimc/mirai/groupverify/PluginMain.kt b/src/main/kotlin/ltd/guimc/mirai/groupverify/PluginMain.kt new file mode 100644 index 0000000..b5a27b3 --- /dev/null +++ b/src/main/kotlin/ltd/guimc/mirai/groupverify/PluginMain.kt @@ -0,0 +1,44 @@ +package ltd.guimc.mirai.groupverify + +import ltd.guimc.mirai.groupverify.listener.MemberListener +import net.mamoe.mirai.console.permission.Permission +import net.mamoe.mirai.console.permission.PermissionId +import net.mamoe.mirai.console.permission.PermissionService +import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription +import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin +import net.mamoe.mirai.event.events.MemberJoinEvent +import net.mamoe.mirai.event.globalEventChannel + +object PluginMain : KotlinPlugin( + JvmPluginDescription( + id = "ltd.guimc.mirai.groupverify", + name = "Mirai Group Verify", + version = "0.1.0" + ) { + author("BakaBotTeam") + } +) { + lateinit var rootPerm: Permission + lateinit var enablePerm: Permission + + override fun onEnable() { + logger.info("Mirai Group Verify 正在加载的路上了喵~") + registerPerms() + registerEvents() + logger.info("Mirai Group Verify 加载好啦喵~") + } + + override fun onDisable() { + logger.info("Mirai Group Verify 正在关闭呢...") + logger.info("Mirai Group Verify 已关闭了喵") + } + + private fun registerPerms() = PermissionService.INSTANCE.run { + rootPerm = register(PermissionId("ltd.guimc.mirai.groupverify", "*"), "Root Permission") + enablePerm = register(PermissionId("ltd.guimc.mirai.groupverify", "enable"), "启用插件 (群)") + } + + private fun registerEvents() = this.globalEventChannel().run { + subscribeAlways { event -> MemberListener.onEvent(event) } + } +} diff --git a/src/main/kotlin/ltd/guimc/mirai/groupverify/config/Config.kt b/src/main/kotlin/ltd/guimc/mirai/groupverify/config/Config.kt new file mode 100644 index 0000000..a7b99ba --- /dev/null +++ b/src/main/kotlin/ltd/guimc/mirai/groupverify/config/Config.kt @@ -0,0 +1,12 @@ +package ltd.guimc.mirai.groupverify.config + +import net.mamoe.mirai.console.data.AutoSavePluginConfig +import net.mamoe.mirai.console.data.value + +object Config : AutoSavePluginConfig("config") { + var backendUrl by value("http://example.com:5566/verify") + + var secret by value("xxx") + + var appid by value("xxx_xxx_xxxxxxxxxxxx") +} \ No newline at end of file diff --git a/src/main/kotlin/ltd/guimc/mirai/groupverify/listener/MemberListener.kt b/src/main/kotlin/ltd/guimc/mirai/groupverify/listener/MemberListener.kt new file mode 100644 index 0000000..8473ba8 --- /dev/null +++ b/src/main/kotlin/ltd/guimc/mirai/groupverify/listener/MemberListener.kt @@ -0,0 +1,69 @@ +package ltd.guimc.mirai.groupverify.listener + +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import ltd.guimc.mirai.groupverify.PluginMain +import ltd.guimc.mirai.groupverify.config.Config +import ltd.guimc.mirai.groupverify.utils.APIUtils +import net.mamoe.mirai.console.permission.PermissionService.Companion.hasPermission +import net.mamoe.mirai.console.permission.PermitteeId.Companion.permitteeId +import net.mamoe.mirai.contact.Member +import net.mamoe.mirai.contact.MemberPermission +import net.mamoe.mirai.contact.NormalMember +import net.mamoe.mirai.contact.checkBotPermission +import net.mamoe.mirai.event.events.MemberJoinEvent +import net.mamoe.mirai.message.data.At +import net.mamoe.mirai.message.data.PlainText +import java.util.* + +object MemberListener { + suspend fun onEvent(event: MemberJoinEvent) { + if (event.group.permitteeId.hasPermission(PluginMain.enablePerm)) { + event.group.checkBotPermission(MemberPermission.ADMINISTRATOR) { "权限不足" } + event.member.mute(2592000) // 30 Days + + val session = APIUtils.newSession(event.member) + event.group.sendMessage( + At(event.member)+ + PlainText(" 你好呀! 进入本群,你需要先完成以下的人机验证!\n" + + "请点击下面的链接来开始验证\n\n" + + "${Config.backendUrl}?session=$session") + ) + statusListenerRegister(event.member, session) + } + } + + @OptIn(DelicateCoroutinesApi::class) + private fun statusListenerRegister(member: Member, session: String) { + Timer().schedule( + object : TimerTask() { + override fun run() { + GlobalScope.launch { + if (statusTimerTask(member, session)) cancel() + } + } + }, 2, 2 + ) + } + + private suspend fun statusTimerTask(member: Member, session: String): Boolean { + val status = APIUtils.getStatus(session) + if (status == 1) { + member.group.sendMessage( + At(member)+ + PlainText(" 你已经完成了验证 现在可以正常发言了!") + ) + (member as NormalMember).unmute() + return true + } else if (status == 2) { + member.group.sendMessage( + At(member)+ + PlainText(" 你的验证超时 请重新进群") + ) + (member as NormalMember).kick("人机验证超时") + return true + } + return false + } +} \ No newline at end of file diff --git a/src/main/kotlin/ltd/guimc/mirai/groupverify/utils/APIUtils.kt b/src/main/kotlin/ltd/guimc/mirai/groupverify/utils/APIUtils.kt new file mode 100644 index 0000000..21f71db --- /dev/null +++ b/src/main/kotlin/ltd/guimc/mirai/groupverify/utils/APIUtils.kt @@ -0,0 +1,53 @@ +package ltd.guimc.mirai.groupverify.utils + +import ltd.guimc.mirai.groupverify.config.Config +import ltd.guimc.mirai.groupverify.utils.HashUtils.sha256 +import net.mamoe.mirai.contact.Member +import org.json.JSONObject +import java.net.URI +import java.net.http.HttpClient +import java.net.http.HttpRequest +import java.net.http.HttpResponse + +object APIUtils { + val httpclient = HttpClient.newBuilder().build(); + + fun newSession(member: Member): String { + val time = System.currentTimeMillis() + val url = "${Config.backendUrl}?action=new&appid=${Config.appid}&qqid=${member.id}&group=${member.group.id}&time=${time}&sign=${sign(member, time)}" + return JSONObject(get(url)).getString("session")!! + } + + fun getStatus(session: String): Int { + val url = "${Config.backendUrl}?action=status&session=$session" + val success = JSONObject(get(url)).getBoolean("success") + val timedout = JSONObject(get(url)).getBoolean("timeout") + + return if (success) { + Status.FINISHED + } else if (timedout) { + Status.TIMEDOUT + } else { + Status.INPROGRESS + } + } + + fun get(url: String): String { + val request = HttpRequest.newBuilder() + .uri(URI.create(url)) + .build(); + + val response = httpclient.send(request, HttpResponse.BodyHandlers.ofString()); + return response.body()!! + } + + object Status { + const val INPROGRESS = 0 + const val FINISHED = 1 + const val TIMEDOUT = 2 + } + + private fun sign(member: Member, time: Long): String = "${Config.appid}:$secret:${member.group.id}:${member.id}:$time".sha256() + private val secret: String + get() = "${Config.appid}:${Config.secret}".sha256() +} \ No newline at end of file diff --git a/src/main/kotlin/ltd/guimc/mirai/groupverify/utils/HashUtils.kt b/src/main/kotlin/ltd/guimc/mirai/groupverify/utils/HashUtils.kt new file mode 100644 index 0000000..cb3603f --- /dev/null +++ b/src/main/kotlin/ltd/guimc/mirai/groupverify/utils/HashUtils.kt @@ -0,0 +1,11 @@ +package ltd.guimc.mirai.groupverify.utils + +import java.math.BigInteger +import java.security.MessageDigest + +object HashUtils { + fun String.sha256(): String { + val md = MessageDigest.getInstance("SHA-256") + return BigInteger(1, md.digest(toByteArray())).toString(16).padStart(32, '0') + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin b/src/main/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin index 0bed70b..847e297 100644 --- a/src/main/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin +++ b/src/main/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin @@ -1 +1 @@ -org.example.mirai.plugin.PluginMain \ No newline at end of file +ltd.guimc.mirai.groupverify.PluginMain \ No newline at end of file diff --git a/src/test/kotlin/RunMirai.kt b/src/test/kotlin/RunMirai.kt deleted file mode 100644 index b4837db..0000000 --- a/src/test/kotlin/RunMirai.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.example.mirai.plugin - -import net.mamoe.mirai.alsoLogin -import net.mamoe.mirai.console.MiraiConsole -import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.enable -import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.load -import net.mamoe.mirai.console.terminal.MiraiConsoleTerminalLoader - -suspend fun main() { - if (true) { - - error(""" - DEPRECATED: - 此启动方法已经被弃用, 请使用 ./gradlew runConsole 启动测试环境 - - 详见: - https://docs.mirai.mamoe.net/console/plugin/JVMPlugin.html#%E8%B0%83%E8%AF%95 - https://github.com/mamoe/mirai/blob/dev/mirai-console/docs/plugin/JVMPlugin.md#%E8%B0%83%E8%AF%95 - """.trimIndent()) - } - - MiraiConsoleTerminalLoader.startAsDaemon() - - //如果是Kotlin - PluginMain.load() - PluginMain.enable() - //如果是Java -// JavaPluginMain.INSTANCE.load() -// JavaPluginMain.INSTANCE.enable() - - val bot = MiraiConsole.addBot(123456, "") { - fileBasedDeviceInfo() - }.alsoLogin() - - MiraiConsole.job.join() -} \ No newline at end of file