From 7ca62bb0c89a38db186a05e83a1904b6d30f04e3 Mon Sep 17 00:00:00 2001 From: Him188moe Date: Mon, 2 Sep 2019 22:33:23 +0800 Subject: [PATCH 01/19] Updated verification code processing --- .../main/java/net/mamoe/mirai/MiraiMain.java | 18 +-- .../java/net/mamoe/mirai/MiraiServer.java | 70 ++------- .../src/main/java/net/mamoe/mirai/Robot.java | 17 ++- .../java/net/mamoe/mirai/contact/Contact.kt | 2 +- .../java/net/mamoe/mirai/contact/Group.kt | 86 ++++++----- .../main/java/net/mamoe/mirai/contact/Lazy.kt | 17 --- .../main/java/net/mamoe/mirai/contact/QQ.kt | 5 +- .../net/mamoe/mirai/message/defaults/At.java | 6 +- .../mirai/network/RobotNetworkHandler.kt | 117 ++++++++------- .../mamoe/mirai/network/packet/AccountInfo.kt | 2 +- .../mirai/network/packet/ClientPacket.kt | 31 +++- .../mamoe/mirai/network/packet/Heartbeat.kt | 2 +- .../mirai/network/packet/MessageEvent.kt | 2 +- .../net/mamoe/mirai/network/packet/SKey.kt | 4 +- .../mamoe/mirai/network/packet/ServerEvent.kt | 20 ++- .../mirai/network/packet/ServerPacket.kt | 10 +- .../net/mamoe/mirai/network/packet/Session.kt | 2 +- .../net/mamoe/mirai/network/packet/Touch.kt | 4 +- .../mirai/network/packet/VerificationCode.kt | 98 +++++++++++++ .../network/packet/login/ClientLoginPacket.kt | 15 +- .../packet/login/ClientLoginStatusPacket.kt | 2 +- .../ClientLoginVerificationCodePacket.kt | 41 ------ ...oginResponseVerificationCodeInitPacket.kt} | 13 +- .../message/ClientSendFriendMessagePacket.kt | 10 +- .../message/ClientSendGroupMessagePacket.kt | 6 +- .../ServerVerificationCodePacket.kt | 44 ------ .../net/mamoe/mirai/utils/ContactList.java | 2 +- .../main/java/net/mamoe/mirai/utils/Utils.kt | 2 + .../utils/config/MiraiConfigSection.java | 4 +- mirai-core/src/test/java/HexComparator.java | 133 +++++++++++++----- mirai-core/src/test/java/TestKt.kt | 8 ++ 31 files changed, 435 insertions(+), 358 deletions(-) delete mode 100644 mirai-core/src/main/java/net/mamoe/mirai/contact/Lazy.kt create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt delete mode 100644 mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginVerificationCodePacket.kt rename mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/{ServerLoginResponseVerificationCodePacket.kt => ServerLoginResponseVerificationCodeInitPacket.kt} (61%) delete mode 100644 mirai-core/src/main/java/net/mamoe/mirai/network/packet/verification/ServerVerificationCodePacket.kt create mode 100644 mirai-core/src/test/java/TestKt.kt diff --git a/mirai-core/src/main/java/net/mamoe/mirai/MiraiMain.java b/mirai-core/src/main/java/net/mamoe/mirai/MiraiMain.java index 77c77cbfd..d959f504a 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/MiraiMain.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/MiraiMain.java @@ -1,28 +1,14 @@ package net.mamoe.mirai; -import net.mamoe.mirai.utils.config.MiraiConfig; -import net.mamoe.mirai.utils.config.MiraiConfigSection; - /** * @author Him188moe */ public final class MiraiMain { private static MiraiServer server; + public static void main(String[] args) { server = new MiraiServer(); - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - server.shutdown(); - })); - MiraiConfig config = new MiraiConfig("QQ.yml"); - MiraiConfigSection data = config.getSection("123123"); - data.put("account","123123a"); - try { - Robot robot = new Robot(data); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - - + Runtime.getRuntime().addShutdownHook(new Thread(() -> server.shutdown())); } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java index 6ba54eb76..a768ff60f 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java @@ -5,7 +5,6 @@ import net.mamoe.mirai.event.MiraiEventManager; import net.mamoe.mirai.event.events.server.ServerDisableEvent; import net.mamoe.mirai.event.events.server.ServerEnableEvent; import net.mamoe.mirai.network.RobotNetworkHandler; -import net.mamoe.mirai.network.packet.ClientTouchPacket; import net.mamoe.mirai.task.MiraiTaskManager; import net.mamoe.mirai.utils.LoggerTextFormat; import net.mamoe.mirai.utils.MiraiLogger; @@ -17,7 +16,6 @@ import net.mamoe.mirai.utils.setting.MiraiSettingMapSection; import java.io.File; import java.io.IOException; -import java.util.LinkedList; import java.util.Scanner; public class MiraiServer { @@ -119,62 +117,20 @@ public class MiraiServer { getLogger().info("ready to connect"); - /* - MiraiConfigSection section = new MiraiConfigSection>(){{ - put("1",new MiraiConfigSection<>(){{ - put("1","0"); - }}); - }}; + this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> { + try { + Robot robot = new Robot(section); + RobotNetworkHandler robotNetworkHandler = robot.getHandler(); + robotNetworkHandler.setServerIP("14.116.136.106"); + robotNetworkHandler.touch$mirai_core(); - this.qqs.put("test",section); - this.qqs.save(); - */ - - - MiraiConfigSection x = this.qqs.getTypedSection("test"); - //System.out.println(x.getSection("1").getInt("1")); - - /* - System.out.println(v); - - System.out.println(v.get("1111")); - */ - - - Robot robot = new Robot(1994701021, "xiaoqqq", new LinkedList<>()); - RobotNetworkHandler robotNetworkHandler = robot.getHandler(); - try { - //System.out.println(Protocol.Companion.getSERVER_IP().get(3)); - //System.out.println(Protocol.Companion.getSERVER_IP().toString()); - - robotNetworkHandler.setServerIP("14.116.136.106"); - robotNetworkHandler.sendPacket(new ClientTouchPacket(1994701021, "14.116.136.106")); - while (true) ; - //robotNetworkHandler.connect("14.116.136.106"); - //robotNetworkHandler.connect(Protocol.Companion.getSERVER_IP().get(2)); - //robotNetworkHandler.connect("125.39.132.242"); - } catch (Exception e) { - e.printStackTrace(); - System.exit(1); - } -/* - System.out.println("network test"); - try { - - - MiraiUDPServer server = new MiraiUDPServer(); - MiraiUDPClient client = new MiraiUDPClient(InetAddress.getLocalHost(),9999,MiraiNetwork.getAvailablePort()); - this.getTaskManager().repeatingTask(() -> { - byte[] sendInfo = "test test".getBytes(StandardCharsets.UTF_8); - try { - client.send(new DatagramPacket(sendInfo,sendInfo.length)); - } catch (IOException e) { - e.printStackTrace(); - } - },300); - } catch (IOException e) { - e.printStackTrace(); - }*/ + Robot.instances.add(robot); + } catch (Throwable e) { + e.printStackTrace(); + getLogger().error("Could not load QQ robots config!"); + System.exit(1); + } + }); } private void initSetting(File setting) { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java index fa6d90e37..20b6c922a 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java @@ -9,11 +9,13 @@ import net.mamoe.mirai.utils.config.MiraiConfigSection; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedList; import java.util.List; public class Robot { + public static final List instances = Collections.synchronizedList(new LinkedList<>()); - private final int qqNumber; + private final long qqNumber; private final String password; @Getter private final RobotNetworkHandler handler; @@ -31,38 +33,41 @@ public class Robot { return owners.contains(ownerName); } + public long getQQNumber() { + return qqNumber; + } public Robot(MiraiConfigSection data) throws Throwable { this( - data.getIntOrThrow("account", () -> new IllegalArgumentException("account")), + data.getLongOrThrow("account", () -> new IllegalArgumentException("account")), data.getStringOrThrow("password", () -> new IllegalArgumentException("password")), data.getAsOrDefault("owners", ArrayList::new) ); } - public Robot(int qqNumber, String password, List owners) { + public Robot(long qqNumber, String password, List owners) { this.qqNumber = qqNumber; this.password = password; this.owners = Collections.unmodifiableList(owners); this.handler = new RobotNetworkHandler(this, this.qqNumber, this.password); } - public QQ getQQ(int qqNumber) { + public QQ getQQ(long qqNumber) { if (!this.qqs.containsKey(qqNumber)) { this.qqs.put(qqNumber, new QQ(qqNumber)); } return this.qqs.get(qqNumber); } - public Group getGroup(int groupNumber) { + public Group getGroup(long groupNumber) { if (!this.groups.containsKey(groupNumber)) { this.groups.put(groupNumber, new Group(groupNumber)); } return groups.get(groupNumber); } - public Group getGroupByGroupId(int groupId) { + public Group getGroupByGroupId(long groupId) { return getGroup(Group.Companion.groupIdToNumber(groupId)); } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt index 844c5c050..fa1a475c1 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt @@ -8,7 +8,7 @@ import net.mamoe.mirai.message.defaults.PlainText * * @author Him188moe */ -abstract class Contact(val number: Int) { +abstract class Contact(val number: Long) { /** * Async diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt index 835a1b0a2..2d8677058 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt @@ -3,14 +3,10 @@ package net.mamoe.mirai.contact import net.mamoe.mirai.message.Message import net.mamoe.mirai.utils.ContactList -class Group(number: Int) : Contact(number) { +class Group(number: Long) : Contact(number) { val groupId = groupNumberToId(number) val members = ContactList() - init { - Instances.groups.add(this) - } - override fun sendMessage(message: Message) { } @@ -20,38 +16,38 @@ class Group(number: Int) : Contact(number) { } companion object { - fun groupNumberToId(number: Int): Int { - val left: Int = number.toString().let { + fun groupNumberToId(number: Long): Long { + val left: Long = number.toString().let { if (it.length < 6) { return@groupNumberToId number } - it.substring(0, it.length - 6).toInt() + it.substring(0, it.length - 6).toLong() } - val right: Int = number.toString().let { - it.substring(it.length - 6).toInt() + val right: Long = number.toString().let { + it.substring(it.length - 6).toLong() } return when (left) { in 1..10 -> { - ((left + 202).toString() + right.toString()).toInt() + ((left + 202).toString() + right.toString()).toLong() } in 11..19 -> { - ((left + 469).toString() + right.toString()).toInt() + ((left + 469).toString() + right.toString()).toLong() } in 20..66 -> { - ((left + 208).toString() + right.toString()).toInt() + ((left + 208).toString() + right.toString()).toLong() } in 67..156 -> { - ((left + 1943).toString() + right.toString()).toInt() + ((left + 1943).toString() + right.toString()).toLong() } in 157..209 -> { - ((left + 199).toString() + right.toString()).toInt() + ((left + 199).toString() + right.toString()).toLong() } in 210..309 -> { - ((left + 389).toString() + right.toString()).toInt() + ((left + 389).toString() + right.toString()).toLong() } in 310..499 -> { - ((left + 349).toString() + right.toString()).toInt() + ((left + 349).toString() + right.toString()).toLong() } else -> number } @@ -62,60 +58,60 @@ class Group(number: Int) : Contact(number) { groupNumberToId(580266363) } - fun groupIdToNumber(id: Int): Int { - var left: Int = id.toString().let { + fun groupIdToNumber(id: Long): Long { + var left: Long = id.toString().let { if (it.length < 6) { return@groupIdToNumber id } - it.substring(0 until it.length - 6).toInt() + it.substring(0 until it.length - 6).toLong() } return when (left) { in 203..212 -> { - val right: Int = id.toString().let { - it.substring(it.length - 6).toInt() + val right: Long = id.toString().let { + it.substring(it.length - 6).toLong() } - ((left - 202).toString() + right.toString()).toInt() + ((left - 202).toString() + right.toString()).toLong() } in 480..488 -> { - val right: Int = id.toString().let { - it.substring(it.length - 6).toInt() + val right: Long = id.toString().let { + it.substring(it.length - 6).toLong() } - ((left - 469).toString() + right.toString()).toInt() + ((left - 469).toString() + right.toString()).toLong() } in 2100..2146 -> { - val right: Int = id.toString().let { - it.substring(it.length - 7).toInt() + val right: Long = id.toString().let { + it.substring(it.length - 7).toLong() } - left = left.toString().substring(0 until 3).toInt() - ((left - 208).toString() + right.toString()).toInt() + left = left.toString().substring(0 until 3).toLong() + ((left - 208).toString() + right.toString()).toLong() } in 2010..2099 -> { - val right: Int = id.toString().let { - it.substring(it.length - 6).toInt() + val right: Long = id.toString().let { + it.substring(it.length - 6).toLong() } - ((left - 1943).toString() + right.toString()).toInt() + ((left - 1943).toString() + right.toString()).toLong() } in 2147..2199 -> { - val right: Int = id.toString().let { - it.substring(it.length - 7).toInt() + val right: Long = id.toString().let { + it.substring(it.length - 7).toLong() } - left = left.toString().substring(0 until 3).toInt() - ((left - 199).toString() + right.toString()).toInt() + left = left.toString().substring(0 until 3).toLong() + ((left - 199).toString() + right.toString()).toLong() } in 4100..4199 -> { - val right: Int = id.toString().let { - it.substring(it.length - 7).toInt() + val right: Long = id.toString().let { + it.substring(it.length - 7).toLong() } - left = left.toString().substring(0 until 3).toInt() - ((left - 389).toString() + right.toString()).toInt() + left = left.toString().substring(0 until 3).toLong() + ((left - 389).toString() + right.toString()).toLong() } in 3800..3989 -> { - val right: Int = id.toString().let { - it.substring(it.length - 7).toInt() + val right: Long = id.toString().let { + it.substring(it.length - 7).toLong() } - left = left.toString().substring(0 until 3).toInt() - ((left - 349).toString() + right.toString()).toInt() + left = left.toString().substring(0 until 3).toLong() + ((left - 349).toString() + right.toString()).toLong() } else -> id } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Lazy.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Lazy.kt deleted file mode 100644 index cecd6001c..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Lazy.kt +++ /dev/null @@ -1,17 +0,0 @@ -package net.mamoe.mirai.contact - - -fun Int.asQQ(): QQ = Instances.qqs.stream().filter { t: QQ? -> t?.number?.equals(this)!! }.findAny().orElse(QQ(this))!! - -fun Int.asGroup(): Group = Instances.groups.stream().filter { t: Group? -> t?.number?.equals(this)!! }.findAny().orElse(Group(this))!! - -fun String.withImage(id: String, type: String) = "{$id}.$type" - -fun String.withAt(qq: Int) = qq.asQQ().at() - -fun String.withAt(qq: QQ) = qq.at() - -object Instances { - var qqs = arrayListOf() - var groups = arrayListOf() -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt index 5638a2de2..e7a0cf537 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt @@ -6,10 +6,7 @@ import net.mamoe.mirai.message.defaults.At /** * @author Him188moe */ -class QQ(number: Int) : Contact(number) { - init { - Instances.qqs.add(this) - } +class QQ(number: Long) : Contact(number) { override fun sendMessage(message: Message) { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java index 088a98a30..003d40850 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java @@ -10,17 +10,17 @@ import java.util.Objects; * @author Him188moe */ public final class At extends Message { - private final int target; + private final long target; public At(@NotNull QQ target) { this(Objects.requireNonNull(target).getNumber()); } - public At(int target) { + public At(long target) { this.target = target; } - public int getTarget() { + public long getTarget() { return target; } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index 7d28047fc..0db821a4f 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -1,6 +1,5 @@ package net.mamoe.mirai.network -import net.mamoe.mirai.MiraiServer import net.mamoe.mirai.Robot import net.mamoe.mirai.contact.Group import net.mamoe.mirai.event.events.qq.FriendMessageEvent @@ -10,12 +9,8 @@ import net.mamoe.mirai.network.packet.login.* import net.mamoe.mirai.network.packet.message.ClientSendGroupMessagePacket import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket -import net.mamoe.mirai.network.packet.verification.ServerVerificationCodePacket -import net.mamoe.mirai.network.packet.verification.ServerVerificationCodePacketEncrypted import net.mamoe.mirai.task.MiraiThreadPool import net.mamoe.mirai.utils.* -import java.io.ByteArrayInputStream -import java.io.FileOutputStream import java.net.DatagramPacket import java.net.DatagramSocket import java.net.InetSocketAddress @@ -28,9 +23,7 @@ import java.util.concurrent.TimeUnit * @author Him188moe */ @ExperimentalUnsignedTypes -class RobotNetworkHandler(val robot: Robot, val number: Int, private val password: String) { - - private var sequence: Int = 0 +class RobotNetworkHandler(val robot: Robot, val number: Long, private val password: String) { var socket: DatagramSocket = DatagramSocket((15314 + Math.random() * 100).toInt()) @@ -39,33 +32,7 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor serverAddress = InetSocketAddress(value, 8000) field = value - socket.close() - socket = DatagramSocket((15314 + Math.random() * 100).toInt()) - socket.connect(this.serverAddress) - val zeroByte: Byte = 0 - Thread { - while (true) { - val dp1 = DatagramPacket(ByteArray(2048), 2048) - try { - socket.receive(dp1) - } catch (e: Exception) { - if (e.message == "socket closed") { - return@Thread - } - } - MiraiThreadPool.getInstance().submit { - var i = dp1.data.size - 1; - while (dp1.data[i] == zeroByte) { - --i - } - try { - onPacketReceived(ServerPacket.ofByteArray(dp1.data.copyOfRange(0, i + 1))) - } catch (e: Exception) { - e.printStackTrace() - } - } - } - }.start() + restartSocket() } private lateinit var serverAddress: InetSocketAddress @@ -78,6 +45,10 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor private var tlv0105: ByteArray private lateinit var _0828_rec_decr_key: ByteArray + private var verificationCodeSequence: Int = 0//这两个验证码使用 + private var verificationCodeCache: ByteArray? = null//每次包只发一部分验证码来 + private var verificationCodeCacheCount: Int = 0// + private lateinit var verificationToken: ByteArray private lateinit var sessionKey: ByteArray//这两个是登录成功后得到的 private lateinit var sKey: String @@ -104,6 +75,40 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor private var md5_32: ByteArray = getRandomKey(32) + internal fun touch() { + this.sendPacket(ClientTouchPacket(this.number, this.serverIP)) + } + + private fun restartSocket() { + socket.close() + socket = DatagramSocket((15314 + Math.random() * 100).toInt()) + socket.connect(this.serverAddress) + val zeroByte: Byte = 0 + Thread { + while (true) { + val dp1 = DatagramPacket(ByteArray(2048), 2048) + try { + socket.receive(dp1) + } catch (e: Exception) { + if (e.message == "socket closed") { + return@Thread + } + } + MiraiThreadPool.getInstance().submit { + var i = dp1.data.size - 1; + while (dp1.data[i] == zeroByte) { + --i + } + try { + onPacketReceived(ServerPacket.ofByteArray(dp1.data.copyOfRange(0, i + 1))) + } catch (e: Exception) { + e.printStackTrace() + } + } + } + }.start() + } + @ExperimentalUnsignedTypes internal fun onPacketReceived(packet: ServerPacket) { packet.decode() @@ -131,22 +136,44 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor return } - is ServerLoginResponseVerificationCodePacket -> { + is ServerLoginResponseVerificationCodeInitPacket -> { //[token00BA]来源之一: 验证码 this.token00BA = packet.token00BA + this.verificationCodeCache = packet.verifyCodePart1 - with(MiraiServer.getInstance().parentFolder + "verifyCode.png") { - ByteArrayInputStream(packet.verifyCode).transferTo(FileOutputStream(this)) - println("验证码已写入到 " + this.path) - } if (packet.unknownBoolean != null && packet.unknownBoolean!!) { - this.sequence = 1 - sendPacket(ClientLoginVerificationCodePacket(this.number, this.token0825, this.sequence, this.token00BA)) + this.verificationCodeSequence = 1 + sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, this.number, this.token0825, this.verificationCodeSequence, this.token00BA)) } } + is ServerVerificationCodeRepeatPacket -> {//todo 这个名字正确么 + this.tgtgtKey = packet.tgtgtKeyUpdate + this.token00BA = packet.token00BA + sendPacket(ClientLoginResendPacket3105(this.number, this.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA)) + } + + is ServerVerificationCodeTransmissionPacket -> { + this.verificationCodeSequence = 0 + this.verificationCodeCache = this.verificationCodeCache!! + packet.verificationCodePart2 + + this.verificationToken = packet.verificationToken + this.verificationCodeCacheCount = packet.count + + this.token00BA = packet.token00BA + this.verificationCodeCache + + + if (packet.transmissionCompleted) { + this.verificationCodeCache + TODO("验证码好了") + } else { + sendPacket(ClientVerificationCodeTransmissionRequestPacket(packet.count, this.number, this.token0825, this.verificationCodeSequence, this.token00BA)) + } + } + is ServerLoginResponseSuccessPacket -> { this._0828_rec_decr_key = packet._0828_rec_decr_key sendPacket(ClientSessionRequestPacket(this.number, this.serverIP, this.loginIP, this.md5_32, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105)) @@ -190,10 +217,6 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor } } - is ServerVerificationCodePacket -> { - this.sequence++ - - } is ServerSessionKeyResponsePacket -> { this.sessionKey = packet.sessionKey @@ -267,7 +290,7 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor is ServerMessageEventPacketRaw -> onPacketReceived(packet.analyze()) - is ServerVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt(this.token00BA)) + is ServerVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt()) is ServerLoginResponseVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt()) is ServerLoginResponseResendPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) is ServerLoginResponseSuccessPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt index 85ffc41dc..90d50c89e 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt @@ -12,7 +12,7 @@ import java.io.DataInputStream @ExperimentalUnsignedTypes @PacketId("00 5C") class ClientAccountInfoRequestPacket( - private val qq: Int, + private val qq: Long, private val sessionKey: ByteArray ) : ClientPacket() { override fun encode() { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt index 29682026d..6c18807e8 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt @@ -119,13 +119,18 @@ fun DataOutputStream.encryptAndWrite(key: ByteArray, encoder: (ByteArrayDataOutp this.write(TEACryptor.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() }, key)) } +@ExperimentalUnsignedTypes +fun DataOutputStream.encryptAndWrite(keyHex: String, encoder: (ByteArrayDataOutputStream) -> Unit) { + this.encryptAndWrite(keyHex.hexToBytes(), encoder) +} + fun DataOutputStream.encryptAndWrite(cryptor: TEACryptor, encoder: (ByteArrayDataOutputStream) -> Unit) { this.write(cryptor.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() })) } @ExperimentalUnsignedTypes @Throws(IOException::class) -fun DataOutputStream.writeTLV0006(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray) { +fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray) { ByteArrayDataOutputStream().let { it.writeHex("12 12 12 12")//it.writeRandom(4) todo it.writeHex("00 02") @@ -134,7 +139,7 @@ fun DataOutputStream.writeTLV0006(qq: Int, password: String, loginTime: Int, log it.writeHex("00 00 01") val md5_1 = md5(password); - val md5_2 = md5(md5_1 + "00 00 00 00".hexToBytes() + qq.toByteArray()) + val md5_2 = md5(md5_1 + "00 00 00 00".hexToBytes() + qq.toUInt().toByteArray()) println(md5_1.toUByteArray().toUHexString()) println(md5_2.toUByteArray().toUHexString()) it.write(md5_1) @@ -193,6 +198,17 @@ fun Int.toByteArray(): ByteArray = byteArrayOf( (this.ushr(0) and 0xFF).toByte() ) +/** + * 255u -> 00 00 00 FF + */ +@ExperimentalUnsignedTypes +fun UInt.toByteArray(): ByteArray = byteArrayOf( + (this.shr(24) and 255u).toByte(), + (this.shr(16) and 255u).toByte(), + (this.shr(8) and 255u).toByte(), + (this.shr(0) and 255u).toByte() +) + /** * 255 -> FF 00 00 00 */ @@ -225,7 +241,14 @@ fun DataOutputStream.writeRandom(length: Int) { } } +@ExperimentalUnsignedTypes @Throws(IOException::class) -fun DataOutputStream.writeQQ(qq: Int) { - this.writeInt(qq) +fun DataOutputStream.writeQQ(qq: Long) { + this.write(qq.toUInt().toByteArray()) +} + +@ExperimentalUnsignedTypes +@Throws(IOException::class) +fun DataOutputStream.writeGroup(groupIdOrGroupNumber: Long) { + this.write(groupIdOrGroupNumber.toUInt().toByteArray()) } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt index 8a40a441d..d8b1b8040 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt @@ -10,7 +10,7 @@ import java.io.IOException @ExperimentalUnsignedTypes @PacketId("00 58") class ClientHeartbeatPacket( - private val qq: Int, + private val qq: Long, private val sessionKey: ByteArray ) : ClientPacket() { @Throws(IOException::class) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt index 2657662ee..001cf7571 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt @@ -12,7 +12,7 @@ import java.io.DataInputStream @PacketId("")//随后写入 @ExperimentalUnsignedTypes class ClientMessageResponsePacket( - private val qq: Int, + private val qq: Long, private val packetIdFromServer: ByteArray, private val sessionKey: ByteArray, private val eventIdentity: ByteArray diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt index c5a1d4905..76b181fca 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt @@ -11,7 +11,7 @@ import java.io.DataInputStream @ExperimentalUnsignedTypes @PacketId("00 1D") class ClientSKeyRequestPacket( - private val qq: Int, + private val qq: Long, private val sessionKey: ByteArray ) : ClientPacket() { override fun encode() { @@ -31,7 +31,7 @@ class ClientSKeyRequestPacket( @PacketId("00 1D") @ExperimentalUnsignedTypes class ClientSKeyRefreshmentRequestPacket( - private val qq: Int, + private val qq: Long, private val sessionKey: ByteArray ) : ClientPacket() { override fun encode() { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt index 8d73cc493..02fcfc719 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt @@ -39,8 +39,8 @@ class ServerGroupUploadFileEventPacket(input: DataInputStream, packetId: ByteArr } class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) { - var groupNumber: Int = 0 - var qq: Int = 0 + var groupNumber: Long = 0 + var qq: Long = 0 lateinit var message: String lateinit var messageType: MessageType @@ -58,9 +58,10 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray, OTHER, } + @ExperimentalUnsignedTypes override fun decode() { - groupNumber = this.input.goto(51).readInt() - qq = this.input.goto(56).readInt() + groupNumber = this.input.goto(51).readInt().toLong() + qq = this.input.goto(56).readLong().toUInt().toLong() val fontLength = this.input.goto(108).readShort() //println(this.input.goto(110 + fontLength).readNBytesAt(2).toUHexString())//always 00 00 @@ -142,7 +143,7 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray, } class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) { - var qq: Int = 0 + var qq: Long = 0 lateinit var message: MessageChain @@ -153,7 +154,7 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray println(input.readAllBytes().toUHexString()) input.goto(0) - qq = input.readIntAt(0) + qq = input.readIntAt(0).toLong() val msgLength = input.readShortAt(22) val fontLength = input.readShortAt(93 + msgLength) val offset = msgLength + fontLength @@ -164,6 +165,11 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray } } +/* +3E 03 3F A2 76 E4 B8 DD 00 09 7C 3F 64 5C 2A 60 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E4 5D 6B A8 F6 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A8 F6 08 7E 90 CE 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 +3E 03 3F A2 76 E4 B8 DD 00 03 5F 85 64 5C 2A A4 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E5 5D 6B A9 16 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A9 17 1B B3 4D D7 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 + + */ /* @@ -171,7 +177,7 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray backup class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) { - var qq: Int = 0 + var qq: Long = 0 lateinit var message: String diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt index c3e0e2e3a..ced9db2b2 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt @@ -3,7 +3,6 @@ package net.mamoe.mirai.network.packet import net.mamoe.mirai.network.packet.login.* import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket -import net.mamoe.mirai.network.packet.verification.ServerVerificationCodePacketEncrypted import net.mamoe.mirai.utils.getAllDeclaredFields import net.mamoe.mirai.utils.hexToBytes import net.mamoe.mirai.utils.toUHexString @@ -150,6 +149,15 @@ fun DataInputStream.readNBytesAt(position: N, length: Int): ByteArr return this.readNBytes(length) } +fun DataInputStream.readNBytes(length: N): ByteArray { + return this.readNBytes(length.toInt()) +} + +fun DataInputStream.readNBytesIn(range: IntRange): ByteArray { + this.goto(range.first) + return this.readNBytes(range.last - range.first + 1) +} + fun DataInputStream.readIntAt(position: N): Int { this.goto(position) return this.readInt(); diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt index a6eb7bf81..4f55c4e88 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt @@ -14,7 +14,7 @@ import java.net.InetAddress @ExperimentalUnsignedTypes @PacketId("08 28 04 34") class ClientSessionRequestPacket( - private val qq: Int, + private val qq: Long, private val serverIp: String, private val loginIP: String, private val md5_32: ByteArray, diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt index 5654f791c..bf3624e84 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt @@ -76,7 +76,7 @@ class ServerTouchResponsePacketEncrypted(private val type: ServerTouchResponsePa */ @ExperimentalUnsignedTypes @PacketId("08 25 31 01") -class ClientTouchPacket(val qq: Int, val serverIp: String) : ClientPacket() { +class ClientTouchPacket(val qq: Long, val serverIp: String) : ClientPacket() { @ExperimentalUnsignedTypes @Throws(IOException::class) override fun encode() { @@ -108,7 +108,7 @@ class ClientTouchPacket(val qq: Int, val serverIp: String) : ClientPacket() { */ @ExperimentalUnsignedTypes @PacketId("08 25 31 02") -class ClientServerRedirectionPacket(private val serverIP: String, private val qq: Int) : ClientPacket() { +class ClientServerRedirectionPacket(private val serverIP: String, private val qq: Long) : ClientPacket() { @ExperimentalUnsignedTypes override fun encode() { this.writeQQ(qq) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt new file mode 100644 index 000000000..4684f356b --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt @@ -0,0 +1,98 @@ +package net.mamoe.mirai.network.packet + +import net.mamoe.mirai.network.Protocol +import net.mamoe.mirai.utils.* +import java.io.DataInputStream + + +@ExperimentalUnsignedTypes +@PacketId("00 BA 31") +class ClientVerificationCodeTransmissionRequestPacket(//todo 这个包可能有问题. + private val count: Int, + private val qq: Long, + private val token0825: ByteArray, + private val verificationSequence: Int, + private val token00BA: ByteArray +) : ClientPacket() { + override fun encode() { + this.writeByte(count)//part of packet id + + this.writeQQ(qq) + this.writeHex(Protocol._fixVer) + this.writeHex(Protocol._00BaKey) + this.encryptAndWrite(Protocol._00BaKey) { + it.writeHex("00 02 00 00 08 04 01 E0") + it.writeHex(Protocol._0825data2) + it.writeHex("00 00 38") + it.write(token0825) + it.writeHex("01 03 00 19") + it.writeHex(Protocol.publicKey) + it.writeHex("13 00 05 00 00 00 00") + it.writeByte(verificationSequence) + it.writeHex("00 28") + it.write(token00BA) + it.writeHex("00 10") + it.writeHex(Protocol._00BaFixKey) + } + } +} + +/** + * @author Him188moe + */ +class ServerVerificationCodeTransmissionPacket(input: DataInputStream, val dataSize: Int, val packetId: ByteArray) : ServerVerificationCodePacket(input) { + + lateinit var verificationCodePart2: ByteArray + lateinit var verificationToken: ByteArray//56bytes + var transmissionCompleted: Boolean = false//验证码是否已经传输完成 + lateinit var token00BA: ByteArray//40 bytes + var count: Int = 0 + + @ExperimentalUnsignedTypes + override fun decode() { + this.verificationToken = this.input.readNBytesAt(10, 56) + + val length = this.input.readShortAt(66) + this.verificationCodePart2 = this.input.readNBytes(length) + + this.input.skip(2) + this.transmissionCompleted = this.input.readBoolean() + + this.token00BA = this.input.readNBytesAt(dataSize - 57, 40) + this.count = byteArrayOf(0, 0, packetId[2], packetId[3]).toUHexString().hexToInt() + } +} + +/** + * @author Him188moe + */ +class ServerVerificationCodeRepeatPacket(input: DataInputStream) : ServerVerificationCodePacket(input) { + + lateinit var token00BA: ByteArray//56 bytes + lateinit var tgtgtKeyUpdate: ByteArray + + @ExperimentalUnsignedTypes + override fun decode() { + token00BA = this.input.readNBytesAt(10, 56) + tgtgtKeyUpdate = getRandomKey(16) + } +} + +abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input) + +class ServerVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) { + override fun decode() { + + } + + @ExperimentalUnsignedTypes + fun decrypt(): ServerVerificationCodePacket { + this.input goto 14 + val data = TEACryptor.decrypt(Protocol._00BaKey.hexToBytes(), this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }) + return if (data.size == 95) { + ServerVerificationCodeRepeatPacket(data.dataInputStream()) + } else { + ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4)) + } + } +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt index c58e1c6d4..2330c1d30 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt @@ -18,7 +18,7 @@ import java.io.DataOutputStream @ExperimentalUnsignedTypes @TestedSuccessfully class ClientPasswordSubmissionPacket( - private val qq: Int, + private val qq: Long, private val password: String, private val loginTime: Int, private val loginIP: String, @@ -43,17 +43,22 @@ class ClientPasswordSubmissionPacket( @PacketId("08 36 31 04") @ExperimentalUnsignedTypes -class ClientLoginResendPacket3104(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null) +class ClientLoginResendPacket3104(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null) : ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv_0006_encr) +@PacketId("08 36 31 05") +@ExperimentalUnsignedTypes +class ClientLoginResendPacket3105(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray) + : ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, null) + @PacketId("08 36 31 06") @ExperimentalUnsignedTypes -class ClientLoginResendPacket3106(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null) +class ClientLoginResendPacket3106(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null) : ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv_0006_encr) @ExperimentalUnsignedTypes open class ClientLoginResendPacket internal constructor( - val qq: Int, + val qq: Long, val password: String, val loginTime: Int, val loginIP: String, @@ -91,7 +96,7 @@ open class ClientLoginResendPacket internal constructor( * @author Him188moe */ @ExperimentalUnsignedTypes -private fun DataOutputStream.writePart1(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, tlv_0006_encr: ByteArray? = null) { +private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, tlv_0006_encr: ByteArray? = null) { //this.writeInt(System.currentTimeMillis().toInt()) this.writeHex("01 12")//tag diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt index e73b228d5..7c2b2eae3 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt @@ -10,7 +10,7 @@ import net.mamoe.mirai.utils.ClientLoginStatus @ExperimentalUnsignedTypes @PacketId("00 EC") class ClientLoginStatusPacket( - private val qq: Int, + private val qq: Long, private val sessionKey: ByteArray, private val loginStatus: ClientLoginStatus diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginVerificationCodePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginVerificationCodePacket.kt deleted file mode 100644 index 751fa07bf..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginVerificationCodePacket.kt +++ /dev/null @@ -1,41 +0,0 @@ -package net.mamoe.mirai.network.packet.login - -import net.mamoe.mirai.network.Protocol -import net.mamoe.mirai.network.packet.* -import net.mamoe.mirai.utils.ByteArrayDataOutputStream -import net.mamoe.mirai.utils.TEACryptor - -/** - * @author Him188moe - */ -@PacketId("00 BA 31 01") -@ExperimentalUnsignedTypes -class ClientLoginVerificationCodePacket( - private val qq: Int, - private val token0825: ByteArray, - private val sequence: Int, - private val token00BA: ByteArray -) : ClientPacket() { - override fun encode() { - this.writeQQ(qq) - this.writeHex(Protocol.fixVer) - this.writeHex(Protocol._00BaKey) - this.write(TEACryptor.CRYPTOR_00BAKEY.encrypt(object : ByteArrayDataOutputStream() { - override fun toByteArray(): ByteArray { - this.writeHex("00 02 00 00 08 04 01 E0") - this.writeHex(Protocol._0825data2) - this.writeHex("00 00 38") - this.write(token0825) - this.writeHex("01 03 00 19") - this.writeHex(Protocol.publicKey) - this.writeHex("13 00 05 00 00 00 00") - this.writeVarInt(sequence.toUInt()) - this.writeHex("00 28") - this.write(token00BA) - this.writeHex("00 10") - this.writeHex(Protocol._00BaFixKey) - return super.toByteArray() - } - }.toByteArray())) - } -} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt similarity index 61% rename from mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodePacket.kt rename to mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt index 540b23f5a..1d6428c63 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodePacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt @@ -7,19 +7,22 @@ import net.mamoe.mirai.utils.TEACryptor import java.io.DataInputStream /** + * 收到这个包意味着需要验证码登录, 并且能得到验证码图片文件的一半 + * * @author Him188moe */ -class ServerLoginResponseVerificationCodePacket(input: DataInputStream, private val packetLength: Int) : ServerPacket(input) { +class ServerLoginResponseVerificationCodeInitPacket(input: DataInputStream, private val packetLength: Int) : ServerPacket(input) { - lateinit var verifyCode: ByteArray + lateinit var verifyCodePart1: ByteArray lateinit var token00BA: ByteArray var unknownBoolean: Boolean? = null +//todo 也有可能这个包有问题, 也有可能 ClientVerificationCodeTransmissionRequestPacket. 检查 @ExperimentalUnsignedTypes override fun decode() { val verifyCodeLength = this.input.goto(78).readShort()//2bytes - this.verifyCode = this.input.readNBytes(verifyCodeLength.toInt()) + this.verifyCodePart1 = this.input.readNBytes(verifyCodeLength.toInt()) this.input.skip(1) @@ -34,9 +37,9 @@ class ServerLoginResponseVerificationCodePacketEncrypted(input: DataInputStream) } - fun decrypt(): ServerLoginResponseVerificationCodePacket { + fun decrypt(): ServerLoginResponseVerificationCodeInitPacket { this.input goto 14 val data = TEACryptor.CRYPTOR_SHARE_KEY.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }); - return ServerLoginResponseVerificationCodePacket(data.dataInputStream(), data.size) + return ServerLoginResponseVerificationCodeInitPacket(data.dataInputStream(), data.size) } } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt index 905d3fd9b..6fa63d04d 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt @@ -11,10 +11,10 @@ import java.io.DataInputStream @PacketId("00 CD") @ExperimentalUnsignedTypes class ClientSendFriendMessagePacket( - val robotQQ: Int, - val targetQQ: Int, - val sessionKey: ByteArray, - val message: String + private val robotQQ: Long, + private val targetQQ: Long, + private val sessionKey: ByteArray, + private val message: String ) : ClientPacket() { override fun encode() { this.writeRandom(2)//part of packet id @@ -52,7 +52,7 @@ class ClientSendFriendMessagePacket( it.writeByte(0x01) it.writeShort(bytes.size) it.write(bytes) - }//todo check + } } } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt index 315814a29..2ef2a85cc 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt @@ -12,8 +12,8 @@ import java.io.DataInputStream @PacketId("00 02") @ExperimentalUnsignedTypes class ClientSendGroupMessagePacket( - private val groupId: Int,//不是 number - private val qq: Int, + private val groupId: Long,//不是 number + private val qq: Long, private val sessionKey: ByteArray, private val message: String ) : ClientPacket() { @@ -25,7 +25,7 @@ class ClientSendGroupMessagePacket( this.encryptAndWrite(sessionKey) { val bytes = message.toByteArray() it.writeByte(0x2A) - it.writeInt(groupId) + it.writeGroup(groupId) it.writeShort(56 + bytes.size) it.writeHex("00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00") diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/verification/ServerVerificationCodePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/verification/ServerVerificationCodePacket.kt deleted file mode 100644 index 710c1c2a0..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/verification/ServerVerificationCodePacket.kt +++ /dev/null @@ -1,44 +0,0 @@ -package net.mamoe.mirai.network.packet.verification - -import net.mamoe.mirai.network.packet.ServerPacket -import net.mamoe.mirai.network.packet.dataInputStream -import net.mamoe.mirai.network.packet.goto -import net.mamoe.mirai.utils.TEACryptor -import java.io.DataInputStream - -/** - * @author Him188moe - */ -class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input) { - - lateinit var verifyCode: ByteArray - lateinit var verifyToken: ByteArray - var unknownBoolean: Boolean? = null - lateinit var token00BA: ByteArray - var count: Int = 0 - - @ExperimentalUnsignedTypes - override fun decode() { - TODO() - val verifyCodeLength = this.input.goto(78).readShort()//2bytes - this.verifyCode = this.input.readNBytes(verifyCodeLength.toInt()) - - this.input.skip(1) - - this.unknownBoolean = this.input.readByte().toInt() == 1 - - //this.token00BA = this.input.goto(packetLength - 60).readNBytesAt(40) - } -} - -class ServerVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) { - override fun decode() { - - } - - fun decrypt(token00BA: ByteArray): ServerVerificationCodePacket { - this.input goto 14 - val data = TEACryptor.decrypt(token00BA, this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }); - return ServerVerificationCodePacket(data.dataInputStream()) - } -} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/ContactList.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/ContactList.java index 2729890f2..6cfde9c52 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/ContactList.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/ContactList.java @@ -6,5 +6,5 @@ import net.mamoe.mirai.utils.config.MiraiSynchronizedLinkedListMap; /** * @author Him188moe */ -public class ContactList extends MiraiSynchronizedLinkedListMap { +public class ContactList extends MiraiSynchronizedLinkedListMap { } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt b/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt index 3fac69b21..72ceb4c1a 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt @@ -20,6 +20,8 @@ fun ByteArray.toHexString(separator: String = " "): String = this.joinToString(s @ExperimentalUnsignedTypes fun ByteArray.toUHexString(separator: String = " "): String = this.toUByteArray().toUHexString(separator) +fun ByteArray.__toUHexString(separator: String = " "): String = this.toUByteArray().toUHexString(separator) + @ExperimentalUnsignedTypes fun ByteArray.toUHexString(): String = this.toUByteArray().toUHexString() diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfigSection.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfigSection.java index 196ddd59a..7005b3f59 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfigSection.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfigSection.java @@ -126,10 +126,10 @@ public class MiraiConfigSection extends MiraiSynchronizedLinkedListMap throwableCallable) throws Throwable { + public String getStringOrThrow(String key, Supplier exceptionSupplier) throws Throwable { Object result = this.getOrDefault(key, null); if(result == null){ - throw throwableCallable.call(); + throw exceptionSupplier.get(); } return result.toString(); } diff --git a/mirai-core/src/test/java/HexComparator.java b/mirai-core/src/test/java/HexComparator.java index cabaeba5d..e3a1571ca 100644 --- a/mirai-core/src/test/java/HexComparator.java +++ b/mirai-core/src/test/java/HexComparator.java @@ -3,11 +3,17 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.ToString; import net.mamoe.mirai.network.Protocol; +import net.mamoe.mirai.network.packet.ClientPacketKt; +import net.mamoe.mirai.utils.UtilsKt; +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; import java.lang.reflect.Field; import java.util.Arrays; import java.util.LinkedList; import java.util.List; +import java.util.Scanner; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; @@ -32,15 +38,24 @@ public class HexComparator { private static final String BLUE = "\033[34m"; - public static final List consts = new LinkedList<>(){{ + public static final List consts = new LinkedList<>() {{ add(new HexReader("90 5E 39 DF 00 02 76 E4 B8 DD 00")); }}; private static class ConstMatcher { private static final List CONST_FIELDS = new LinkedList<>() {{ List.of(Protocol.class).forEach(aClass -> Arrays.stream(aClass.getDeclaredFields()).peek(this::add).forEach(Field::trySetAccessible)); + List.of(TestConsts.class).forEach(aClass -> Arrays.stream(aClass.getDeclaredFields()).peek(this::add).forEach(Field::trySetAccessible)); }}; + @SuppressWarnings({"unused", "NonAsciiCharacters"}) + private static class TestConsts { + private static final String 牛逼 = UtilsKt.__toUHexString("牛逼".getBytes(), " "); + private static final String _1994701021 = ClientPacketKt.toHexString(1994701021, " "); + private static final String _1040400290 = ClientPacketKt.toHexString(1040400290, " "); + private static final String _580266363 = ClientPacketKt.toHexString(580266363, " "); + } + private final List matches = new LinkedList<>(); private ConstMatcher(String hex) { @@ -89,6 +104,23 @@ public class HexComparator { } } + private static void buildConstNameChain(int length, ConstMatcher constMatcher, StringBuilder constNameBuilder) { + for (int i = 0; i < length; i++) { + constNameBuilder.append(" "); + String match = constMatcher.getMatchedConstName(i / 4); + if (match != null) { + int appendedNameLength = match.length(); + constNameBuilder.append(match); + while (constMatcher.getMatchedConstName(i++ / 4) != null) { + if (appendedNameLength-- <= 0) { + constNameBuilder.append(" "); + } + } + + } + } + } + private static String compare(String hex1s, String hex2s) { StringBuilder builder = new StringBuilder(); @@ -105,10 +137,17 @@ public class HexComparator { StringBuilder numberLine = new StringBuilder(); + StringBuilder hex1ConstName = new StringBuilder(); StringBuilder hex1b = new StringBuilder(); StringBuilder hex2b = new StringBuilder(); + StringBuilder hex2ConstName = new StringBuilder(); int dif = 0; + int length = Math.max(hex1.length, hex2.length) * 4; + buildConstNameChain(length, constMatcher1, hex1ConstName); + buildConstNameChain(length, constMatcher2, hex2ConstName); + + for (int i = 0; i < Math.max(hex1.length, hex2.length); ++i) { String h1 = null; String h2 = null; @@ -152,7 +191,7 @@ public class HexComparator { } } - numberLine.append(UNKNOWN).append(getNumber(i)).append(" "); + numberLine.append(UNKNOWN).append(getFixedNumber(i)).append(" "); hex1b.append(" ").append(h1).append(" "); hex2b.append(" ").append(h2).append(" "); if (isDif) { @@ -165,42 +204,46 @@ public class HexComparator { return (builder.append(" ").append(dif).append(" 个不同").append("\n") .append(numberLine).append("\n") + .append(hex1ConstName).append("\n") .append(hex1b).append("\n") - .append(hex2b)) + .append(hex2b).append("\n") + .append(hex2ConstName).append("\n") + ) .toString(); } - private static void doConstReplacement(StringBuilder builder){ + private static void doConstReplacement(StringBuilder builder) { String mirror = builder.toString(); HexReader hexs = new HexReader(mirror); - for (AtomicInteger i=new AtomicInteger(0);i.get() { hexs.setTo(i.get()); List posToPlaceColor = new LinkedList<>(); AtomicBoolean is = new AtomicBoolean(false); - a.readFully((c,d) -> { - if(c.equals(hexs.readHex())){ + a.readFully((c, d) -> { + if (c.equals(hexs.readHex())) { posToPlaceColor.add(d); - }else{ + } else { is.set(false); } }); - if(is.get()){ + if (is.get()) { AtomicInteger adder = new AtomicInteger(); posToPlaceColor.forEach(e -> { - builder.insert(e + adder.getAndAdd(BLUE.length()),BLUE); + builder.insert(e + adder.getAndAdd(BLUE.length()), BLUE); }); } }); } } - private static String getNumber(int number) { + + private static String getFixedNumber(int number) { if (number < 10) { return "00" + number; } @@ -210,8 +253,31 @@ public class HexComparator { return String.valueOf(number); } - public static void main(String[] args) { + private static String getClipboardString() { + Transferable trans = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null); + if (trans.isDataFlavorSupported(DataFlavor.stringFlavor)) { + try { + return (String) trans.getTransferData(DataFlavor.stringFlavor); + } catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } + + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + while (true) { + System.out.println("Hex1: "); + var hex1 = scanner.nextLine(); + System.out.println("Hex2: "); + var hex2 = scanner.nextLine(); + System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + System.out.println(HexComparator.compare(hex1, hex2)); + System.out.println(); + } +/* System.out.println(HexComparator.compare( //mirai @@ -230,66 +296,63 @@ public class HexComparator { "6F 0B DF 92 00 02 76 E4 B8 DD 00 00 04 53 00 00 00 01 00 00 15 85 00 00 01 55 35 05 8E C9 BA 16 D0 01 63 5B 59 4B 59 52 31 01 B9 00 00 00 00 00 00 00 00 00 00 00 00 00 E9 E9 E9 E9 00 00 00 00 00 00 00 00 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B AA BB CC DD EE FF AA BB CC\n\n\n" ));*/ } - - } -class HexReader{ +class HexReader { private String s; private int pos = 0; private int lastHaxPos = 0; - public HexReader(String s){ + public HexReader(String s) { this.s = s; } - public String readHex(){ + public String readHex() { boolean isStr = false; String next = ""; - for (;pos processor){ + public void readFully(BiConsumer processor) { this.reset(); String nextHax = this.readHex(); - while (!nextHax.equals(" ")){ - processor.accept(nextHax,this.lastHaxPos); + while (!nextHax.equals(" ")) { + processor.accept(nextHax, this.lastHaxPos); nextHax = this.readHex(); } } - public void setTo(int pos){ + public void setTo(int pos) { this.pos = pos; } - public void reset(){ + public void reset() { this.pos = 0; } - } diff --git a/mirai-core/src/test/java/TestKt.kt b/mirai-core/src/test/java/TestKt.kt new file mode 100644 index 000000000..42878b5dc --- /dev/null +++ b/mirai-core/src/test/java/TestKt.kt @@ -0,0 +1,8 @@ +import net.mamoe.mirai.utils.toUHexString + +/** + * @author Him188moe + */ +fun main() { + println("牛逼".toByteArray().toUHexString()) +} \ No newline at end of file From b2ec40e195e6a52112cb90be27d6374ee2111423 Mon Sep 17 00:00:00 2001 From: Him188moe Date: Tue, 3 Sep 2019 19:25:48 +0800 Subject: [PATCH 02/19] Updated verification code processing --- .../mirai/network/RobotNetworkHandler.kt | 12 +++++---- .../mirai/network/packet/ServerPacket.kt | 2 +- .../mirai/network/packet/VerificationCode.kt | 7 ++++-- ...LoginResponseVerificationCodeInitPacket.kt | 25 ++++++++++++++++++- .../main/java/net/mamoe/mirai/utils/Utils.kt | 14 ++++++----- 5 files changed, 45 insertions(+), 15 deletions(-) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index 0db821a4f..8e0e5a363 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -47,7 +47,7 @@ class RobotNetworkHandler(val robot: Robot, val number: Long, private val passwo private var verificationCodeSequence: Int = 0//这两个验证码使用 private var verificationCodeCache: ByteArray? = null//每次包只发一部分验证码来 - private var verificationCodeCacheCount: Int = 0// + private var verificationCodeCacheCount: Int = 1// private lateinit var verificationToken: ByteArray private lateinit var sessionKey: ByteArray//这两个是登录成功后得到的 @@ -156,21 +156,23 @@ class RobotNetworkHandler(val robot: Robot, val number: Long, private val passwo } is ServerVerificationCodeTransmissionPacket -> { - this.verificationCodeSequence = 0 + this.verificationCodeSequence++ this.verificationCodeCache = this.verificationCodeCache!! + packet.verificationCodePart2 this.verificationToken = packet.verificationToken - this.verificationCodeCacheCount = packet.count + this.verificationCodeCacheCount++ this.token00BA = packet.token00BA - this.verificationCodeCache + + + //todo 看易语言 count 和 sequence 是怎样变化的 if (packet.transmissionCompleted) { this.verificationCodeCache TODO("验证码好了") } else { - sendPacket(ClientVerificationCodeTransmissionRequestPacket(packet.count, this.number, this.token0825, this.verificationCodeSequence, this.token00BA)) + sendPacket(ClientVerificationCodeTransmissionRequestPacket(this.verificationCodeCacheCount, this.number, this.token0825, this.verificationCodeSequence, this.token00BA)) } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt index ced9db2b2..dbe4d4599 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt @@ -55,7 +55,7 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { 359 -> ServerLoginResponseFailedPacket.State.TAKEN_BACK //unknown - 63 -> throw IllegalArgumentException(bytes.size.toString() + " (Already logged in)")//可能是已经完成登录, 服务器拒绝第二次登录 + 63 -> throw IllegalArgumentException(bytes.size.toString() + " (Unknown error)")//可能是已经完成登录, 服务器拒绝第二次登录 351 -> throw IllegalArgumentException(bytes.size.toString() + " (Illegal package data)")//包数据有误 else -> throw IllegalArgumentException(bytes.size.toString()) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt index 4684f356b..d79cabe9f 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt @@ -1,19 +1,21 @@ package net.mamoe.mirai.network.packet import net.mamoe.mirai.network.Protocol +import net.mamoe.mirai.util.TestedSuccessfully import net.mamoe.mirai.utils.* import java.io.DataInputStream @ExperimentalUnsignedTypes @PacketId("00 BA 31") -class ClientVerificationCodeTransmissionRequestPacket(//todo 这个包可能有问题. +class ClientVerificationCodeTransmissionRequestPacket( private val count: Int, private val qq: Long, private val token0825: ByteArray, private val verificationSequence: Int, private val token00BA: ByteArray ) : ClientPacket() { + @TestedSuccessfully override fun encode() { this.writeByte(count)//part of packet id @@ -80,6 +82,7 @@ class ServerVerificationCodeRepeatPacket(input: DataInputStream) : ServerVerific abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input) +@PacketId("00 BA") class ServerVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) { override fun decode() { @@ -88,7 +91,7 @@ class ServerVerificationCodePacketEncrypted(input: DataInputStream) : ServerPack @ExperimentalUnsignedTypes fun decrypt(): ServerVerificationCodePacket { this.input goto 14 - val data = TEACryptor.decrypt(Protocol._00BaKey.hexToBytes(), this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }) + val data = TEACryptor.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, Protocol._00BaKey.hexToBytes()) return if (data.size == 95) { ServerVerificationCodeRepeatPacket(data.dataInputStream()) } else { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt index 1d6428c63..3d46f3b0f 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt @@ -3,7 +3,9 @@ package net.mamoe.mirai.network.packet.login import net.mamoe.mirai.network.packet.ServerPacket import net.mamoe.mirai.network.packet.dataInputStream import net.mamoe.mirai.network.packet.goto +import net.mamoe.mirai.util.TestedSuccessfully import net.mamoe.mirai.utils.TEACryptor +import net.mamoe.mirai.utils.hexToUBytes import java.io.DataInputStream /** @@ -16,9 +18,9 @@ class ServerLoginResponseVerificationCodeInitPacket(input: DataInputStream, priv lateinit var verifyCodePart1: ByteArray lateinit var token00BA: ByteArray var unknownBoolean: Boolean? = null -//todo 也有可能这个包有问题, 也有可能 ClientVerificationCodeTransmissionRequestPacket. 检查 + @TestedSuccessfully @ExperimentalUnsignedTypes override fun decode() { val verifyCodeLength = this.input.goto(78).readShort()//2bytes @@ -32,6 +34,27 @@ class ServerLoginResponseVerificationCodeInitPacket(input: DataInputStream, priv } } +fun main() { + val data = "FB 01 04 03 33 00 01 00 BA 02 03 2C 13 00 05 01 00 00 01 23 00 38 D5 01 05 8B 67 4D 52 5A FA 92 DB 99 18 D4 F0 72 03 E0 17 71 7C 8A 45 74 1F C3 2D F8 61 96 0D 93 0D 8C 51 95 70 F8 F9 CB B9 2D 5D BC 4F 5D 89 5F E7 59 8C E4 E5 A2 04 56 02 BC 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 00 82 00 00 00 35 08 03 00 00 00 BA 12 C3 02 00 00 00 04 67 41 4D 41 00 00 B1 8F 0B FC 61 05 00 00 00 01 73 52 47 42 00 AE CE 1C E9 00 00 00 45 50 4C 54 45 FE F6 ED E2 F1 DF F3 FF F2 11 77 48 FE FE F3 F1 F9 EA D7 FD E7 F8 F9 EC FC EF E7 E8 FF EE 2D 69 48 2A 8A 5D 29 7A 52 F0 ED E1 A9 C7 B1 65 96 79 AB E0 C2 C3 F0 D5 42 7D 5C 4A 99 72 89 AA 93 51 73 5C 6E BA 94 42 BD 7A 0B 00 00 09 C5 49 44 41 54 58 C3 AC 99 8B 76 AB 3A 12 44 91 D0 1B 10 08 04 FF FF A9 B3 5B 60 C7 AF 38 77 EE 0C EB C4 76 6C 07 95 BA AB AB AB 75 BA EE 1F 5D DE CB 63 08 C1 C7 A8 AD BC B6 31 46 6B 3B A3 79 94 E7 F3 63 79 E4 D9 98 89 37 7D F7 FF BB 3C 10 82 6F B7 F7 2A B6 5B 07 EF B5 16 60 DE 1B 63 3A 1F 7E BE 6D 0C 50 EC 09 E1 FE 76 B8 3F FC 6B 0C 1D 5B 37 1F 3E E1 AE 61 9A D8 B6 07 93 B7 56 4D 66 22 06 9D FC EE 5F BF F9 3F 81 90 BB 99 F3 49 E2 1D DA 43 38 13 44 14 8C 9D B4 8E E7 65 40 11 E4 BB FE 8C 5B 78 41 F1 AF 01 48 2E 08 6D 8B AD F1 BA 05 F9 C4 E0 25 E6 31 BA EB 2A 90 C3 74 26 FC 1E 80 CF 14 91 44 7F FC 39 FF D4 37 10 82 C0 B3 B0 67 BF 2E 5E 5B F4 46 E5 3A 5F D7 BE A6 54 17 2D 7C 0D D7 DA E1 7E 93 C7 E5 DB 9E 6E 9F FD A3 14 9C 7F 23 97 55 FA DC 6F 74 8A CC 04 49 03 3F DE 4E 5C 4A 95 9C 53 8D 7A EA 82 F9 10 77 7F EE E5 43 28 C2 9F 00 BA 5B C0 59 A4 CE DB BA AE DB BC 14 D5 2A 82 A5 83 E0 30 92 19 A8 99 36 A7 15 7C BC DF F6 BE D7 86 C0 7F C9 C5 ED 93 C7 1F B9 E0 56 CB AC 61 F5 5D 2E 00 F0 93 D2 5A 9D B6 B0 3F 4B 4D 5C B9 0F C1 EE 29 46 65 4E 40 46 E2 E4 1B 91 C3 A5 2E FE D3 7A 3C 84 0B E3 F3 E2 57 16 2F 08 B9 E6 5A 73 29 65 29 4E B9 25 CF 6B 9A 97 48 20 B2 35 46 1B 6D AD D6 9A 57 69 45 B2 1A 00 90 05 51 8D C7 24 F8 1B B9 FE A6 41 B8 83 6C 59 05 84 9F 44 0F 85 05 9A 97 5A 97 BC A6 6D 81 FE 59 DE 2F 4B 5E E4 DF B2 A4 19 AA 06 D9 FE F9 33 4D 7E 6A 40 FC 97 34 BF 84 E4 81 81 ED E9 DC 85 32 56 47 E5 A4 F0 2D 6F 4D 2A BA 65 4B 73 89 B6 58 5E D7 35 8D 69 E4 4A 6B 76 50 C1 5C 3A D9 59 11 CF 37 99 FA 48 88 70 7F F4 9F 22 12 F2 24 91 3E 2B BF 28 A5 34 68 C0 50 A3 55 DD A4 E3 9C 6E 85 99 95 B6 24 2E 18 D9 3C 5C B1 4D AA 2F 08 E1 75 F1 F0 6B 49 FC BC E3 8D 00 01 00 28 42 E6 18 57 D4 B1 4D AE 51 27 D5 EF A2 38 91 39 15 37 6C 5A FE 75 93 49 DB FC 57 3C 12 3F 26 D9 16 1D 83 45 8B 78 39 D8 01 15 00 10 F6 F0 50 03 74 BB 18 91 D3 55 8D 7F BB 53 15 7A".hexToUBytes().toByteArray(); + ServerLoginResponseVerificationCodeInitPacket( + data.dataInputStream(), + data.size + ).let { it.decode(); println(it) } +} + +/* +data +FB 01 04 03 33 00 01 00 BA 02 03 2C 13 00 05 01 00 00 01 23 00 38 D5 01 05 8B 67 4D 52 5A FA 92 DB 99 18 D4 F0 72 03 E0 17 71 7C 8A 45 74 1F C3 2D F8 61 96 0D 93 0D 8C 51 95 70 F8 F9 CB B9 2D 5D BC 4F 5D 89 5F E7 59 8C E4 E5 A2 04 56 02 BC 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 00 82 00 00 00 35 08 03 00 00 00 BA 12 C3 02 00 00 00 04 67 41 4D 41 00 00 B1 8F 0B FC 61 05 00 00 00 01 73 52 47 42 00 AE CE 1C E9 00 00 00 45 50 4C 54 45 FE F6 ED E2 F1 DF F3 FF F2 11 77 48 FE FE F3 F1 F9 EA D7 FD E7 F8 F9 EC FC EF E7 E8 FF EE 2D 69 48 2A 8A 5D 29 7A 52 F0 ED E1 A9 C7 B1 65 96 79 AB E0 C2 C3 F0 D5 42 7D 5C 4A 99 72 89 AA 93 51 73 5C 6E BA 94 42 BD 7A 0B 00 00 09 C5 49 44 41 54 58 C3 AC 99 8B 76 AB 3A 12 44 91 D0 1B 10 08 04 FF FF A9 B3 5B 60 C7 AF 38 77 EE 0C EB C4 76 6C 07 95 BA AB AB AB 75 BA EE 1F 5D DE CB 63 08 C1 C7 A8 AD BC B6 31 46 6B 3B A3 79 94 E7 F3 63 79 E4 D9 98 89 37 7D F7 FF BB 3C 10 82 6F B7 F7 2A B6 5B 07 EF B5 16 60 DE 1B 63 3A 1F 7E BE 6D 0C 50 EC 09 E1 FE 76 B8 3F FC 6B 0C 1D 5B 37 1F 3E E1 AE 61 9A D8 B6 07 93 B7 56 4D 66 22 06 9D FC EE 5F BF F9 3F 81 90 BB 99 F3 49 E2 1D DA 43 38 13 44 14 8C 9D B4 8E E7 65 40 11 E4 BB FE 8C 5B 78 41 F1 AF 01 48 2E 08 6D 8B AD F1 BA 05 F9 C4 E0 25 E6 31 BA EB 2A 90 C3 74 26 FC 1E 80 CF 14 91 44 7F FC 39 FF D4 37 10 82 C0 B3 B0 67 BF 2E 5E 5B F4 46 E5 3A 5F D7 BE A6 54 17 2D 7C 0D D7 DA E1 7E 93 C7 E5 DB 9E 6E 9F FD A3 14 9C 7F 23 97 55 FA DC 6F 74 8A CC 04 49 03 3F DE 4E 5C 4A 95 9C 53 8D 7A EA 82 F9 10 77 7F EE E5 43 28 C2 9F 00 BA 5B C0 59 A4 CE DB BA AE DB BC 14 D5 2A 82 A5 83 E0 30 92 19 A8 99 36 A7 15 7C BC DF F6 BE D7 86 C0 7F C9 C5 ED 93 C7 1F B9 E0 56 CB AC 61 F5 5D 2E 00 F0 93 D2 5A 9D B6 B0 3F 4B 4D 5C B9 0F C1 EE 29 46 65 4E 40 46 E2 E4 1B 91 C3 A5 2E FE D3 7A 3C 84 0B E3 F3 E2 57 16 2F 08 B9 E6 5A 73 29 65 29 4E B9 25 CF 6B 9A 97 48 20 B2 35 46 1B 6D AD D6 9A 57 69 45 B2 1A 00 90 05 51 8D C7 24 F8 1B B9 FE A6 41 B8 83 6C 59 05 84 9F 44 0F 85 05 9A 97 5A 97 BC A6 6D 81 FE 59 DE 2F 4B 5E E4 DF B2 A4 19 AA 06 D9 FE F9 33 4D 7E 6A 40 FC 97 34 BF 84 E4 81 81 ED E9 DC 85 32 56 47 E5 A4 F0 2D 6F 4D 2A BA 65 4B 73 89 B6 58 5E D7 35 8D 69 E4 4A 6B 76 50 C1 5C 3A D9 59 11 CF 37 99 FA 48 88 70 7F F4 9F 22 12 F2 24 91 3E 2B BF 28 A5 34 68 C0 50 A3 55 DD A4 E3 9C 6E 85 99 95 B6 24 2E 18 D9 3C 5C B1 4D AA 2F 08 E1 75 F1 F0 6B 49 FC BC E3 8D 00 01 00 28 42 E6 18 57 D4 B1 4D AE 51 27 D5 EF A2 38 91 39 15 37 6C 5A FE 75 93 49 DB FC 57 3C 12 3F 26 D9 16 1D 83 45 8B 78 39 D8 01 15 00 10 F6 F0 50 03 74 BB 18 91 D3 55 8D 7F BB 53 15 7A + +length 700 + +verify code +89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 00 82 00 00 00 35 08 03 00 00 00 BA 12 C3 02 00 00 00 04 67 41 4D 41 00 00 B1 8F 0B FC 61 05 00 00 00 01 73 52 47 42 00 AE CE 1C E9 00 00 00 45 50 4C 54 45 FE F6 ED E2 F1 DF F3 FF F2 11 77 48 FE FE F3 F1 F9 EA D7 FD E7 F8 F9 EC FC EF E7 E8 FF EE 2D 69 48 2A 8A 5D 29 7A 52 F0 ED E1 A9 C7 B1 65 96 79 AB E0 C2 C3 F0 D5 42 7D 5C 4A 99 72 89 AA 93 51 73 5C 6E BA 94 42 BD 7A 0B 00 00 09 C5 49 44 41 54 58 C3 AC 99 8B 76 AB 3A 12 44 91 D0 1B 10 08 04 FF FF A9 B3 5B 60 C7 AF 38 77 EE 0C EB C4 76 6C 07 95 BA AB AB AB 75 BA EE 1F 5D DE CB 63 08 C1 C7 A8 AD BC B6 31 46 6B 3B A3 79 94 E7 F3 63 79 E4 D9 98 89 37 7D F7 FF BB 3C 10 82 6F B7 F7 2A B6 5B 07 EF B5 16 60 DE 1B 63 3A 1F 7E BE 6D 0C 50 EC 09 E1 FE 76 B8 3F FC 6B 0C 1D 5B 37 1F 3E E1 AE 61 9A D8 B6 07 93 B7 56 4D 66 22 06 9D FC EE 5F BF F9 3F 81 90 BB 99 F3 49 E2 1D DA 43 38 13 44 14 8C 9D B4 8E E7 65 40 11 E4 BB FE 8C 5B 78 41 F1 AF 01 48 2E 08 6D 8B AD F1 BA 05 F9 C4 E0 25 E6 31 BA EB 2A 90 C3 74 26 FC 1E 80 CF 14 91 44 7F FC 39 FF D4 37 10 82 C0 B3 B0 67 BF 2E 5E 5B F4 46 E5 3A 5F D7 BE A6 54 17 2D 7C 0D D7 DA E1 7E 93 C7 E5 DB 9E 6E 9F FD A3 14 9C 7F 23 97 55 FA DC 6F 74 8A CC 04 49 03 3F DE 4E 5C 4A 95 9C 53 8D 7A EA 82 F9 10 77 7F EE E5 43 28 C2 9F 00 BA 5B C0 59 A4 CE DB BA AE DB BC 14 D5 2A 82 A5 83 E0 30 92 19 A8 99 36 A7 15 7C BC DF F6 BE D7 86 C0 7F C9 C5 ED 93 C7 1F B9 E0 56 CB AC 61 F5 5D 2E 00 F0 93 D2 5A 9D B6 B0 3F 4B 4D 5C B9 0F C1 EE 29 46 65 4E 40 46 E2 E4 1B 91 C3 A5 2E FE D3 7A 3C 84 0B E3 F3 E2 57 16 2F 08 B9 E6 5A 73 29 65 29 4E B9 25 CF 6B 9A 97 48 20 B2 35 46 1B 6D AD D6 9A 57 69 45 B2 1A 00 90 05 51 8D C7 24 F8 1B B9 FE A6 41 B8 83 6C 59 05 84 9F 44 0F 85 05 9A 97 5A 97 BC A6 6D 81 FE 59 DE 2F 4B 5E E4 DF B2 A4 19 AA 06 D9 FE F9 33 4D 7E 6A 40 FC 97 34 BF 84 E4 81 81 ED E9 DC 85 32 56 47 E5 A4 F0 2D 6F 4D 2A BA 65 4B 73 89 B6 58 5E D7 35 8D 69 E4 4A 6B 76 50 C1 5C 3A D9 59 11 CF 37 99 FA 48 88 70 7F F4 9F 22 12 F2 24 91 3E 2B BF 28 A5 34 68 C0 50 A3 55 DD A4 E3 9C 6E 85 99 95 B6 24 2E 18 D9 3C 5C B1 4D AA 2F 08 E1 75 F1 F0 6B 49 FC BC E3 8D + +token00ba +42 E6 18 57 D4 B1 4D AE 51 27 D5 EF A2 38 91 39 15 37 6C 5A FE 75 93 49 DB FC 57 3C 12 3F 26 D9 16 1D 83 45 8B 78 39 D8 + */ + class ServerLoginResponseVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) { override fun decode() { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt b/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt index 72ceb4c1a..0157ffa82 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt @@ -26,12 +26,14 @@ fun ByteArray.__toUHexString(separator: String = " "): String = this.toUByteArra fun ByteArray.toUHexString(): String = this.toUByteArray().toUHexString() @ExperimentalUnsignedTypes -fun UByteArray.toUHexString(separator: String = " "): String = this.joinToString(separator) { - var ret = it.toString(16).toUpperCase() - if (ret.length == 1) { - ret = "0$ret" +fun UByteArray.toUHexString(separator: String = " "): String { + return this.joinToString(separator) { + var ret = it.toString(16).toUpperCase() + if (ret.length == 1) { + ret = "0$ret" + } + return@joinToString ret } - return@joinToString ret } @ExperimentalUnsignedTypes @@ -53,7 +55,7 @@ fun String.hexToUBytes(): UByteArray = Protocol.hexToUBytes(this) fun String.hexToShort(): Short = hexToBytes().let { ((it[1].toInt() shl 8) + it[0]).toShort() } @ExperimentalUnsignedTypes -fun String.hexToInt(): Int = hexToBytes().let { ((it[3].toInt() shl 24) + (it[2].toInt() shl 16) + (it[1].toInt() shl 8) + it[0]) } +fun String.hexToInt(): Int = hexToBytes().let { ((it[0].toInt() shl 24) + (it[1].toInt() shl 16) + (it[2].toInt() shl 8) + it[3]) } @ExperimentalUnsignedTypes fun String.hexToByte(): Byte = hexToBytes()[0] From bde4610f7bc80a4465e4b3867332969e6b3ac104 Mon Sep 17 00:00:00 2001 From: Him188moe Date: Wed, 4 Sep 2019 20:37:10 +0800 Subject: [PATCH 03/19] Updated robot & network structure --- .../java/net/mamoe/mirai/MiraiServer.java | 14 +++-- .../src/main/java/net/mamoe/mirai/Robot.java | 15 ++++- .../java/net/mamoe/mirai/contact/Group.kt | 12 ++-- .../mirai/event/events/robot/RobotEvents.kt | 8 +-- .../net/mamoe/mirai/message/defaults/At.java | 3 +- .../mirai/network/RobotNetworkHandler.kt | 59 +++++++++++++++++-- .../mirai/network/packet/ClientPacket.kt | 4 -- .../mamoe/mirai/network/packet/ServerEvent.kt | 3 +- .../mirai/network/packet/ServerPacket.kt | 20 ++++--- .../mirai/network/packet/VerificationCode.kt | 15 +++-- .../mirai/network/packet/login/LoginState.kt | 18 ++++++ .../login/ServerLoginResponseFailedPacket.kt | 14 +---- .../login/ServerLoginResponseResendPacket.kt | 15 ----- 13 files changed, 130 insertions(+), 70 deletions(-) create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt diff --git a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java index a768ff60f..af7dcfdc7 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java @@ -5,6 +5,7 @@ import net.mamoe.mirai.event.MiraiEventManager; import net.mamoe.mirai.event.events.server.ServerDisableEvent; import net.mamoe.mirai.event.events.server.ServerEnableEvent; import net.mamoe.mirai.network.RobotNetworkHandler; +import net.mamoe.mirai.network.packet.login.LoginState; import net.mamoe.mirai.task.MiraiTaskManager; import net.mamoe.mirai.utils.LoggerTextFormat; import net.mamoe.mirai.utils.MiraiLogger; @@ -120,11 +121,16 @@ public class MiraiServer { this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> { try { Robot robot = new Robot(section); - RobotNetworkHandler robotNetworkHandler = robot.getHandler(); - robotNetworkHandler.setServerIP("14.116.136.106"); - robotNetworkHandler.touch$mirai_core(); + RobotNetworkHandler robotNetworkHandler = robot.getNetworkHandler(); + robotNetworkHandler.tryLogin$mirai_core(state -> { + if (state == LoginState.SUCCEED) { + Robot.instances.add(robot); + } else { + robot.close(); + } + return null; + }); - Robot.instances.add(robot); } catch (Throwable e) { e.printStackTrace(); getLogger().error("Could not load QQ robots config!"); diff --git a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java index 20b6c922a..fbc066118 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java @@ -7,18 +7,19 @@ import net.mamoe.mirai.network.RobotNetworkHandler; import net.mamoe.mirai.utils.ContactList; import net.mamoe.mirai.utils.config.MiraiConfigSection; +import java.io.Closeable; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; -public class Robot { +public class Robot implements Closeable { public static final List instances = Collections.synchronizedList(new LinkedList<>()); private final long qqNumber; private final String password; @Getter - private final RobotNetworkHandler handler; + private final RobotNetworkHandler networkHandler; /** * Ref list @@ -29,6 +30,14 @@ public class Robot { private final ContactList groups = new ContactList<>(); private final ContactList qqs = new ContactList<>(); + public void close() { + this.networkHandler.close(); + this.owners.clear(); + this.groups.values().forEach(Group::close); + this.groups.clear(); + this.qqs.clear(); + } + public boolean isOwnBy(String ownerName) { return owners.contains(ownerName); } @@ -50,7 +59,7 @@ public class Robot { this.qqNumber = qqNumber; this.password = password; this.owners = Collections.unmodifiableList(owners); - this.handler = new RobotNetworkHandler(this, this.qqNumber, this.password); + this.networkHandler = new RobotNetworkHandler(this, this.qqNumber, this.password); } public QQ getQQ(long qqNumber) { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt index 2d8677058..3d23d53b7 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt @@ -2,8 +2,9 @@ package net.mamoe.mirai.contact import net.mamoe.mirai.message.Message import net.mamoe.mirai.utils.ContactList +import java.io.Closeable -class Group(number: Long) : Contact(number) { +class Group(number: Long) : Contact(number), Closeable { val groupId = groupNumberToId(number) val members = ContactList() @@ -15,6 +16,10 @@ class Group(number: Long) : Contact(number) { } + override fun close() { + this.members.clear() + } + companion object { fun groupNumberToId(number: Long): Long { val left: Long = number.toString().let { @@ -53,11 +58,6 @@ class Group(number: Long) : Contact(number) { } } - @JvmStatic - fun main(args: Array) { - groupNumberToId(580266363) - } - fun groupIdToNumber(id: Long): Long { var left: Long = id.toString().let { if (it.length < 6) { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvents.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvents.kt index 581f92e87..737c47d58 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvents.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvents.kt @@ -1,16 +1,16 @@ package net.mamoe.mirai.event.events.robot +import net.mamoe.mirai.Robot import net.mamoe.mirai.event.events.MiraiEvent -import net.mamoe.mirai.network.RobotNetworkHandler /** * @author Him188moe */ -class RobotLoginEvent(val robotNetworkHandler: RobotNetworkHandler) : MiraiEvent() +class RobotLoginEvent(val robot: Robot) : MiraiEvent() -class RobotLogoutEvent(val robotNetworkHandler: RobotNetworkHandler) : MiraiEvent() +class RobotLogoutEvent(val robot: Robot) : MiraiEvent() -class RobotMessageReceivedEvent(val robotNetworkHandler: RobotNetworkHandler, val type: Type, val message: String) : MiraiEvent() { +class RobotMessageReceivedEvent(val robot: Robot, val type: Type, val message: String) : MiraiEvent() { enum class Type { FRIEND, GROUP diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java index 003d40850..d552e53c4 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java @@ -26,6 +26,7 @@ public final class At extends Message { @Override public String toString() { - return null; + // TODO: 2019/9/4 At.toString + throw new UnsupportedOperationException(); } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index 8e0e5a363..e62c95502 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -11,6 +11,7 @@ import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePac import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.task.MiraiThreadPool import net.mamoe.mirai.utils.* +import java.io.Closeable import java.net.DatagramPacket import java.net.DatagramSocket import java.net.InetSocketAddress @@ -23,7 +24,7 @@ import java.util.concurrent.TimeUnit * @author Him188moe */ @ExperimentalUnsignedTypes -class RobotNetworkHandler(val robot: Robot, val number: Long, private val password: String) { +internal class RobotNetworkHandler(val robot: Robot, val number: Long, private val password: String) : Closeable { var socket: DatagramSocket = DatagramSocket((15314 + Math.random() * 100).toInt()) @@ -36,6 +37,7 @@ class RobotNetworkHandler(val robot: Robot, val number: Long, private val passwo } private lateinit var serverAddress: InetSocketAddress + private var closed: Boolean = false private lateinit var token00BA: ByteArray //这些数据全部是login用的 private lateinit var token0825: ByteArray @@ -60,6 +62,16 @@ class RobotNetworkHandler(val robot: Robot, val number: Long, private val passwo private var gtk: Int = 0 private var ignoreMessage: Boolean = false + private var loginState: LoginState? = null + set(value) { + field = value + if (value != null) { + loginHook?.invoke(value) + } + } + + private var loginHook: ((LoginState) -> Unit)? = null + init { tlv0105 = lazyEncode { it.writeHex("01 05 00 30") @@ -74,15 +86,37 @@ class RobotNetworkHandler(val robot: Robot, val number: Long, private val passwo @ExperimentalUnsignedTypes private var md5_32: ByteArray = getRandomKey(32) + /** + * Try to login to server + */ + internal fun tryLogin(loginHook: ((LoginState) -> Unit)? = null) { +//"14.116.136.106", + tryLogin() + } - internal fun touch() { + /** + * Try to login to server + */ + private fun tryLogin(serverAddress: String, loginHook: ((LoginState) -> Unit)? = null) { + + touch(serverAddress, loginHook) + } + + /** + * Start network + */ + private fun touch(serverAddress: String, loginHook: ((LoginState) -> Unit)? = null) { + serverIP = serverAddress + if (loginHook != null) { + this.loginHook = loginHook + } this.sendPacket(ClientTouchPacket(this.number, this.serverIP)) } private fun restartSocket() { socket.close() socket = DatagramSocket((15314 + Math.random() * 100).toInt()) - socket.connect(this.serverAddress) + socket.connect(this.serverAddress).runCatching { } val zeroByte: Byte = 0 Thread { while (true) { @@ -91,11 +125,14 @@ class RobotNetworkHandler(val robot: Robot, val number: Long, private val passwo socket.receive(dp1) } catch (e: Exception) { if (e.message == "socket closed") { + if (!closed) { + restartSocket() + } return@Thread } } MiraiThreadPool.getInstance().submit { - var i = dp1.data.size - 1; + var i = dp1.data.size - 1 while (dp1.data[i] == zeroByte) { --i } @@ -132,7 +169,8 @@ class RobotNetworkHandler(val robot: Robot, val number: Long, private val passwo } is ServerLoginResponseFailedPacket -> { - MiraiLogger error "Login failed: " + packet.state.toString() + this.loginState = packet.loginState + MiraiLogger error "Login failed: " + packet.loginState.toString() return } @@ -157,7 +195,7 @@ class RobotNetworkHandler(val robot: Robot, val number: Long, private val passwo is ServerVerificationCodeTransmissionPacket -> { this.verificationCodeSequence++ - this.verificationCodeCache = this.verificationCodeCache!! + packet.verificationCodePart2 + this.verificationCodeCache = this.verificationCodeCache!! + packet.verificationCodePartN this.verificationToken = packet.verificationToken this.verificationCodeCacheCount++ @@ -236,6 +274,7 @@ class RobotNetworkHandler(val robot: Robot, val number: Long, private val passwo } is ServerLoginSuccessPacket -> { + loginState = LoginState.SUCCEED sendPacket(ClientSKeyRequestPacket(this.number, this.sessionKey)) } @@ -328,4 +367,12 @@ class RobotNetworkHandler(val robot: Robot, val number: Long, private val passwo } } } + + override fun close() { + this.socket.close() + this.loginState = null + this.loginHook = null + this.verificationCodeCache = null + this.tgtgtKey = null + } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt index 6c18807e8..7ea56c462 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt @@ -140,8 +140,6 @@ fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, lo val md5_1 = md5(password); val md5_2 = md5(md5_1 + "00 00 00 00".hexToBytes() + qq.toUInt().toByteArray()) - println(md5_1.toUByteArray().toUHexString()) - println(md5_2.toUByteArray().toUHexString()) it.write(md5_1) it.writeInt(loginTime) it.writeByte(0); @@ -151,8 +149,6 @@ fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, lo it.writeHex("00 10") it.writeHex("15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B") it.write(tgtgtKey) - println() - println(it.toByteArray().toUHexString()) this.write(TEACryptor.encrypt(it.toByteArray(), md5_2)) } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt index 02fcfc719..acf94031d 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt @@ -2,6 +2,7 @@ package net.mamoe.mirai.network.packet import net.mamoe.mirai.message.defaults.MessageChain import net.mamoe.mirai.message.defaults.PlainText +import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.toUHexString import java.io.ByteArrayOutputStream import java.io.DataInputStream @@ -77,7 +78,7 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray, 25 -> MessageType.ANONYMOUS else -> { - println("id=$id") + MiraiLogger debug ("ServerGroupMessageEventPacket id=$id") MessageType.OTHER } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt index dbe4d4599..980bf9961 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt @@ -3,6 +3,7 @@ package net.mamoe.mirai.network.packet import net.mamoe.mirai.network.packet.login.* import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket +import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.getAllDeclaredFields import net.mamoe.mirai.utils.hexToBytes import net.mamoe.mirai.utils.toUHexString @@ -36,7 +37,7 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { 271, 207 -> return ServerLoginResponseResendPacketEncrypted(stream, when (idHex) { "08 36 31 03" -> ServerLoginResponseResendPacket.Flag.`08 36 31 03` else -> { - println("flag=$idHex"); ServerLoginResponseResendPacket.Flag.OTHER + MiraiLogger debug ("ServerLoginResponseResendPacketEncrypted: flag=$idHex"); ServerLoginResponseResendPacket.Flag.OTHER } }) 871 -> return ServerLoginResponseVerificationCodePacketEncrypted(stream) @@ -47,16 +48,16 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { } return ServerLoginResponseFailedPacket(when (bytes.size) { - 319 -> ServerLoginResponseFailedPacket.State.WRONG_PASSWORD - 135 -> ServerLoginResponseFailedPacket.State.RETYPE_PASSWORD - 279 -> ServerLoginResponseFailedPacket.State.BLOCKED - 263 -> ServerLoginResponseFailedPacket.State.UNKNOWN_QQ_NUMBER - 551, 487 -> ServerLoginResponseFailedPacket.State.DEVICE_LOCK - 359 -> ServerLoginResponseFailedPacket.State.TAKEN_BACK + 319 -> LoginState.WRONG_PASSWORD + 135 -> LoginState.RETYPE_PASSWORD + 279 -> LoginState.BLOCKED + 263 -> LoginState.UNKNOWN_QQ_NUMBER + 551, 487 -> LoginState.DEVICE_LOCK + 359 -> LoginState.TAKEN_BACK //unknown - 63 -> throw IllegalArgumentException(bytes.size.toString() + " (Unknown error)")//可能是已经完成登录, 服务器拒绝第二次登录 - 351 -> throw IllegalArgumentException(bytes.size.toString() + " (Illegal package data)")//包数据有误 + 63 -> throw IllegalArgumentException(bytes.size.toString() + " (Unknown error)") + 351 -> throw IllegalArgumentException(bytes.size.toString() + " (Illegal package data or Unknown error)")//包数据有误 else -> throw IllegalArgumentException(bytes.size.toString()) }, stream) @@ -88,6 +89,7 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { } } + @ExperimentalUnsignedTypes override fun toString(): String { return this.javaClass.simpleName + this.getAllDeclaredFields().joinToString(", ", "{", "}") { it.trySetAccessible(); it.name + "=" + it.get(this).let { value -> diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt index d79cabe9f..ba3e8d377 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt @@ -6,6 +6,9 @@ import net.mamoe.mirai.utils.* import java.io.DataInputStream +/** + * 客户端请求验证码图片数据的第几部分 + */ @ExperimentalUnsignedTypes @PacketId("00 BA 31") class ClientVerificationCodeTransmissionRequestPacket( @@ -40,11 +43,13 @@ class ClientVerificationCodeTransmissionRequestPacket( } /** + * 服务器发送验证码图片文件一部分过来 + * * @author Him188moe */ -class ServerVerificationCodeTransmissionPacket(input: DataInputStream, val dataSize: Int, val packetId: ByteArray) : ServerVerificationCodePacket(input) { +class ServerVerificationCodeTransmissionPacket(input: DataInputStream, private val dataSize: Int, private val packetId: ByteArray) : ServerVerificationCodePacket(input) { - lateinit var verificationCodePart2: ByteArray + lateinit var verificationCodePartN: ByteArray lateinit var verificationToken: ByteArray//56bytes var transmissionCompleted: Boolean = false//验证码是否已经传输完成 lateinit var token00BA: ByteArray//40 bytes @@ -55,10 +60,10 @@ class ServerVerificationCodeTransmissionPacket(input: DataInputStream, val dataS this.verificationToken = this.input.readNBytesAt(10, 56) val length = this.input.readShortAt(66) - this.verificationCodePart2 = this.input.readNBytes(length) + this.verificationCodePartN = this.input.readNBytes(length) this.input.skip(2) - this.transmissionCompleted = this.input.readBoolean() + this.transmissionCompleted = this.input.readBoolean().not() this.token00BA = this.input.readNBytesAt(dataSize - 57, 40) this.count = byteArrayOf(0, 0, packetId[2], packetId[3]).toUHexString().hexToInt() @@ -66,6 +71,8 @@ class ServerVerificationCodeTransmissionPacket(input: DataInputStream, val dataS } /** + * 暂不了解意义 + * * @author Him188moe */ class ServerVerificationCodeRepeatPacket(input: DataInputStream) : ServerVerificationCodePacket(input) { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt new file mode 100644 index 000000000..7be53ad7d --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt @@ -0,0 +1,18 @@ +package net.mamoe.mirai.network.packet.login + +/** + * @author Him188moe + */ +enum class LoginState { + SUCCEED, + + WRONG_PASSWORD, + // UNKNOWN,//? 要再次发送某数据包 + RETYPE_PASSWORD,//similar to [WRONG_PASSWORD] + BLOCKED,//你的帐号存在被盗风险,已进入保护模式 + UNKNOWN_QQ_NUMBER,//你输入的帐号不存在 + DEVICE_LOCK,//设备锁 + TAKEN_BACK,//被回收 + // VERIFICATION_CODE,//需要验证码 + // SUCCEED, +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseFailedPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseFailedPacket.kt index 5276b7f39..6c1915094 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseFailedPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseFailedPacket.kt @@ -6,19 +6,7 @@ import java.io.DataInputStream /** * @author Him188moe */ -class ServerLoginResponseFailedPacket(val state: State, input: DataInputStream) : ServerPacket(input) { - enum class State { - WRONG_PASSWORD, - // UNKNOWN,//? 要再次发送某数据包 - RETYPE_PASSWORD,//similar to [WRONG_PASSWORD] - BLOCKED,//你的帐号存在被盗风险,已进入保护模式 - UNKNOWN_QQ_NUMBER,//你输入的帐号不存在 - DEVICE_LOCK,//设备锁 - TAKEN_BACK,//被回收 - // VERIFICATION_CODE,//需要验证码 - // SUCCEED, - } - +class ServerLoginResponseFailedPacket(val loginState: LoginState, input: DataInputStream) : ServerPacket(input) { override fun decode() { } } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt index 7372b1ff8..0303fcb6e 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt @@ -6,8 +6,6 @@ import net.mamoe.mirai.network.packet.dataInputStream import net.mamoe.mirai.network.packet.goto import net.mamoe.mirai.util.TestedSuccessfully import net.mamoe.mirai.utils.TEACryptor -import net.mamoe.mirai.utils.hexToUBytes -import net.mamoe.mirai.utils.toUHexString import java.io.DataInputStream /** @@ -61,17 +59,4 @@ class ServerLoginResponseResendPacketEncrypted(input: DataInputStream, private v data = TEACryptor.decrypt(data, tgtgtKey) return ServerLoginResponseResendPacket(data.dataInputStream(), flag) } -} - -fun main() { - val tgtgtkey = "9E 83 61 FF 18 61 4B 77 34 FE 1C 9C E2 03 B4 F2".hexToUBytes() - - ServerLoginResponseResendPacketEncrypted("02 37 13 08 36 31 03 76 E4 B8 DD 00 00 00 94 9B 87 00 87 7F 9E D0 E5 6A F6 17 41 02 0C AA F3 AC C8 CF 4E C6 9D EC FA 6C BD F8 7C 4B A5 28 80 CC DE B5 0A 41 8E 63 CE 5E 30 D8 A6 83 92 0E 2E 5C 35 E5 6E 62 3D FE 17 DD 7C 47 9A AD EF F0 F7 2A 6F 21 32 99 1B 6D E1 DA BE 68 2F 26 A9 93 DE 1B 4F 11 F0 AF A1 06 7B 85 53 46 D2 A3 DD A6 BE F2 76 8A 61 BF 15 FD 17 C4 45 DB EC 05 51 56 46 63 48 87 49 79 0D 40 DF 9D D9 99 93 EC D0 44 7B 4A 79 EB BD 08 10 18 29 0E 85 EE 26 A0 CD 40 00 2F 3E ED F4 A4 C3 01 5E 82 F5 A8 02 FA 70 EB F2 07 AD FF 0E DA 08 7A 3A FE B6 F4 5D 98 18 F7 58 C2 19 21 AF 29 D2 95 16 CE C4 A3 5F B0 E6 23 C2 B2 C6 5F 03 42 C2 44 C2 B0 A0 3F 95 8E 89 EF FC EC E4 BF 03 CB DA 9C D3 84 3F 9B A0 F1 B4 14 6E 23 D5 74 79 6F 89 DA B8 33 DB EF 0B 21 E1 27 27 57 8B 56 CB D9 BF C2 A8 25 6E 48 23 EB 31 9D 03".hexToUBytes().toByteArray().dataInputStream(), ServerLoginResponseResendPacket.Flag.`08 36 31 03`).decrypt(tgtgtkey.toByteArray()).let { it.decode();println(it._0836_tlv0006_encr.toUHexString()) } - - val data = "94 9B 87 00 87 7F 9E D0 E5 6A F6 17 41 02 0C AA F3 AC C8 CF 4E C6 9D EC FA 6C BD F8 7C 4B A5 28 80 CC DE B5 0A 41 8E 63 CE 5E 30 D8 A6 83 92 0E 2E 5C 35 E5 6E 62 3D FE 17 DD 7C 47 9A AD EF F0 F7 2A 6F 21 32 99 1B 6D E1 DA BE 68 2F 26 A9 93 DE 1B 4F 11 F0 AF A1 06 7B 85 53 46 D2 A3 DD A6 BE F2 76 8A 61 BF 15 FD 17 C4 45 DB EC 05 51 56 46 63 48 87 49 79 0D 40 DF 9D D9 99 93 EC D0 44 7B 4A 79 EB BD 08 10 18 29 0E 85 EE 26 A0 CD 40 00 2F 3E ED F4 A4 C3 01 5E 82 F5 A8 02 FA 70 EB F2 07 AD FF 0E DA 08 7A 3A FE B6 F4 5D 98 18 F7 58 C2 19 21 AF 29 D2 95 16 CE C4 A3 5F B0 E6 23 C2 B2 C6 5F 03 42 C2 44 C2 B0 A0 3F 95 8E 89 EF FC EC E4 BF 03 CB DA 9C D3 84 3F 9B A0 F1 B4 14 6E 23 D5 74 79 6F 89 DA B8 33 DB EF 0B 21 E1 27 27 57 8B 56 CB D9 BF C2 A8 25 6E 48 23 EB 31 9D".hexToUBytes() - - val d1 = TEACryptor.CRYPTOR_SHARE_KEY.decrypt(data.toByteArray()) - - ServerLoginResponseResendPacket(TEACryptor.decrypt(d1, tgtgtkey.toByteArray()).dataInputStream(), ServerLoginResponseResendPacket.Flag.`08 36 31 03`).let { it.decode();println(it._0836_tlv0006_encr.toUHexString()) } - } \ No newline at end of file From 512d27b843bab738d24313e01e6e4535b7eb1495 Mon Sep 17 00:00:00 2001 From: Him188moe Date: Wed, 4 Sep 2019 22:18:36 +0800 Subject: [PATCH 04/19] Updated robot & network structure --- .../java/net/mamoe/mirai/MiraiServer.java | 6 +- .../src/main/java/net/mamoe/mirai/Robot.java | 108 +++++++++------- .../java/net/mamoe/mirai/contact/Contact.kt | 4 +- .../java/net/mamoe/mirai/contact/Group.kt | 5 +- .../main/java/net/mamoe/mirai/contact/QQ.kt | 9 +- .../java/net/mamoe/mirai/network/Protocol.kt | 44 +++++-- .../mirai/network/RobotNetworkHandler.kt | 115 ++++++++++-------- .../mamoe/mirai/network/packet/AccountInfo.kt | 22 ++-- .../mirai/network/packet/ClientPacket.kt | 24 ++-- .../mamoe/mirai/network/packet/Heartbeat.kt | 6 +- .../mirai/network/packet/MessageEvent.kt | 84 ------------- .../net/mamoe/mirai/network/packet/SKey.kt | 22 ++-- .../mamoe/mirai/network/packet/ServerEvent.kt | 65 +++++++++- .../mirai/network/packet/ServerPacket.kt | 44 ++++--- .../net/mamoe/mirai/network/packet/Session.kt | 30 ++--- .../net/mamoe/mirai/network/packet/Touch.kt | 37 ++---- .../mirai/network/packet/VerificationCode.kt | 39 +++--- ...t.kt => ClientChangeOnlineStatusPacket.kt} | 6 +- .../{ClientLoginPacket.kt => ClientLogin.kt} | 20 +-- ...rverLoginResponsePasswordVerifiedPacket.kt | 29 ++--- .../login/ServerLoginResponseResendPacket.kt | 23 +--- ...LoginResponseVerificationCodeInitPacket.kt | 28 +++-- .../packet/login/ServerLoginSuccessPacket.kt | 8 +- .../message/ClientSendFriendMessagePacket.kt | 7 +- .../message/ClientSendGroupMessagePacket.kt | 28 +---- .../mamoe/mirai/utils/ClientLoginStatus.java | 8 +- .../net/mamoe/mirai/utils/RobotAccount.java | 17 +++ .../mirai/utils/{TEACryptor.java => TEA.java} | 22 ++-- 28 files changed, 422 insertions(+), 438 deletions(-) delete mode 100644 mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt rename mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/{ClientLoginStatusPacket.kt => ClientChangeOnlineStatusPacket.kt} (83%) rename mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/{ClientLoginPacket.kt => ClientLogin.kt} (91%) create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/utils/RobotAccount.java rename mirai-core/src/main/java/net/mamoe/mirai/utils/{TEACryptor.java => TEA.java} (91%) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java index af7dcfdc7..9d9074da2 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java @@ -4,7 +4,6 @@ import lombok.Getter; import net.mamoe.mirai.event.MiraiEventManager; import net.mamoe.mirai.event.events.server.ServerDisableEvent; import net.mamoe.mirai.event.events.server.ServerEnableEvent; -import net.mamoe.mirai.network.RobotNetworkHandler; import net.mamoe.mirai.network.packet.login.LoginState; import net.mamoe.mirai.task.MiraiTaskManager; import net.mamoe.mirai.utils.LoggerTextFormat; @@ -36,7 +35,7 @@ public class MiraiServer { @Getter //is running under UNIX private boolean unix; - @Getter//file path + @Getter//file pathq public File parentFolder; @Getter @@ -121,8 +120,7 @@ public class MiraiServer { this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> { try { Robot robot = new Robot(section); - RobotNetworkHandler robotNetworkHandler = robot.getNetworkHandler(); - robotNetworkHandler.tryLogin$mirai_core(state -> { + robot.network.tryLogin$mirai_core(state -> { if (state == LoginState.SUCCEED) { Robot.instances.add(robot); } else { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java index fbc066118..0c3a1c169 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java @@ -5,21 +5,58 @@ import net.mamoe.mirai.contact.Group; import net.mamoe.mirai.contact.QQ; import net.mamoe.mirai.network.RobotNetworkHandler; import net.mamoe.mirai.utils.ContactList; +import net.mamoe.mirai.utils.RobotAccount; import net.mamoe.mirai.utils.config.MiraiConfigSection; +import org.jetbrains.annotations.NotNull; import java.io.Closeable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; +import java.util.*; -public class Robot implements Closeable { +/** + * Robot that is the base of the whole program. + * It contains a {@link ContactSystem}, which manage contacts such as {@link QQ} and {@link Group}. + */ +public final class Robot implements Closeable { public static final List instances = Collections.synchronizedList(new LinkedList<>()); - private final long qqNumber; - private final String password; - @Getter - private final RobotNetworkHandler networkHandler; + public final RobotAccount account; + + public final ContactSystem contacts = new ContactSystem(); + + public final RobotNetworkHandler network; + + /** + * Robot 联系人管理. + * + * @see Robot#contacts + */ + public final class ContactSystem { + private final ContactList groups = new ContactList<>(); + private final ContactList qqs = new ContactList<>(); + + private ContactSystem() { + + } + + public QQ getQQ(long qqNumber) { + if (!this.qqs.containsKey(qqNumber)) { + this.qqs.put(qqNumber, new QQ(Robot.this, qqNumber)); + } + return this.qqs.get(qqNumber); + } + + public Group getGroupByNumber(long groupNumber) { + if (!this.groups.containsKey(groupNumber)) { + this.groups.put(groupNumber, new Group(Robot.this, groupNumber)); + } + return groups.get(groupNumber); + } + + public Group getGroupById(long groupId) { + return getGroupByNumber(Group.Companion.groupIdToNumber(groupId)); + } + } + /** * Ref list @@ -27,57 +64,36 @@ public class Robot implements Closeable { @Getter private final List owners; - private final ContactList groups = new ContactList<>(); - private final ContactList qqs = new ContactList<>(); - - public void close() { - this.networkHandler.close(); - this.owners.clear(); - this.groups.values().forEach(Group::close); - this.groups.clear(); - this.qqs.clear(); - } - public boolean isOwnBy(String ownerName) { return owners.contains(ownerName); } - public long getQQNumber() { - return qqNumber; - } - public Robot(MiraiConfigSection data) throws Throwable { this( - data.getLongOrThrow("account", () -> new IllegalArgumentException("account")), - data.getStringOrThrow("password", () -> new IllegalArgumentException("password")), + new RobotAccount( + data.getLongOrThrow("account", () -> new IllegalArgumentException("account")), + data.getStringOrThrow("password", () -> new IllegalArgumentException("password")) + ), data.getAsOrDefault("owners", ArrayList::new) ); - } - public Robot(long qqNumber, String password, List owners) { - this.qqNumber = qqNumber; - this.password = password; + public Robot(@NotNull RobotAccount account, @NotNull List owners) { + Objects.requireNonNull(account); + Objects.requireNonNull(owners); + this.account = account; this.owners = Collections.unmodifiableList(owners); - this.networkHandler = new RobotNetworkHandler(this, this.qqNumber, this.password); + this.network = new RobotNetworkHandler(this); } - public QQ getQQ(long qqNumber) { - if (!this.qqs.containsKey(qqNumber)) { - this.qqs.put(qqNumber, new QQ(qqNumber)); - } - return this.qqs.get(qqNumber); + + public void close() { + this.network.close(); + this.owners.clear(); + this.contacts.groups.values().forEach(Group::close); + this.contacts.groups.clear(); + this.contacts.qqs.clear(); } - public Group getGroup(long groupNumber) { - if (!this.groups.containsKey(groupNumber)) { - this.groups.put(groupNumber, new Group(groupNumber)); - } - return groups.get(groupNumber); - } - - public Group getGroupByGroupId(long groupId) { - return getGroup(Group.Companion.groupIdToNumber(groupId)); - } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt index fa1a475c1..ab33c4d10 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt @@ -1,14 +1,16 @@ package net.mamoe.mirai.contact +import net.mamoe.mirai.Robot import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.defaults.PlainText /** * A contact is a [QQ] or a [Group] for one particular [Robot] instance only. * + * @param robot Owner [Robot] * @author Him188moe */ -abstract class Contact(val number: Long) { +abstract class Contact(val robot: Robot, val number: Long) { /** * Async diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt index 3d23d53b7..3c14af642 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt @@ -1,15 +1,16 @@ package net.mamoe.mirai.contact +import net.mamoe.mirai.Robot import net.mamoe.mirai.message.Message import net.mamoe.mirai.utils.ContactList import java.io.Closeable -class Group(number: Long) : Contact(number), Closeable { +class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable { val groupId = groupNumberToId(number) val members = ContactList() override fun sendMessage(message: Message) { - + robot.network.packetSystem.sendGroupMessage(this, message) } override fun sendXMLMessage(message: String) { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt index e7a0cf537..efab8f4a6 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt @@ -1,15 +1,18 @@ package net.mamoe.mirai.contact +import net.mamoe.mirai.Robot import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.defaults.At /** + * A QQ instance helps you to receive message from or send message to. + * Notice that one QQ instance belong to one [Robot], that is, QQ instances from different [Robot] are NOT the same. + * * @author Him188moe */ -class QQ(number: Long) : Contact(number) { - +class QQ(robot: Robot, number: Long) : Contact(robot, number) { override fun sendMessage(message: Message) { - + robot.network.packetSystem.sendFriendMessage(this, message) } override fun sendXMLMessage(message: String) { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt index 258aff770..f5c4bbfb3 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt @@ -28,26 +28,44 @@ interface Protocol { const val head = "02" - const val ver = "37 13 " - const val fixVer = "03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00 " - const val tail = " 03" - const val _fixVer = "02 00 00 00 01 01 01 00 00 68 20 " - const val _0825data0 = "00 18 00 16 00 01 " - const val _0825data2 = "00 00 04 53 00 00 00 01 00 00 15 85 " - const val _0825key = "A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D" + const val ver = "37 13" + const val fixVer = "03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00" + const val tail = "03" + /** + * _fixVer + */ + const val fixVer2 = "02 00 00 00 01 01 01 00 00 68 20" + /** + * 0825data1 + */ + const val constantData0 = "00 18 00 16 00 01 " + /** + * 0825data2 + */ + const val constantData1 = "00 00 04 53 00 00 00 01 00 00 15 85 " + const val key0825 = "A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D" const val redirectionKey = "A8 F2 14 5F 58 12 60 AF 07 63 97 D6 76 B2 1A 3B" const val publicKey = "02 6D 28 41 D2 A5 6F D2 FC 3E 2A 1F 03 75 DE 6E 28 8F A8 19 3E 5F 16 49 D3" const val shareKey = "1A E9 7F 7D C9 73 75 98 AC 02 E0 80 5F A9 C6 AF" - const val _0836fix = "06 A9 12 97 B7 F8 76 25 AF AF D3 EA B4 C8 BC E7 " + const val fix0836 = "06 A9 12 97 B7 F8 76 25 AF AF D3 EA B4 C8 BC E7 " - const val _00BaKey = "C1 9C B8 C8 7B 8C 81 BA 9E 9E 7A 89 E1 7A EC 94" - const val _00BaFixKey = "69 20 D1 14 74 F5 B3 93 E4 D5 02 B3 71 1A CD 2A" + const val key00BA = "C1 9C B8 C8 7B 8C 81 BA 9E 9E 7A 89 E1 7A EC 94" + const val key00BAFix = "69 20 D1 14 74 F5 B3 93 E4 D5 02 B3 71 1A CD 2A" const val encryptKey = "“BA 42 FF 01 CF B4 FF D2 12 F0 6E A7 1B 7C B3 08”" - const val _0836_622_fix2 = "00 15 00 30 00 01 01 27 9B C7 F5 00 10 65 03 FD 8B 00 00 00 00 00 00 00 00 00 00 00 00 02 90 49 55 33 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B"; - const val _0836_622_fix1 = "03 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 01 01 03 00 19"; - const val _0836key1 = "EF 4A 36 6A 16 A8 E6 3D 2E EA BD 1F 98 C1 3C DA" + /** + * 0836_622_fix2 + */ + const val passwordSubmissionKey2 = "00 15 00 30 00 01 01 27 9B C7 F5 00 10 65 03 FD 8B 00 00 00 00 00 00 00 00 00 00 00 00 02 90 49 55 33 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B"; + /** + * 0836_622_fix1 + */ + const val passwordSubmissionKey1 = "03 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 01 01 03 00 19"; + /** + * fix_0836_1 + */ + const val key0836 = "EF 4A 36 6A 16 A8 E6 3D 2E EA BD 1F 98 C1 3C DA" private val hexToByteArrayCacheMap: MutableMap = mutableMapOf() diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index e62c95502..0a8fb4c67 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -2,33 +2,36 @@ package net.mamoe.mirai.network import net.mamoe.mirai.Robot import net.mamoe.mirai.contact.Group +import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.event.events.qq.FriendMessageEvent import net.mamoe.mirai.event.events.robot.RobotLoginSucceedEvent +import net.mamoe.mirai.message.Message import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.network.packet.login.* -import net.mamoe.mirai.network.packet.message.ClientSendGroupMessagePacket import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.task.MiraiThreadPool -import net.mamoe.mirai.utils.* +import net.mamoe.mirai.utils.ClientLoginStatus +import net.mamoe.mirai.utils.MiraiLogger +import net.mamoe.mirai.utils.getGTK +import net.mamoe.mirai.utils.lazyEncode import java.io.Closeable import java.net.DatagramPacket import java.net.DatagramSocket import java.net.InetSocketAddress import java.util.concurrent.TimeUnit - /** * A RobotNetworkHandler is used to connect with Tencent servers. * * @author Him188moe */ -@ExperimentalUnsignedTypes -internal class RobotNetworkHandler(val robot: Robot, val number: Long, private val password: String) : Closeable { +@Suppress("EXPERIMENTAL_API_USAGE")//to simplify code +internal class RobotNetworkHandler(private val robot: Robot) : Closeable { - var socket: DatagramSocket = DatagramSocket((15314 + Math.random() * 100).toInt()) + private var socket: DatagramSocket = DatagramSocket((15314 + Math.random() * 100).toInt()) - var serverIP: String = "" + private var serverIP: String = "" set(value) { serverAddress = InetSocketAddress(value, 8000) field = value @@ -45,7 +48,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v private lateinit var loginIP: String private var tgtgtKey: ByteArray? = null private var tlv0105: ByteArray - private lateinit var _0828_rec_decr_key: ByteArray + private lateinit var sessionResponseDecryptionKey: ByteArray private var verificationCodeSequence: Int = 0//这两个验证码使用 private var verificationCodeCache: ByteArray? = null//每次包只发一部分验证码来 @@ -82,10 +85,6 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v } } - - @ExperimentalUnsignedTypes - private var md5_32: ByteArray = getRandomKey(32) - /** * Try to login to server */ @@ -110,7 +109,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v if (loginHook != null) { this.loginHook = loginHook } - this.sendPacket(ClientTouchPacket(this.number, this.serverIP)) + this.sendPacket(ClientTouchPacket(this.robot.account.qqNumber, this.serverIP)) } private fun restartSocket() { @@ -151,20 +150,20 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v packet.decode() MiraiLogger info "Packet received: $packet" if (packet is ServerEventPacket) { - sendPacket(ClientMessageResponsePacket(this.number, packet.packetId, this.sessionKey, packet.eventIdentity)) + sendPacket(ClientMessageResponsePacket(this.robot.account.qqNumber, packet.packetId, this.sessionKey, packet.eventIdentity)) } when (packet) { is ServerTouchResponsePacket -> { if (packet.serverIP != null) {//redirection serverIP = packet.serverIP!! //connect(packet.serverIP!!) - sendPacket(ClientServerRedirectionPacket(packet.serverIP!!, number)) + sendPacket(ClientServerRedirectionPacket(packet.serverIP!!, this.robot.account.qqNumber)) } else {//password submission this.loginIP = packet.loginIP this.loginTime = packet.loginTime this.token0825 = packet.token0825 this.tgtgtKey = packet.tgtgtKey - sendPacket(ClientPasswordSubmissionPacket(this.number, this.password, packet.loginTime, packet.loginIP, packet.tgtgtKey, packet.token0825)) + sendPacket(ClientPasswordSubmissionPacket(this.robot.account.qqNumber, this.robot.account.password, packet.loginTime, packet.loginIP, packet.tgtgtKey, packet.token0825)) } } @@ -182,7 +181,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v if (packet.unknownBoolean != null && packet.unknownBoolean!!) { this.verificationCodeSequence = 1 - sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, this.number, this.token0825, this.verificationCodeSequence, this.token00BA)) + sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, this.robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA)) } } @@ -190,7 +189,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v is ServerVerificationCodeRepeatPacket -> {//todo 这个名字正确么 this.tgtgtKey = packet.tgtgtKeyUpdate this.token00BA = packet.token00BA - sendPacket(ClientLoginResendPacket3105(this.number, this.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA)) + sendPacket(ClientLoginResendPacket3105(this.robot.account.qqNumber, this.robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA)) } is ServerVerificationCodeTransmissionPacket -> { @@ -210,26 +209,26 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v this.verificationCodeCache TODO("验证码好了") } else { - sendPacket(ClientVerificationCodeTransmissionRequestPacket(this.verificationCodeCacheCount, this.number, this.token0825, this.verificationCodeSequence, this.token00BA)) + sendPacket(ClientVerificationCodeTransmissionRequestPacket(this.verificationCodeCacheCount, this.robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA)) } } is ServerLoginResponseSuccessPacket -> { - this._0828_rec_decr_key = packet._0828_rec_decr_key - sendPacket(ClientSessionRequestPacket(this.number, this.serverIP, this.loginIP, this.md5_32, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105)) + this.sessionResponseDecryptionKey = packet._0828_rec_decr_key + sendPacket(ClientSessionRequestPacket(this.robot.account.qqNumber, this.serverIP, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105)) } //是ClientPasswordSubmissionPacket之后服务器回复的 is ServerLoginResponseResendPacket -> { - if (packet.tokenUnknown != null) { - //this.token00BA = packet.token00BA!! - //println("token00BA changed!!! to " + token00BA.toUByteArray()) - } + //if (packet.tokenUnknown != null) { + //this.token00BA = packet.token00BA!! + //println("token00BA changed!!! to " + token00BA.toUByteArray()) + //} if (packet.flag == ServerLoginResponseResendPacket.Flag.`08 36 31 03`) { this.tgtgtKey = packet.tgtgtKey sendPacket(ClientLoginResendPacket3104( - this.number, - this.password, + this.robot.account.qqNumber, + this.robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey!!, @@ -242,8 +241,8 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v )) } else { sendPacket(ClientLoginResendPacket3106( - this.number, - this.password, + this.robot.account.qqNumber, + this.robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey!!, @@ -261,7 +260,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v is ServerSessionKeyResponsePacket -> { this.sessionKey = packet.sessionKey MiraiThreadPool.getInstance().scheduleWithFixedDelay({ - sendPacket(ClientHeartbeatPacket(this.number, this.sessionKey)) + sendPacket(ClientHeartbeatPacket(this.robot.account.qqNumber, this.sessionKey)) }, 90000, 90000, TimeUnit.MILLISECONDS) RobotLoginSucceedEvent(robot).broadcast() @@ -270,24 +269,24 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v }, 2, TimeUnit.SECONDS) this.tlv0105 = packet.tlv0105 - sendPacket(ClientLoginStatusPacket(this.number, this.sessionKey, ClientLoginStatus.ONLINE)) + sendPacket(ClientChangeOnlineStatusPacket(this.robot.account.qqNumber, this.sessionKey, ClientLoginStatus.ONLINE)) } is ServerLoginSuccessPacket -> { loginState = LoginState.SUCCEED - sendPacket(ClientSKeyRequestPacket(this.number, this.sessionKey)) + sendPacket(ClientSKeyRequestPacket(this.robot.account.qqNumber, this.sessionKey)) } is ServerSKeyResponsePacket -> { this.sKey = packet.sKey - this.cookies = "uin=o" + this.number + ";skey=" + this.sKey + ";" + this.cookies = "uin=o" + this.robot.account.qqNumber + ";skey=" + this.sKey + ";" MiraiThreadPool.getInstance().scheduleWithFixedDelay({ - sendPacket(ClientSKeyRefreshmentRequestPacket(this.number, this.sessionKey)) + sendPacket(ClientSKeyRefreshmentRequestPacket(this.robot.account.qqNumber, this.sessionKey)) }, 1800000, 1800000, TimeUnit.MILLISECONDS) this.gtk = getGTK(sKey) - sendPacket(ClientAccountInfoRequestPacket(this.number, this.sessionKey)) + sendPacket(ClientAccountInfoRequestPacket(this.robot.account.qqNumber, this.sessionKey)) } is ServerHeartbeatResponsePacket -> { @@ -304,17 +303,12 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v return } - FriendMessageEvent(this.robot, this.robot.getQQ(packet.qq), packet.message) + FriendMessageEvent(this.robot, this.robot.contacts.getQQ(packet.qq), packet.message) } is ServerGroupMessageEventPacket -> { - //group message - if (packet.message == "牛逼") { - sendPacket(ClientSendGroupMessagePacket(Group.groupNumberToId(packet.groupNumber), this.number, this.sessionKey, "牛逼!")) - } - - //todo - //GroupMessageEvent(this.robot, this.robot.getGroup(packet.groupNumber), this.robot.getQQ(packet.qq), packet.message) + //todo message chain + //GroupMessageEvent(this.robot, this.robot.contacts.getGroupByNumber(packet.groupNumber), this.robot.contacts.getQQ(packet.qq), packet.message) } is UnknownServerEventPacket -> { @@ -329,17 +323,17 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v } - is ServerMessageEventPacketRaw -> onPacketReceived(packet.analyze()) + is ServerEventPacket.Raw -> onPacketReceived(packet.distribute()) - is ServerVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt()) - is ServerLoginResponseVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt()) - is ServerLoginResponseResendPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) - is ServerLoginResponseSuccessPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) - is ServerSessionKeyResponsePacketEncrypted -> onPacketReceived(packet.decrypt(this._0828_rec_decr_key)) - is ServerTouchResponsePacketEncrypted -> onPacketReceived(packet.decrypt()) - is ServerSKeyResponsePacketEncrypted -> onPacketReceived(packet.decrypt(this.sessionKey)) - is ServerAccountInfoResponsePacketEncrypted -> onPacketReceived(packet.decrypt(this.sessionKey)) - is ServerMessageEventPacketRawEncoded -> onPacketReceived(packet.decrypt(this.sessionKey)) + is ServerVerificationCodePacket.Encrypted -> onPacketReceived(packet.decrypt()) + is ServerLoginResponseVerificationCodeInitPacket.Encrypted -> onPacketReceived(packet.decrypt()) + is ServerLoginResponseResendPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) + is ServerLoginResponseSuccessPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) + is ServerSessionKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionResponseDecryptionKey)) + is ServerTouchResponsePacket.Encrypted -> onPacketReceived(packet.decrypt()) + is ServerSKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey)) + is ServerAccountInfoResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey)) + is ServerEventPacket.Raw.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey)) is ServerSendFriendMessageResponsePacket, @@ -352,6 +346,21 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v } + internal val packetSystem: PacketSystem = PacketSystem() + + inner class PacketSystem { + fun sendFriendMessage(qq: QQ, message: Message) { + TODO() + //sendPacket(ClientSendFriendMessagePacket(robot.account.qqNumber, qq.number, sessionKey, message)) + } + + fun sendGroupMessage(group: Group, message: Message): Unit { + TODO() + //sendPacket(ClientSendGroupMessagePacket(group.groupId, robot.account.qqNumber, sessionKey, message)) + } + + } + @ExperimentalUnsignedTypes fun sendPacket(packet: ClientPacket) { MiraiThreadPool.getInstance().submit { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt index 90d50c89e..67d5d3113 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt @@ -1,7 +1,7 @@ package net.mamoe.mirai.network.packet import net.mamoe.mirai.network.Protocol -import net.mamoe.mirai.utils.TEACryptor +import net.mamoe.mirai.utils.TEA import java.io.DataInputStream /** @@ -18,7 +18,7 @@ class ClientAccountInfoRequestPacket( override fun encode() { this.writeRandom(2)//part of packet id this.writeQQ(qq) - this.writeHex(Protocol._fixVer) + this.writeHex(Protocol.fixVer2) this.encryptAndWrite(sessionKey) { it.writeByte(0x88) it.writeQQ(qq) @@ -27,6 +27,7 @@ class ClientAccountInfoRequestPacket( } } +@PacketId("00 5C") class ServerAccountInfoResponsePacket(input: DataInputStream) : ServerPacket(input) { //等级 //升级剩余活跃天数 @@ -34,16 +35,13 @@ class ServerAccountInfoResponsePacket(input: DataInputStream) : ServerPacket(inp override fun decode() { } -} -class ServerAccountInfoResponsePacketEncrypted(inputStream: DataInputStream) : ServerPacket(inputStream) { - override fun decode() { - - } - - fun decrypt(sessionKey: ByteArray): ServerAccountInfoResponsePacket { - this.input goto 14 - val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) } - return ServerAccountInfoResponsePacket(TEACryptor.decrypt(data, sessionKey).dataInputStream()); + @PacketId("00 5C") + class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) { + fun decrypt(sessionKey: ByteArray): ServerAccountInfoResponsePacket { + this.input goto 14 + val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) } + return ServerAccountInfoResponsePacket(TEA.decrypt(data, sessionKey).dataInputStream()); + } } } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt index 7ea56c462..2435134d0 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt @@ -108,15 +108,15 @@ fun DataOutputStream.writeVarInt(dec: UInt) { } fun DataOutputStream.encryptAndWrite(byteArray: ByteArray, key: ByteArray) { - this.write(TEACryptor.encrypt(byteArray, key)) + this.write(TEA.encrypt(byteArray, key)) } -fun DataOutputStream.encryptAndWrite(byteArray: ByteArray, cryptor: TEACryptor) { +fun DataOutputStream.encryptAndWrite(byteArray: ByteArray, cryptor: TEA) { this.write(cryptor.encrypt(byteArray)) } fun DataOutputStream.encryptAndWrite(key: ByteArray, encoder: (ByteArrayDataOutputStream) -> Unit) { - this.write(TEACryptor.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() }, key)) + this.write(TEA.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() }, key)) } @ExperimentalUnsignedTypes @@ -124,7 +124,7 @@ fun DataOutputStream.encryptAndWrite(keyHex: String, encoder: (ByteArrayDataOutp this.encryptAndWrite(keyHex.hexToBytes(), encoder) } -fun DataOutputStream.encryptAndWrite(cryptor: TEACryptor, encoder: (ByteArrayDataOutputStream) -> Unit) { +fun DataOutputStream.encryptAndWrite(cryptor: TEA, encoder: (ByteArrayDataOutputStream) -> Unit) { this.write(cryptor.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() })) } @@ -132,24 +132,24 @@ fun DataOutputStream.encryptAndWrite(cryptor: TEACryptor, encoder: (ByteArrayDat @Throws(IOException::class) fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray) { ByteArrayDataOutputStream().let { - it.writeHex("12 12 12 12")//it.writeRandom(4) todo + it.writeRandom(4) it.writeHex("00 02") it.writeQQ(qq) - it.writeHex(Protocol._0825data2) + it.writeHex(Protocol.constantData1) it.writeHex("00 00 01") - val md5_1 = md5(password); - val md5_2 = md5(md5_1 + "00 00 00 00".hexToBytes() + qq.toUInt().toByteArray()) - it.write(md5_1) + val firstMD5 = md5(password) + val secondMD5 = md5(firstMD5 + "00 00 00 00".hexToBytes() + qq.toUInt().toByteArray()) + it.write(firstMD5) it.writeInt(loginTime) - it.writeByte(0); + it.writeByte(0) it.writeZero(4 * 3) it.writeIP(loginIP) it.writeZero(8) it.writeHex("00 10") it.writeHex("15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B") it.write(tgtgtKey) - this.write(TEACryptor.encrypt(it.toByteArray(), md5_2)) + this.write(TEA.encrypt(it.toByteArray(), secondMD5)) } } @@ -216,7 +216,7 @@ fun Int.toLByteArray(): ByteArray = byteArrayOf( ) @ExperimentalUnsignedTypes -fun Int.toHexString(separator: String = " "): String = this.toByteArray().toUByteArray().toUHexString(separator); +fun Int.toHexString(separator: String = " "): String = this.toByteArray().toUByteArray().toUHexString(separator) internal fun md5(str: String): ByteArray = MessageDigest.getInstance("MD5").digest(str.toByteArray()) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt index d8b1b8040..9fcd36304 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt @@ -24,8 +24,4 @@ class ClientHeartbeatPacket( } } -class ServerHeartbeatResponsePacket(input: DataInputStream) : ServerPacket(input) { - override fun decode() { - - } -} \ No newline at end of file +class ServerHeartbeatResponsePacket(input: DataInputStream) : ServerPacket(input) \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt deleted file mode 100644 index 001cf7571..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt +++ /dev/null @@ -1,84 +0,0 @@ -package net.mamoe.mirai.network.packet - -import net.mamoe.mirai.network.Protocol -import net.mamoe.mirai.utils.TEACryptor -import net.mamoe.mirai.utils.toUHexString -import java.io.DataInputStream - - -/** - * 告知服务器已经收到数据 - */ -@PacketId("")//随后写入 -@ExperimentalUnsignedTypes -class ClientMessageResponsePacket( - private val qq: Long, - private val packetIdFromServer: ByteArray, - private val sessionKey: ByteArray, - private val eventIdentity: ByteArray -) : ClientPacket() { - override fun encode() { - this.write(packetIdFromServer) - this.writeQQ(qq) - this.writeHex(Protocol._fixVer) - this.encryptAndWrite(sessionKey) { - it.write(eventIdentity) - } - } -} - - -/** - * 群聊和好友消息分发 - */ -@PacketId("00 17") -class ServerMessageEventPacketRaw( - input: DataInputStream, - private val dataLength: Int, - private val packetId: ByteArray -) : ServerPacket(input) { - lateinit var type: ByteArray; - lateinit var eventIdentity: ByteArray; - - override fun decode() { - eventIdentity = this.input.readNBytes(16) - type = this.input.goto(18).readNBytes(2) - } - - fun analyze(): ServerEventPacket = when (val typeHex = type.toUHexString()) { - "00 C4" -> { - if (this.input.goto(33).readBoolean()) { - ServerAndroidOnlineEventPacket(this.input, packetId, eventIdentity) - } else { - ServerAndroidOfflineEventPacket(this.input, packetId, eventIdentity) - } - } - "00 2D" -> ServerGroupUploadFileEventPacket(this.input, packetId, eventIdentity) - - "00 52" -> ServerGroupMessageEventPacket(this.input, packetId, eventIdentity) - - "00 A6" -> ServerFriendMessageEventPacket(this.input, packetId, eventIdentity) - - //"02 10", "00 12" -> ServerUnknownEventPacket(this.input, packetId, eventIdentity) - - else -> UnknownServerEventPacket(this.input, packetId, eventIdentity) - } -} - -class UnknownServerEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) - -@PacketId("00 17") -class ServerMessageEventPacketRawEncoded(input: DataInputStream, val packetId: ByteArray) : ServerPacket(input) { - - - override fun decode() { - - } - - fun decrypt(sessionKey: ByteArray): ServerMessageEventPacketRaw { - this.input goto 14 - val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) } - return ServerMessageEventPacketRaw(TEACryptor.decrypt(data, sessionKey).dataInputStream(), data.size, packetId); - } - -} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt index 76b181fca..4ffb53ca3 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt @@ -1,7 +1,7 @@ package net.mamoe.mirai.network.packet import net.mamoe.mirai.network.Protocol -import net.mamoe.mirai.utils.TEACryptor +import net.mamoe.mirai.utils.TEA import java.io.DataInputStream @@ -18,7 +18,7 @@ class ClientSKeyRequestPacket( this.writeRandom(2)//part of packet id this.writeQQ(qq) - this.writeHex(Protocol._fixVer) + this.writeHex(Protocol.fixVer2) this.encryptAndWrite(sessionKey) { it.writeHex("33 00 05 00 08 74 2E 71 71 2E 63 6F 6D 00 0A 71 75 6E 2E 71 71 2E 63 6F 6D 00 0C 71 7A 6F 6E 65 2E 71 71 2E 63 6F 6D 00 0C 6A 75 62 61 6F 2E 71 71 2E 63 6F 6D 00 09 6B 65 2E 71 71 2E 63 6F 6D") } @@ -52,19 +52,13 @@ class ServerSKeyResponsePacket(input: DataInputStream) : ServerPacket(input) { override fun decode() { this.sKey = String(this.input.goto(4).readNBytes(10)) } -} -/** - * @author Him188moe - */ -class ServerSKeyResponsePacketEncrypted(inputStream: DataInputStream) : ServerPacket(inputStream) { - override fun decode() { - } - - fun decrypt(sessionKey: ByteArray): ServerSKeyResponsePacket { - this.input goto 14 - val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) } - return ServerSKeyResponsePacket(TEACryptor.decrypt(data, sessionKey).dataInputStream()); + class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) { + fun decrypt(sessionKey: ByteArray): ServerSKeyResponsePacket { + this.input goto 14 + val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) } + return ServerSKeyResponsePacket(TEA.decrypt(data, sessionKey).dataInputStream()); + } } } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt index acf94031d..ec54aeed5 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt @@ -2,6 +2,7 @@ package net.mamoe.mirai.network.packet import net.mamoe.mirai.message.defaults.MessageChain import net.mamoe.mirai.message.defaults.PlainText +import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.toUHexString import java.io.ByteArrayOutputStream @@ -9,15 +10,50 @@ import java.io.DataInputStream import java.util.zip.GZIPInputStream /** + * Packet id: `00 CE` or `00 17` + * * @author Him188moe */ open class ServerEventPacket(input: DataInputStream, val packetId: ByteArray, val eventIdentity: ByteArray) : ServerPacket(input) { + @PacketId("00 17") + class Raw(input: DataInputStream, private val packetId: ByteArray) : ServerPacket(input) { + @ExperimentalUnsignedTypes + fun distribute(): ServerEventPacket { + val eventIdentity = this.input.readNBytes(16) + val type = this.input.goto(18).readNBytes(2) - override fun decode() { + return when (type.toUHexString()) { + "00 C4" -> { + if (this.input.goto(33).readBoolean()) { + ServerAndroidOnlineEventPacket(this.input, packetId, eventIdentity) + } else { + ServerAndroidOfflineEventPacket(this.input, packetId, eventIdentity) + } + } + "00 2D" -> ServerGroupUploadFileEventPacket(this.input, packetId, eventIdentity) + "00 52" -> ServerGroupMessageEventPacket(this.input, packetId, eventIdentity) + + "00 A6" -> ServerFriendMessageEventPacket(this.input, packetId, eventIdentity) + + //"02 10", "00 12" -> ServerUnknownEventPacket(this.input, packetId, eventIdentity) + + else -> UnknownServerEventPacket(this.input, packetId, eventIdentity) + } + } + + @PacketId("00 17") + class Encrypted(input: DataInputStream, private val packetId: ByteArray) : ServerPacket(input) { + fun decrypt(sessionKey: ByteArray): Raw = Raw(decryptBy(sessionKey), packetId) + } } } +/** + * Unknown event + */ +class UnknownServerEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) + /** * Android 客户端上线 */ @@ -32,7 +68,7 @@ class ServerAndroidOfflineEventPacket(input: DataInputStream, packetId: ByteArra * 群文件上传 */ class ServerGroupUploadFileEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) { - lateinit var xmlMessage: String + private lateinit var xmlMessage: String override fun decode() { xmlMessage = String(this.input.goto(65).readNBytes(this.input.goto(60).readShort().toInt())) @@ -147,7 +183,6 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray var qq: Long = 0 lateinit var message: MessageChain - @ExperimentalUnsignedTypes override fun decode() { //start at Sep1.0:27 @@ -166,6 +201,30 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray } } + + +/** + * 告知服务器已经收到数据 + */ +@PacketId("")//随后写入 +@ExperimentalUnsignedTypes +class ClientMessageResponsePacket( + private val qq: Long, + private val packetIdFromServer: ByteArray,//4bytes + private val sessionKey: ByteArray, + private val eventIdentity: ByteArray +) : ClientPacket() { + override fun encode() { + this.write(packetIdFromServer)//packet id 4bytes + + this.writeQQ(qq) + this.writeHex(Protocol.fixVer2) + this.encryptAndWrite(sessionKey) { + it.write(eventIdentity) + } + } +} + /* 3E 03 3F A2 76 E4 B8 DD 00 09 7C 3F 64 5C 2A 60 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E4 5D 6B A8 F6 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A8 F6 08 7E 90 CE 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 3E 03 3F A2 76 E4 B8 DD 00 03 5F 85 64 5C 2A A4 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E5 5D 6B A9 16 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A9 17 1B B3 4D D7 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt index 980bf9961..cd967e486 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt @@ -3,10 +3,7 @@ package net.mamoe.mirai.network.packet import net.mamoe.mirai.network.packet.login.* import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket -import net.mamoe.mirai.utils.MiraiLogger -import net.mamoe.mirai.utils.getAllDeclaredFields -import net.mamoe.mirai.utils.hexToBytes -import net.mamoe.mirai.utils.toUHexString +import net.mamoe.mirai.utils.* import java.io.DataInputStream /** @@ -14,7 +11,9 @@ import java.io.DataInputStream */ abstract class ServerPacket(val input: DataInputStream) : Packet { - abstract fun decode() + open fun decode() { + + } companion object { @@ -28,23 +27,22 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { return when (val idHex = stream.readInt().toHexString(" ")) { - "08 25 31 01" -> ServerTouchResponsePacketEncrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_01, stream) - - "08 25 31 02" -> ServerTouchResponsePacketEncrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_02, stream) + "08 25 31 01" -> ServerTouchResponsePacket.Encrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_01, stream) + "08 25 31 02" -> ServerTouchResponsePacket.Encrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_02, stream) "08 36 31 03", "08 36 31 04", "08 36 31 05", "08 36 31 06" -> { when (bytes.size) { - 271, 207 -> return ServerLoginResponseResendPacketEncrypted(stream, when (idHex) { + 271, 207 -> return ServerLoginResponseResendPacket.Encrypted(stream, when (idHex) { "08 36 31 03" -> ServerLoginResponseResendPacket.Flag.`08 36 31 03` else -> { MiraiLogger debug ("ServerLoginResponseResendPacketEncrypted: flag=$idHex"); ServerLoginResponseResendPacket.Flag.OTHER } }) - 871 -> return ServerLoginResponseVerificationCodePacketEncrypted(stream) + 871 -> return ServerLoginResponseVerificationCodeInitPacket.Encrypted(stream) } if (bytes.size > 700) { - return ServerLoginResponseSuccessPacketEncrypted(stream) + return ServerLoginResponseSuccessPacket.Encrypted(stream) } return ServerLoginResponseFailedPacket(when (bytes.size) { @@ -63,20 +61,20 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { }, stream) } - "08 28 04 34" -> ServerSessionKeyResponsePacketEncrypted(stream) + "08 28 04 34" -> ServerSessionKeyResponsePacket.Encrypted(stream) else -> when (idHex.substring(0, 5)) { "00 EC" -> ServerLoginSuccessPacket(stream) - "00 1D" -> ServerSKeyResponsePacketEncrypted(stream) - "00 5C" -> ServerAccountInfoResponsePacketEncrypted(stream) + "00 1D" -> ServerSKeyResponsePacket.Encrypted(stream) + "00 5C" -> ServerAccountInfoResponsePacket.Encrypted(stream) "00 58" -> ServerHeartbeatResponsePacket(stream) - "00 BA" -> ServerVerificationCodePacketEncrypted(stream) + "00 BA" -> ServerVerificationCodePacket.Encrypted(stream) - "00 CE", "00 17" -> ServerMessageEventPacketRawEncoded(stream, idHex.hexToBytes()) + "00 CE", "00 17" -> ServerEventPacket.Raw.Encrypted(stream, idHex.hexToBytes()) "00 81" -> UnknownServerPacket(stream) @@ -101,6 +99,16 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { } } } + + fun decryptBy(key: ByteArray): DataInputStream { + input.goto(14) + return DataInputStream(TEA.decrypt(input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, key).inputStream()) + } + + @ExperimentalUnsignedTypes + fun decryptBy(keyHex: String): DataInputStream { + return this.decryptBy(keyHex.hexToBytes()) + } } @@ -173,4 +181,6 @@ fun DataInputStream.readByteAt(position: N): Byte { fun DataInputStream.readShortAt(position: N): Short { this.goto(position) return this.readShort(); -} \ No newline at end of file +} + +fun ByteArray.cutTail(length: Int): ByteArray = this.copyOfRange(0, this.size - length) \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt index 4f55c4e88..301a2402f 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt @@ -2,7 +2,7 @@ package net.mamoe.mirai.network.packet import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.utils.ByteArrayDataOutputStream -import net.mamoe.mirai.utils.TEACryptor +import net.mamoe.mirai.utils.TEA import net.mamoe.mirai.utils.getRandomKey import net.mamoe.mirai.utils.lazyEncode import java.io.DataInputStream @@ -16,8 +16,6 @@ import java.net.InetAddress class ClientSessionRequestPacket( private val qq: Long, private val serverIp: String, - private val loginIP: String, - private val md5_32: ByteArray, private val token38: ByteArray, private val token88: ByteArray, private val encryptionKey: ByteArray, @@ -28,7 +26,7 @@ class ClientSessionRequestPacket( this.writeHex("02 00 00 00 01 2E 01 00 00 68 52 00 30 00 3A") this.writeHex("00 38") this.write(token38) - this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() { + this.write(TEA.encrypt(object : ByteArrayDataOutputStream() { override fun toByteArray(): ByteArray { this.writeHex("00 07 00 88") this.write(token88) @@ -36,10 +34,10 @@ class ClientSessionRequestPacket( this.writeIP(serverIp) this.writeHex("1F 40 00 00 00 00 00 15 00 30 00 01")//fix1 this.writeHex("01 92 A5 D2 59 00 10 54 2D CF 9B 60 BF BB EC 0D D4 81 CE 36 87 DE 35 02 AE 6D ED DC 00 10 ") - this.writeHex(Protocol._0836fix) + this.writeHex(Protocol.fix0836) this.writeHex("00 36 00 12 00 02 00 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00") - this.writeHex(Protocol._0825data0) - this.writeHex(Protocol._0825data2) + this.writeHex(Protocol.constantData0) + this.writeHex(Protocol.constantData1) this.writeQQ(qq) this.writeHex("00 00 00 00 00 1F 00 22 00 01") this.writeHex("1A 68 73 66 E4 BA 79 92 CC C2 D4 EC 14 7C 8B AF 43 B0 62 FB 65 58 A9 EB 37 55 1D 26 13 A8 E5 3D")//device ID @@ -51,7 +49,7 @@ class ClientSessionRequestPacket( //fix3 this.writeHex("00 63 3E 00 63 02 04 03 06 02 00 04 00 52 D9 00 00 00 00 A9 58 3E 6D 6D 49 AA F6 A6 D9 33 0A E7 7E 36 84 03 01 00 00 68 20 15 8B 00 00 01 02 00 00 03 00 07 DF 00 0A 00 0C 00 01 00 04 00 03 00 04 20 5C 00") - this.write(md5_32) + this.write(getRandomKey(32))//md5 32 this.writeHex("68") this.writeHex("00 00 00 00 00 2D 00 06 00 01") @@ -106,16 +104,12 @@ class ServerSessionKeyResponsePacket(inputStream: DataInputStream, private val d //tlv0105 = "01 05 00 88 00 01 01 02 00 40 02 01 03 3C 01 03 00 00" + 取文本中间(data, 取文本长度(data) - 367, 167) + “00 40 02 02 03 3C 01 03 00 00 ” + 取文本中间 (data, 取文本长度 (data) - 166, 167) } -} -class ServerSessionKeyResponsePacketEncrypted(inputStream: DataInputStream) : ServerPacket(inputStream) { - override fun decode() { - - } - - fun decrypt(_0828_rec_decr_key: ByteArray): ServerSessionKeyResponsePacket { - this.input goto 14 - val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) } - return ServerSessionKeyResponsePacket(TEACryptor.decrypt(data, _0828_rec_decr_key).dataInputStream(), data.size); + class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) { + fun decrypt(_0828_rec_decr_key: ByteArray): ServerSessionKeyResponsePacket { + this.input goto 14 + val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) } + return ServerSessionKeyResponsePacket(TEA.decrypt(data, _0828_rec_decr_key).dataInputStream(), data.size); + } } } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt index bf3624e84..6e10d37a9 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt @@ -48,24 +48,13 @@ class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inp } } } -} -class ServerTouchResponsePacketEncrypted(private val type: ServerTouchResponsePacket.Type, inputStream: DataInputStream) : ServerPacket(inputStream) { - override fun decode() { - - } - - @ExperimentalUnsignedTypes - fun decrypt(): ServerTouchResponsePacket { - input.skip(7) - var bytes = input.readAllBytes(); - bytes = bytes.copyOfRange(0, bytes.size - 1); - println(bytes.toUByteArray().toUHexString()) - - return ServerTouchResponsePacket(DataInputStream(TEACryptor.decrypt(bytes, when (type) { - ServerTouchResponsePacket.Type.TYPE_08_25_31_02 -> Protocol.redirectionKey.hexToBytes() - ServerTouchResponsePacket.Type.TYPE_08_25_31_01 -> Protocol._0825key.hexToBytes() - }).inputStream())); + class Encrypted(private val type: Type, inputStream: DataInputStream) : ServerPacket(inputStream) { + @ExperimentalUnsignedTypes + fun decrypt(): ServerTouchResponsePacket = ServerTouchResponsePacket(decryptBy(when (type) { + Type.TYPE_08_25_31_02 -> Protocol.redirectionKey.hexToBytes() + Type.TYPE_08_25_31_01 -> Protocol.key0825.hexToBytes() + })) } } @@ -82,13 +71,13 @@ class ClientTouchPacket(val qq: Long, val serverIp: String) : ClientPacket() { override fun encode() { this.writeQQ(qq) this.writeHex(Protocol.fixVer) - this.writeHex(Protocol._0825key) + this.writeHex(Protocol.key0825) - this.write(TEACryptor.CRYPTOR_0825KEY.encrypt(object : ByteArrayDataOutputStream() { + this.write(TEA.CRYPTOR_0825KEY.encrypt(object : ByteArrayDataOutputStream() { @Throws(IOException::class) override fun toByteArray(): ByteArray { - this.writeHex(Protocol._0825data0) - this.writeHex(Protocol._0825data2) + this.writeHex(Protocol.constantData0) + this.writeHex(Protocol.constantData1) this.writeQQ(qq) this.writeHex("00 00 00 00 03 09 00 08 00 01") this.writeIP(serverIp); @@ -116,11 +105,11 @@ class ClientServerRedirectionPacket(private val serverIP: String, private val qq this.writeHex(Protocol.redirectionKey) - this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() { + this.write(TEA.encrypt(object : ByteArrayDataOutputStream() { @Throws(IOException::class) override fun toByteArray(): ByteArray { - this.writeHex(Protocol._0825data0) - this.writeHex(Protocol._0825data2) + this.writeHex(Protocol.constantData0) + this.writeHex(Protocol.constantData1) this.writeQQ(qq) this.writeHex("00 01 00 00 03 09 00 0C 00 01") this.writeIP(serverIP) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt index ba3e8d377..06e26e7b8 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt @@ -23,11 +23,11 @@ class ClientVerificationCodeTransmissionRequestPacket( this.writeByte(count)//part of packet id this.writeQQ(qq) - this.writeHex(Protocol._fixVer) - this.writeHex(Protocol._00BaKey) - this.encryptAndWrite(Protocol._00BaKey) { + this.writeHex(Protocol.fixVer2) + this.writeHex(Protocol.key00BA) + this.encryptAndWrite(Protocol.key00BA) { it.writeHex("00 02 00 00 08 04 01 E0") - it.writeHex(Protocol._0825data2) + it.writeHex(Protocol.constantData1) it.writeHex("00 00 38") it.write(token0825) it.writeHex("01 03 00 19") @@ -37,7 +37,7 @@ class ClientVerificationCodeTransmissionRequestPacket( it.writeHex("00 28") it.write(token00BA) it.writeHex("00 10") - it.writeHex(Protocol._00BaFixKey) + it.writeHex(Protocol.key00BAFix) } } } @@ -87,22 +87,19 @@ class ServerVerificationCodeRepeatPacket(input: DataInputStream) : ServerVerific } } -abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input) +abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input) { -@PacketId("00 BA") -class ServerVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) { - override fun decode() { - - } - - @ExperimentalUnsignedTypes - fun decrypt(): ServerVerificationCodePacket { - this.input goto 14 - val data = TEACryptor.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, Protocol._00BaKey.hexToBytes()) - return if (data.size == 95) { - ServerVerificationCodeRepeatPacket(data.dataInputStream()) - } else { - ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4)) + @PacketId("00 BA") + class Encrypted(input: DataInputStream) : ServerPacket(input) { + @ExperimentalUnsignedTypes + fun decrypt(): ServerVerificationCodePacket { + this.input goto 14 + val data = TEA.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, Protocol.key00BA.hexToBytes()) + return if (data.size == 95) { + ServerVerificationCodeRepeatPacket(data.dataInputStream()) + } else { + ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4)) + } } } -} \ No newline at end of file +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientChangeOnlineStatusPacket.kt similarity index 83% rename from mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt rename to mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientChangeOnlineStatusPacket.kt index 7c2b2eae3..2007b99bc 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientChangeOnlineStatusPacket.kt @@ -5,11 +5,13 @@ import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.utils.ClientLoginStatus /** + * 改变在线状态: "我在线上", "隐身" 等 + * * @author Him188moe */ @ExperimentalUnsignedTypes @PacketId("00 EC") -class ClientLoginStatusPacket( +class ClientChangeOnlineStatusPacket( private val qq: Long, private val sessionKey: ByteArray, private val loginStatus: ClientLoginStatus @@ -18,7 +20,7 @@ class ClientLoginStatusPacket( override fun encode() { this.writeRandom(2)//part of packet id this.writeQQ(qq) - this.writeHex(Protocol._fixVer) + this.writeHex(Protocol.fixVer2) this.encryptAndWrite(sessionKey) { it.writeHex("01 00") it.writeByte(loginStatus.id) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLogin.kt similarity index 91% rename from mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt rename to mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLogin.kt index 2330c1d30..7066ca1d8 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLogin.kt @@ -4,7 +4,7 @@ import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.util.TestedSuccessfully import net.mamoe.mirai.utils.ByteArrayDataOutputStream -import net.mamoe.mirai.utils.TEACryptor +import net.mamoe.mirai.utils.TEA import net.mamoe.mirai.utils.hexToBytes import net.mamoe.mirai.utils.toUHexString import java.io.DataOutputStream @@ -28,10 +28,10 @@ class ClientPasswordSubmissionPacket( @ExperimentalUnsignedTypes override fun encode() { this.writeQQ(qq) - this.writeHex(Protocol._0836_622_fix1) + this.writeHex(Protocol.passwordSubmissionKey1) this.writeHex(Protocol.publicKey) this.writeHex("00 00 00 10") - this.writeHex(Protocol._0836key1) + this.writeHex(Protocol.key0836) this.encryptAndWrite(Protocol.shareKey.hexToBytes()) { it.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825) @@ -69,12 +69,12 @@ open class ClientLoginResendPacket internal constructor( ) : ClientPacket() { override fun encode() { this.writeQQ(qq) - this.writeHex(Protocol._0836_622_fix1) + this.writeHex(Protocol.passwordSubmissionKey1) this.writeHex(Protocol.publicKey) this.writeHex("00 00 00 10") - this.writeHex(Protocol._0836key1) + this.writeHex(Protocol.key0836) - this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() { + this.write(TEA.encrypt(object : ByteArrayDataOutputStream() { override fun toByteArray(): ByteArray { this.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825, tlv_0006_encr) @@ -115,12 +115,12 @@ private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: I this.writeTLV0006(qq, password, loginTime, loginIP, tgtgtKey) } //fix - this.writeHex(Protocol._0836_622_fix2) + this.writeHex(Protocol.passwordSubmissionKey2) this.writeHex("00 1A")//tag this.writeHex("00 40")//length - this.write(TEACryptor.encrypt(Protocol._0836_622_fix2.hexToBytes(), tgtgtKey)) - this.writeHex(Protocol._0825data0) - this.writeHex(Protocol._0825data2) + this.write(TEA.encrypt(Protocol.passwordSubmissionKey2.hexToBytes(), tgtgtKey)) + this.writeHex(Protocol.constantData0) + this.writeHex(Protocol.constantData1) this.writeQQ(qq) this.writeZero(4) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt index 033f993d9..2313c45b5 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt @@ -1,13 +1,9 @@ package net.mamoe.mirai.network.packet.login import net.mamoe.mirai.network.Protocol -import net.mamoe.mirai.network.packet.ServerPacket -import net.mamoe.mirai.network.packet.goto -import net.mamoe.mirai.network.packet.readNBytesAt -import net.mamoe.mirai.network.packet.readVarString +import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.util.TestedSuccessfully -import net.mamoe.mirai.utils.TEACryptor -import net.mamoe.mirai.utils.hexToBytes +import net.mamoe.mirai.utils.TEA import net.mamoe.mirai.utils.toUHexString import java.io.DataInputStream @@ -117,21 +113,14 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in //this.gender = this.input.goto(packetDataLength - 32).readByteAt().toInt() } -} -class ServerLoginResponseSuccessPacketEncrypted(input: DataInputStream) : ServerPacket(input) { - override fun decode() { + class Encrypted(input: DataInputStream) : ServerPacket(input) { + @ExperimentalUnsignedTypes + fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseSuccessPacket { + input goto 14 + return ServerLoginResponseSuccessPacket(TEA.decrypt(TEA.decrypt(input.readAllBytes().cutTail(1), Protocol.shareKey), tgtgtKey).dataInputStream()); + } } - @ExperimentalUnsignedTypes - fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseSuccessPacket { - input goto 14 - var bytes = input.readAllBytes() - bytes = bytes.copyOfRange(0, bytes.size - 1) - println(bytes.toUByteArray().toUHexString()) - - return ServerLoginResponseSuccessPacket(DataInputStream(TEACryptor.decrypt(TEACryptor.decrypt(bytes, Protocol.shareKey.hexToBytes()), tgtgtKey).inputStream())); - //TeaDecrypt(取文本中间(data, 43, 取文本长度(data) - 45), m_0828_rec_decr_key) - } -} +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt index 0303fcb6e..cfc72a965 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt @@ -2,10 +2,8 @@ package net.mamoe.mirai.network.packet.login import net.mamoe.mirai.network.packet.PacketId import net.mamoe.mirai.network.packet.ServerPacket -import net.mamoe.mirai.network.packet.dataInputStream import net.mamoe.mirai.network.packet.goto import net.mamoe.mirai.util.TestedSuccessfully -import net.mamoe.mirai.utils.TEACryptor import java.io.DataInputStream /** @@ -43,20 +41,9 @@ class ServerLoginResponseResendPacket(input: DataInputStream, val flag: Flag) : } } } + + class Encrypted(input: DataInputStream, private val flag: Flag) : ServerPacket(input) { + @TestedSuccessfully + fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseResendPacket = ServerLoginResponseResendPacket(decryptBy(tgtgtKey), flag) + } } - -class ServerLoginResponseResendPacketEncrypted(input: DataInputStream, private val flag: ServerLoginResponseResendPacket.Flag) : ServerPacket(input) { - override fun decode() { - - } - - @TestedSuccessfully - fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseResendPacket { - //this.input.skip(7) - this.input goto 14 - var data: ByteArray = this.input.readAllBytes() - data = TEACryptor.CRYPTOR_SHARE_KEY.decrypt(data.let { it.copyOfRange(0, it.size - 1) }); - data = TEACryptor.decrypt(data, tgtgtKey) - return ServerLoginResponseResendPacket(data.dataInputStream(), flag) - } -} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt index 3d46f3b0f..49bab953e 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt @@ -1,10 +1,11 @@ package net.mamoe.mirai.network.packet.login import net.mamoe.mirai.network.packet.ServerPacket +import net.mamoe.mirai.network.packet.cutTail import net.mamoe.mirai.network.packet.dataInputStream import net.mamoe.mirai.network.packet.goto import net.mamoe.mirai.util.TestedSuccessfully -import net.mamoe.mirai.utils.TEACryptor +import net.mamoe.mirai.utils.TEA import net.mamoe.mirai.utils.hexToUBytes import java.io.DataInputStream @@ -32,6 +33,19 @@ class ServerLoginResponseVerificationCodeInitPacket(input: DataInputStream, priv this.token00BA = this.input.goto(packetLength - 60).readNBytes(40) } + + + class Encrypted(input: DataInputStream) : ServerPacket(input) { + override fun decode() { + + } + + fun decrypt(): ServerLoginResponseVerificationCodeInitPacket { + this.input goto 14 + val data = TEA.CRYPTOR_SHARE_KEY.decrypt(this.input.readAllBytes().cutTail(1)); + return ServerLoginResponseVerificationCodeInitPacket(data.dataInputStream(), data.size) + } + } } fun main() { @@ -54,15 +68,3 @@ verify code token00ba 42 E6 18 57 D4 B1 4D AE 51 27 D5 EF A2 38 91 39 15 37 6C 5A FE 75 93 49 DB FC 57 3C 12 3F 26 D9 16 1D 83 45 8B 78 39 D8 */ - -class ServerLoginResponseVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) { - override fun decode() { - - } - - fun decrypt(): ServerLoginResponseVerificationCodeInitPacket { - this.input goto 14 - val data = TEACryptor.CRYPTOR_SHARE_KEY.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }); - return ServerLoginResponseVerificationCodeInitPacket(data.dataInputStream(), data.size) - } -} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginSuccessPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginSuccessPacket.kt index 2aebc04d5..4b5d092d0 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginSuccessPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginSuccessPacket.kt @@ -4,10 +4,8 @@ import net.mamoe.mirai.network.packet.ServerPacket import java.io.DataInputStream /** + * Congratulations! + * * @author Him188moe */ -class ServerLoginSuccessPacket(input: DataInputStream) : ServerPacket(input) { - override fun decode() { - - } -} \ No newline at end of file +class ServerLoginSuccessPacket(input: DataInputStream) : ServerPacket(input) \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt index 6fa63d04d..7313a3bbb 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt @@ -19,7 +19,7 @@ class ClientSendFriendMessagePacket( override fun encode() { this.writeRandom(2)//part of packet id this.writeQQ(robotQQ) - this.writeHex(Protocol._fixVer) + this.writeHex(Protocol.fixVer2) this.encryptAndWrite(sessionKey) { it.writeQQ(robotQQ) @@ -58,7 +58,4 @@ class ClientSendFriendMessagePacket( } @PacketId("00 CD") -class ServerSendFriendMessageResponsePacket(input: DataInputStream) : ServerPacket(input) { - override fun decode() { - } -} \ No newline at end of file +class ServerSendFriendMessageResponsePacket(input: DataInputStream) : ServerPacket(input) \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt index 2ef2a85cc..c16d27ae5 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt @@ -2,7 +2,6 @@ package net.mamoe.mirai.network.packet.message import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.packet.* -import net.mamoe.mirai.utils.lazyEncode import net.mamoe.mirai.utils.toUHexString import java.io.DataInputStream @@ -13,14 +12,14 @@ import java.io.DataInputStream @ExperimentalUnsignedTypes class ClientSendGroupMessagePacket( private val groupId: Long,//不是 number - private val qq: Long, + private val robotQQ: Long, private val sessionKey: ByteArray, private val message: String ) : ClientPacket() { override fun encode() { this.writeRandom(2)//part of packet id - this.writeQQ(qq) - this.writeHex(Protocol._fixVer) + this.writeQQ(robotQQ) + this.writeHex(Protocol.fixVer2) this.encryptAndWrite(sessionKey) { val bytes = message.toByteArray() @@ -46,24 +45,5 @@ class ClientSendGroupMessagePacket( } } -fun main() { - println(lazyEncode { - val bytes = "message".toByteArray() - it.writeByte(0x2A) - it.writeInt(580266363) - it.writeShort(19 + bytes.size) - - it.writeByte(0x01) - it.writeByte(0x01) - it.writeShort(bytes.size + 3) - it.writeByte(0x01) - it.writeShort(bytes.size) - it.write(bytes) - }.toUHexString()) -} - @PacketId("00 02") -class ServerSendGroupMessageResponsePacket(input: DataInputStream) : ServerPacket(input) { - override fun decode() { - } -} \ No newline at end of file +class ServerSendGroupMessageResponsePacket(input: DataInputStream) : ServerPacket(input) \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/ClientLoginStatus.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/ClientLoginStatus.java index 45e1976fd..b2864cae6 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/ClientLoginStatus.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/ClientLoginStatus.java @@ -4,10 +4,14 @@ package net.mamoe.mirai.utils; * @author Him188moe */ public enum ClientLoginStatus { + /** + * 我在线上 + */ ONLINE(0x0A); - // TODO: 2019/8/31 add more - public final int id;//1byte + // TODO: 2019/8/31 add more ClientLoginStatus + + public final int id;//1 ubyte ClientLoginStatus(int id) { this.id = id; diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/RobotAccount.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/RobotAccount.java new file mode 100644 index 000000000..0f2bea143 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/RobotAccount.java @@ -0,0 +1,17 @@ +package net.mamoe.mirai.utils; + +import lombok.Data; + +/** + * @author Him188moe + */ +@Data +public final class RobotAccount { + public final long qqNumber; + public final String password; + + public RobotAccount(long qqNumber, String password) { + this.qqNumber = qqNumber; + this.password = password; + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/TEACryptor.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java similarity index 91% rename from mirai-core/src/main/java/net/mamoe/mirai/utils/TEACryptor.java rename to mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java index 9b6269c49..84121e2eb 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/TEACryptor.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java @@ -8,10 +8,10 @@ import java.util.Random; /** * @author iweiz https://github.com/iweizime/StepChanger/blob/master/app/src/main/java/me/iweizi/stepchanger/qq/Cryptor.java */ -public class TEACryptor { - public static final TEACryptor CRYPTOR_SHARE_KEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol.shareKey)); - public static final TEACryptor CRYPTOR_0825KEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol._0825key)); - public static final TEACryptor CRYPTOR_00BAKEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol._00BaKey)); +public class TEA { + public static final TEA CRYPTOR_SHARE_KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.shareKey)); + public static final TEA CRYPTOR_0825KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key0825)); + public static final TEA CRYPTOR_00BAKEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key00BA)); private static final long UINT32_MASK = 0xffffffffL; private final long[] mKey; @@ -25,7 +25,7 @@ public class TEACryptor { private boolean isFirstBlock; private boolean isRand; - public TEACryptor(byte[] key) { + public TEA(byte[] key) { mKey = new long[4]; for (int i = 0; i < 4; i++) { mKey[i] = pack(key, i * 4, 4); @@ -36,11 +36,19 @@ public class TEACryptor { } public static byte[] encrypt(byte[] source, byte[] key) { - return new TEACryptor(key).encrypt(source); + return new TEA(key).encrypt(source); + } + + public static byte[] encrypt(byte[] source, String keyHex) { + return encrypt(source, UtilsKt.hexToBytes(keyHex)); } public static byte[] decrypt(byte[] source, byte[] key) { - return new TEACryptor(key).decrypt(source); + return new TEA(key).decrypt(source); + } + + public static byte[] decrypt(byte[] source, String keyHex) { + return decrypt(source, UtilsKt.hexToBytes(keyHex)); } private static long pack(byte[] bytes, int offset, int len) { From 39330e45604ba7a29f1cdef0d5779272aee13317 Mon Sep 17 00:00:00 2001 From: Him188moe Date: Wed, 4 Sep 2019 22:20:19 +0800 Subject: [PATCH 05/19] Updated robot & network structure --- .../main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt | 4 ++-- .../main/java/net/mamoe/mirai/network/packet/ServerPacket.kt | 4 ++-- .../{message => action}/ClientSendFriendMessagePacket.kt | 2 +- .../{message => action}/ClientSendGroupMessagePacket.kt | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename mirai-core/src/main/java/net/mamoe/mirai/network/packet/{message => action}/ClientSendFriendMessagePacket.kt (97%) rename mirai-core/src/main/java/net/mamoe/mirai/network/packet/{message => action}/ClientSendGroupMessagePacket.kt (96%) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index 0a8fb4c67..baf67a135 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -7,9 +7,9 @@ import net.mamoe.mirai.event.events.qq.FriendMessageEvent import net.mamoe.mirai.event.events.robot.RobotLoginSucceedEvent import net.mamoe.mirai.message.Message import net.mamoe.mirai.network.packet.* +import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket +import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.network.packet.login.* -import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket -import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.task.MiraiThreadPool import net.mamoe.mirai.utils.ClientLoginStatus import net.mamoe.mirai.utils.MiraiLogger diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt index cd967e486..0a1c8b975 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt @@ -1,8 +1,8 @@ package net.mamoe.mirai.network.packet +import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket +import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.network.packet.login.* -import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket -import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.utils.* import java.io.DataInputStream diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendFriendMessagePacket.kt similarity index 97% rename from mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt rename to mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendFriendMessagePacket.kt index 7313a3bbb..0bea83586 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendFriendMessagePacket.kt @@ -1,4 +1,4 @@ -package net.mamoe.mirai.network.packet.message +package net.mamoe.mirai.network.packet.action import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.packet.* diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendGroupMessagePacket.kt similarity index 96% rename from mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt rename to mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendGroupMessagePacket.kt index c16d27ae5..4abd29fed 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendGroupMessagePacket.kt @@ -1,4 +1,4 @@ -package net.mamoe.mirai.network.packet.message +package net.mamoe.mirai.network.packet.action import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.packet.* From 99cf7e2f85f169ee95cdfb6e5fb1c6acbc363176 Mon Sep 17 00:00:00 2001 From: Him188moe Date: Wed, 4 Sep 2019 22:29:47 +0800 Subject: [PATCH 06/19] Updated robot & network structure --- .../mirai/network/packet/ClientPacket.kt | 1 - .../mirai/network/packet/VerificationCode.kt | 1 - .../mirai/network/packet/login/ClientLogin.kt | 6 +--- ...rverLoginResponsePasswordVerifiedPacket.kt | 2 +- .../login/ServerLoginResponseResendPacket.kt | 2 +- ...LoginResponseVerificationCodeInitPacket.kt | 2 +- .../mirai/task/MiraiTaskExceptionHandler.java | 15 ++++------ .../mamoe/mirai/task/MiraiTaskManager.java | 10 +++---- .../main/java/net/mamoe/mirai/utils/TEA.java | 30 +++++++++---------- .../main/java/net/mamoe/mirai/utils/Tested.kt | 2 +- .../mirai/utils/setting/MiraiSetting.java | 16 +++++----- 11 files changed, 39 insertions(+), 48 deletions(-) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt index 2435134d0..a31ed32e9 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt @@ -2,7 +2,6 @@ package net.mamoe.mirai.network.packet import lombok.Getter import net.mamoe.mirai.network.Protocol -import net.mamoe.mirai.util.TestedSuccessfully import net.mamoe.mirai.utils.* import java.io.DataOutputStream import java.io.IOException diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt index 06e26e7b8..e2e3366a3 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt @@ -1,7 +1,6 @@ package net.mamoe.mirai.network.packet import net.mamoe.mirai.network.Protocol -import net.mamoe.mirai.util.TestedSuccessfully import net.mamoe.mirai.utils.* import java.io.DataInputStream diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLogin.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLogin.kt index 7066ca1d8..e28c1a6b7 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLogin.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLogin.kt @@ -2,11 +2,7 @@ package net.mamoe.mirai.network.packet.login import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.packet.* -import net.mamoe.mirai.util.TestedSuccessfully -import net.mamoe.mirai.utils.ByteArrayDataOutputStream -import net.mamoe.mirai.utils.TEA -import net.mamoe.mirai.utils.hexToBytes -import net.mamoe.mirai.utils.toUHexString +import net.mamoe.mirai.utils.* import java.io.DataOutputStream /** diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt index 2313c45b5..61937971e 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt @@ -2,8 +2,8 @@ package net.mamoe.mirai.network.packet.login import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.packet.* -import net.mamoe.mirai.util.TestedSuccessfully import net.mamoe.mirai.utils.TEA +import net.mamoe.mirai.utils.TestedSuccessfully import net.mamoe.mirai.utils.toUHexString import java.io.DataInputStream diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt index cfc72a965..37a9862d0 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseResendPacket.kt @@ -3,7 +3,7 @@ package net.mamoe.mirai.network.packet.login import net.mamoe.mirai.network.packet.PacketId import net.mamoe.mirai.network.packet.ServerPacket import net.mamoe.mirai.network.packet.goto -import net.mamoe.mirai.util.TestedSuccessfully +import net.mamoe.mirai.utils.TestedSuccessfully import java.io.DataInputStream /** diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt index 49bab953e..448d1413c 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt @@ -4,8 +4,8 @@ import net.mamoe.mirai.network.packet.ServerPacket import net.mamoe.mirai.network.packet.cutTail import net.mamoe.mirai.network.packet.dataInputStream import net.mamoe.mirai.network.packet.goto -import net.mamoe.mirai.util.TestedSuccessfully import net.mamoe.mirai.utils.TEA +import net.mamoe.mirai.utils.TestedSuccessfully import net.mamoe.mirai.utils.hexToUBytes import java.io.DataInputStream diff --git a/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskExceptionHandler.java b/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskExceptionHandler.java index 1bef14b21..d79df9f53 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskExceptionHandler.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskExceptionHandler.java @@ -4,15 +4,12 @@ package net.mamoe.mirai.task; public interface MiraiTaskExceptionHandler { void onHandle(Throwable e); - static MiraiTaskExceptionHandler byDefault(){ - return byPrint(); - } - - static MiraiTaskExceptionHandler byIgnore(){ - return a -> {}; - } - - static MiraiTaskExceptionHandler byPrint(){ + static MiraiTaskExceptionHandler printing() { return Throwable::printStackTrace; } + + static MiraiTaskExceptionHandler ignoring() { + return a -> { + }; + } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskManager.java b/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskManager.java index cf814fc39..1f623387d 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskManager.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskManager.java @@ -35,7 +35,7 @@ public final class MiraiTaskManager { */ public void execute(Runnable runnable) { - this.execute(runnable, MiraiTaskExceptionHandler.byDefault()); + this.execute(runnable, MiraiTaskExceptionHandler.printing()); } public void execute(Runnable runnable, MiraiTaskExceptionHandler handler) { @@ -51,7 +51,7 @@ public final class MiraiTaskManager { public Future submit(Callable callable) { - return this.submit(callable, MiraiTaskExceptionHandler.byDefault()); + return this.submit(callable, MiraiTaskExceptionHandler.printing()); } public Future submit(Callable callable, MiraiTaskExceptionHandler handler) { @@ -69,7 +69,7 @@ public final class MiraiTaskManager { * 异步任务 */ public void ansycTask(Callable callable, Consumer callback) { - this.ansycTask(callable, callback, MiraiTaskExceptionHandler.byDefault()); + this.ansycTask(callable, callback, MiraiTaskExceptionHandler.printing()); } public void ansycTask(Callable callable, Consumer callback, MiraiTaskExceptionHandler handler) { @@ -87,7 +87,7 @@ public final class MiraiTaskManager { */ public void repeatingTask(Runnable runnable, long intervalMillis) { - this.repeatingTask(runnable, intervalMillis, MiraiTaskExceptionHandler.byDefault()); + this.repeatingTask(runnable, intervalMillis, MiraiTaskExceptionHandler.printing()); } public void repeatingTask(Runnable runnable, long intervalMillis, MiraiTaskExceptionHandler handler) { @@ -95,7 +95,7 @@ public final class MiraiTaskManager { } public void repeatingTask(Runnable runnable, long intervalMillis, int times) { - this.repeatingTask(runnable, intervalMillis, times, MiraiTaskExceptionHandler.byDefault()); + this.repeatingTask(runnable, intervalMillis, times, MiraiTaskExceptionHandler.printing()); } public void repeatingTask(Runnable runnable, long intervalMillis, int times, MiraiTaskExceptionHandler handler) { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java index 84121e2eb..d26bd145d 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java @@ -6,9 +6,11 @@ import java.nio.ByteBuffer; import java.util.Random; /** + * TEA 加密 + * * @author iweiz https://github.com/iweizime/StepChanger/blob/master/app/src/main/java/me/iweizi/stepchanger/qq/Cryptor.java */ -public class TEA { +public final class TEA { public static final TEA CRYPTOR_SHARE_KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.shareKey)); public static final TEA CRYPTOR_0825KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key0825)); public static final TEA CRYPTOR_00BAKEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key00BA)); @@ -23,14 +25,12 @@ public class TEA { private int mOutPos; private int mPreOutPos; private boolean isFirstBlock; - private boolean isRand; public TEA(byte[] key) { mKey = new long[4]; for (int i = 0; i < 4; i++) { mKey[i] = pack(key, i * 4, 4); } - isRand = true; mRandom = new Random(); isFirstBlock = true; } @@ -51,6 +51,7 @@ public class TEA { return decrypt(source, UtilsKt.hexToBytes(keyHex)); } + @SuppressWarnings("SameParameterValue") private static long pack(byte[] bytes, int offset, int len) { long result = 0; int max_offset = len > 8 ? offset + 8 : offset + len; @@ -61,11 +62,7 @@ public class TEA { } private int rand() { - return isRand ? mRandom.nextInt() : 0xff00ff; - } - - public void enableRandom(boolean rand) { - isRand = rand; + return mRandom.nextInt(); } private byte[] encode(byte[] bytes) { @@ -117,6 +114,7 @@ public class TEA { isFirstBlock = false; } + @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean decodeOneBlock(byte[] ciphertext, int offset, int len) { for (mIndexPos = 0; mIndexPos < 8; mIndexPos++) { if (mOutPos + mIndexPos < len) { @@ -133,6 +131,7 @@ public class TEA { } + @SuppressWarnings("SameParameterValue") private byte[] encrypt(byte[] plaintext, int offset, int len) { mInBlock = new byte[8]; mIV = new byte[8]; @@ -183,11 +182,12 @@ public class TEA { return mOutput; } - private byte[] decrypt(byte[] ciphertext, int offset, int len) { + @SuppressWarnings("SameParameterValue") + private byte[] decrypt(byte[] cipherText, int offset, int len) { if (len % 8 != 0 || len < 16) { throw new IllegalArgumentException("must len % 8 == 0 && len >= 16"); } - mIV = decode(ciphertext, offset); + mIV = decode(cipherText, offset); mIndexPos = mIV[0] & 7; int plen = len - mIndexPos - 10; isFirstBlock = true; @@ -206,7 +206,7 @@ public class TEA { } if (mIndexPos == 8) { isFirstBlock = false; - if (!decodeOneBlock(ciphertext, offset, len)) { + if (!decodeOneBlock(cipherText, offset, len)) { throw new RuntimeException("Unable to decode"); } } @@ -216,20 +216,20 @@ public class TEA { if (mIndexPos < 8) { mOutput[outpos++] = isFirstBlock ? mIV[mIndexPos] : - (byte) (ciphertext[mPreOutPos + offset + mIndexPos] ^ mIV[mIndexPos]); + (byte) (cipherText[mPreOutPos + offset + mIndexPos] ^ mIV[mIndexPos]); ++mIndexPos; } if (mIndexPos == 8) { mPreOutPos = mOutPos - 8; isFirstBlock = false; - if (!decodeOneBlock(ciphertext, offset, len)) { + if (!decodeOneBlock(cipherText, offset, len)) { throw new RuntimeException("Unable to decode"); } } } for (g = 0; g < 7; g++) { if (mIndexPos < 8) { - if ((ciphertext[mPreOutPos + offset + mIndexPos] ^ mIV[mIndexPos]) != 0) { + if ((cipherText[mPreOutPos + offset + mIndexPos] ^ mIV[mIndexPos]) != 0) { throw new RuntimeException(); } else { ++mIndexPos; @@ -238,7 +238,7 @@ public class TEA { if (mIndexPos == 8) { mPreOutPos = mOutPos; - if (!decodeOneBlock(ciphertext, offset, len)) { + if (!decodeOneBlock(cipherText, offset, len)) { throw new RuntimeException("Unable to decode"); } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/Tested.kt b/mirai-core/src/main/java/net/mamoe/mirai/utils/Tested.kt index 6b3e910ee..d2298e467 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/Tested.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/Tested.kt @@ -1,4 +1,4 @@ -package net.mamoe.mirai.util +package net.mamoe.mirai.utils /** * @author Him188moe diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSetting.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSetting.java index 4f93da511..851cdd862 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSetting.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSetting.java @@ -6,14 +6,14 @@ import org.ini4j.Ini; import java.io.File; import java.io.IOException; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** - * Mirai Config - * Only support {INI} format - * Support MAP and LIST - * Thread safe + * Thread-safe Mirai Config
+ * Only supports INI format
+ * Supports {@link Map} and {@link List} */ public class MiraiSetting { @@ -42,12 +42,12 @@ public class MiraiSetting { } } - public void setSection(String key, MiraiSettingSection section){ + public synchronized void setSection(String key, MiraiSettingSection section) { cacheSection.put(key, section); } - public MiraiSettingMapSection getMapSection(String key){ + public synchronized MiraiSettingMapSection getMapSection(String key) { if(!cacheSection.containsKey(key)) { MiraiSettingMapSection section = new MiraiSettingMapSection(); if(ini.containsKey(key)){ @@ -58,7 +58,7 @@ public class MiraiSetting { return (MiraiSettingMapSection) cacheSection.get(key); } - public MiraiSettingListSection getListSection(String key){ + public synchronized MiraiSettingListSection getListSection(String key) { if(!cacheSection.containsKey(key)) { MiraiSettingListSection section = new MiraiSettingListSection(); if(ini.containsKey(key)){ @@ -85,7 +85,7 @@ public class MiraiSetting { } } - public void clearCache(){ + public synchronized void clearCache() { cacheSection.clear(); } } From 1ba96b78aa450b96bd73029fb1b68a16825653d9 Mon Sep 17 00:00:00 2001 From: Him188moe Date: Wed, 4 Sep 2019 22:37:33 +0800 Subject: [PATCH 07/19] Updated robot & network structure --- .../mirai/network/RobotNetworkHandler.kt | 5 +- .../mamoe/mirai/network/packet/ServerEvent.kt | 2 +- .../net/mamoe/mirai/network/packet/Session.kt | 6 +- ...rverLoginResponsePasswordVerifiedPacket.kt | 74 +------------------ 4 files changed, 11 insertions(+), 76 deletions(-) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index baf67a135..bb633c19a 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -48,6 +48,9 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { private lateinit var loginIP: String private var tgtgtKey: ByteArray? = null private var tlv0105: ByteArray + /** + * 0828_decr_key + */ private lateinit var sessionResponseDecryptionKey: ByteArray private var verificationCodeSequence: Int = 0//这两个验证码使用 @@ -214,7 +217,7 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { } is ServerLoginResponseSuccessPacket -> { - this.sessionResponseDecryptionKey = packet._0828_rec_decr_key + this.sessionResponseDecryptionKey = packet.sessionResponseDecryptionKey sendPacket(ClientSessionRequestPacket(this.robot.account.qqNumber, this.serverIP, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105)) } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt index ec54aeed5..943e14368 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt @@ -60,7 +60,7 @@ class UnknownServerEventPacket(input: DataInputStream, packetId: ByteArray, even class ServerAndroidOnlineEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) /** - * Android 客户端上线 + * Android 客户端下线 */ class ServerAndroidOfflineEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt index 301a2402f..ee1dadd85 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt @@ -62,8 +62,6 @@ class ClientSessionRequestPacket( } /** - * Dispose_0828 - * * @author Him188moe */ class ServerSessionKeyResponsePacket(inputStream: DataInputStream, private val dataLength: Int) : ServerPacket(inputStream) { @@ -106,10 +104,10 @@ class ServerSessionKeyResponsePacket(inputStream: DataInputStream, private val d } class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) { - fun decrypt(_0828_rec_decr_key: ByteArray): ServerSessionKeyResponsePacket { + fun decrypt(sessionResponseDecryptionKey: ByteArray): ServerSessionKeyResponsePacket { this.input goto 14 val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) } - return ServerSessionKeyResponsePacket(TEA.decrypt(data, _0828_rec_decr_key).dataInputStream(), data.size); + return ServerSessionKeyResponsePacket(TEA.decrypt(data, sessionResponseDecryptionKey).dataInputStream(), data.size) } } } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt index 61937971e..b6b8f448c 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponsePasswordVerifiedPacket.kt @@ -11,8 +11,8 @@ import java.io.DataInputStream * @author NaturalHG */ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(input) { - lateinit var _0828_rec_decr_key: ByteArray//16 bytes| - lateinit var nick: String + lateinit var sessionResponseDecryptionKey: ByteArray//16 bytes| + lateinit var nickname: String lateinit var token38: ByteArray lateinit var token88: ByteArray @@ -22,72 +22,6 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in @TestedSuccessfully @ExperimentalUnsignedTypes override fun decode() { - //测试完成 @NaturalHG - /** - * Version 1 @Deprecated - this.input.skip(7)//8 - - encryptionKey = this.input.readNBytesAt(16)//24 - - this.input.skip(2)//25->26 - - token38 = this.input.readNBytesAt(56)//81->82 - - this.input.skip(60L)//142 - - //?? - var b = this.input.readNBytesAt(2) - val msgLength = when (b.toUByteArray().toUHexString()) { - "01 07" -> 0 - "00 33" -> 28 - "01 10" -> 65 - else -> throw IllegalStateException() - }//144 - - - System.out.println(msgLength) - - this.input.skip(17L + msgLength)//161+msgLength - - this.input.skip(10)//171+msgLength - - _0828_rec_decr_key = this.input.readNBytesAt(16)//187+msgLength - - - this.input.skip(2) - - token88 = this.input.readNBytesAt(136)//325+ // msgLength - - this.input.skip(299L)//624+msgLength - - //varString (nickLength bytes) - val nickLength = this.input.readByteAt().toInt()//625+msgLength - - System.out.println(nickLength) - - nick = this.input.readVarString(nickLength)//625+msgLength+nickLength - - val dataIndex = packetDataLength - 31 - - /* - this.input.skip((dataIndex - (625 + msgLength + nickLength)) + 0L)//-31 - - gender = this.input.readByteAt().toUByte().toInt()//-30 - - this.input.skip(9)//-27 - - age = this.input.readShortAt()//-25 - */ - age = 0 - gender = 0 - - /* - age = HexToDec(取文本中间(data, 取文本长度(data) - 82, 5)) - gender = 取文本中间(data, 取文本长度(data) - 94, 2) - */ - * **/ - /** version 2 */ - this.input.skip(7)//8 this.encryptionKey = this.input.readNBytes(16)//24 @@ -102,12 +36,12 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in else -> throw IllegalStateException(id) } - this._0828_rec_decr_key = this.input.readNBytesAt(171 + msgLength, 16) + this.sessionResponseDecryptionKey = this.input.readNBytesAt(171 + msgLength, 16) this.token88 = this.input.readNBytesAt(189 + msgLength, 136) val nickLength = this.input.goto(624 + msgLength).readByte().toInt() - this.nick = this.input.readVarString(nickLength) + this.nickname = this.input.readVarString(nickLength) //this.age = this.input.goto(packetDataLength - 28).readShortAt() From d0a9a9da349401547bd6f3e625171351abccb5d8 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 4 Sep 2019 22:38:29 +0800 Subject: [PATCH 08/19] Updated robot & network structure --- .../src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index bb633c19a..15e462c07 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -346,7 +346,6 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { else -> throw IllegalArgumentException(packet.toString()) } - } internal val packetSystem: PacketSystem = PacketSystem() From 7b8cd5d5219514b09f76f83073a124c8a68a21df Mon Sep 17 00:00:00 2001 From: Him188moe Date: Wed, 4 Sep 2019 22:40:18 +0800 Subject: [PATCH 09/19] Updated robot & network structure --- .../java/net/mamoe/mirai/message/defaults/MessageChain.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.java index d0fe6465f..9adfed317 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.java @@ -29,6 +29,9 @@ public final class MessageChain extends Message { list.add(message); } + /** + * @return An unmodifiable list + */ public List toList() { return List.copyOf(list); } From a445f5b5230bb58ce6d0443dbae4bbf8aa258030 Mon Sep 17 00:00:00 2001 From: Him188moe Date: Wed, 4 Sep 2019 22:55:14 +0800 Subject: [PATCH 10/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 66c0555cf..c16fc755a 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The project is all for learning proposes and still in developing stage ### 代码结构 Network部分使用 Kotlin 完成(因为kt有对 unsigned byte 的支持). -与插件相关性强(或其他在二次开发中容易接触的部分)均使用 Java 完成, +与插件相关性强(或其他在二次开发中容易接触)的部分使用 Java 完成, 同时也会针对kotlin提供优化的方法调用. 例如对'+'操作符的重载: `String+BufferedImage+QQ.At+Face+URL+String+File` 将会被自动处理为String消息. From e9ee57296d3e65f4c4ac774aae59cb8654059403 Mon Sep 17 00:00:00 2001 From: Him188moe Date: Wed, 4 Sep 2019 22:56:18 +0800 Subject: [PATCH 11/19] Updated robot & network structure --- .../main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index 15e462c07..c28f20f31 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -118,7 +118,7 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { private fun restartSocket() { socket.close() socket = DatagramSocket((15314 + Math.random() * 100).toInt()) - socket.connect(this.serverAddress).runCatching { } + socket.connect(this.serverAddress) val zeroByte: Byte = 0 Thread { while (true) { From c353e8e8f998f2809bb9f87235a46a0c9592259d Mon Sep 17 00:00:00 2001 From: Him188moe Date: Wed, 4 Sep 2019 22:57:46 +0800 Subject: [PATCH 12/19] Updated robot & network structure sendPacket is not async now --- .../mirai/network/RobotNetworkHandler.kt | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index c28f20f31..b19399d84 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -363,19 +363,20 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { } + /** + * Not async + */ @ExperimentalUnsignedTypes fun sendPacket(packet: ClientPacket) { - MiraiThreadPool.getInstance().submit { - try { - packet.encode() - packet.writeHex(Protocol.tail) + try { + packet.encode() + packet.writeHex(Protocol.tail) - val data = packet.toByteArray() - socket.send(DatagramPacket(data, data.size)) - MiraiLogger info "Packet sent: $packet" - } catch (e: Throwable) { - e.printStackTrace() - } + val data = packet.toByteArray() + socket.send(DatagramPacket(data, data.size)) + MiraiLogger info "Packet sent: $packet" + } catch (e: Throwable) { + e.printStackTrace() } } From c734431f642de69a0d12841aaa9f46340bde3dca Mon Sep 17 00:00:00 2001 From: Him188moe Date: Wed, 4 Sep 2019 23:31:19 +0800 Subject: [PATCH 13/19] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c16fc755a..2f84601d4 100644 --- a/README.md +++ b/README.md @@ -21,17 +21,18 @@ Network部分使用 Kotlin 完成(因为kt有对 unsigned byte 的支持). ### TODO - [x] 事件(Event)模块 -- [ ] 插件(Plugin)模块 **(Working on)** +- [ ] 插件(Plugin)模块 - [x] Network - Touch - [X] Network - Login - [X] Network - Session -- [ ] Network - Verification Code (Low priority) +- [ ] Network - Verification Code **(Woring on)** - [X] Network - Message Receiving - [X] Network - Message Sending - [ ] Network - Events **(Working on)** - [ ] Robot - Friend/group list - [ ] Message Section **(Working on)** - [ ] Contact +- [ ] UI **(Woring on)**
From 6e0e38896d4474116dc477add94beedb527db95e Mon Sep 17 00:00:00 2001 From: Him188moe Date: Wed, 4 Sep 2019 23:33:09 +0800 Subject: [PATCH 14/19] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2f84601d4..21191dd68 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,15 @@ Network部分使用 Kotlin 完成(因为kt有对 unsigned byte 的支持). - [x] Network - Touch - [X] Network - Login - [X] Network - Session -- [ ] Network - Verification Code **(Woring on)** +- [ ] Network - Verification Code **(Working on)** - [X] Network - Message Receiving - [X] Network - Message Sending - [ ] Network - Events **(Working on)** - [ ] Robot - Friend/group list +- [ ] Robot - Actions(joining group, adding friend, etc.) - [ ] Message Section **(Working on)** - [ ] Contact -- [ ] UI **(Woring on)** +- [ ] UI **(Working on)**
From e129719d4b91f75d54d1a0fc27568ed7a77d77a1 Mon Sep 17 00:00:00 2001 From: Him188moe Date: Thu, 5 Sep 2019 20:21:35 +0800 Subject: [PATCH 15/19] Updated robot & network structure --- .../java/net/mamoe/mirai/contact/Group.kt | 2 +- .../main/java/net/mamoe/mirai/contact/QQ.kt | 2 +- .../java/net/mamoe/mirai/network/Protocol.kt | 140 ++-- .../mirai/network/RobotNetworkHandler.kt | 704 ++++++++++-------- .../mamoe/mirai/network/packet/AccountInfo.kt | 1 + .../mirai/network/packet/ServerPacket.kt | 15 +- .../mirai/network/packet/login/LoginState.kt | 4 +- .../main/java/net/mamoe/mirai/utils/TEA.java | 5 +- .../main/java/net/mamoe/mirai/utils/Utils.kt | 14 +- 9 files changed, 486 insertions(+), 401 deletions(-) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt index 3c14af642..93640bacd 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt @@ -10,7 +10,7 @@ class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable { val members = ContactList() override fun sendMessage(message: Message) { - robot.network.packetSystem.sendGroupMessage(this, message) + robot.network.messageHandler.sendGroupMessage(this, message) } override fun sendXMLMessage(message: String) { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt index efab8f4a6..2b8fb792d 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt @@ -12,7 +12,7 @@ import net.mamoe.mirai.message.defaults.At */ class QQ(robot: Robot, number: Long) : Contact(robot, number) { override fun sendMessage(message: Message) { - robot.network.packetSystem.sendFriendMessage(this, message) + robot.network.messageHandler.sendFriendMessage(this, message) } override fun sendXMLMessage(message: String) { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt index f5c4bbfb3..2e33a4f20 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt @@ -7,88 +7,86 @@ import java.util.stream.Collectors /** * @author Him188moe */ -interface Protocol { - companion object { - val SERVER_IP: ArrayList = object : ArrayList() { - init { - add("183.60.56.29") +object Protocol { + val SERVER_IP: List = object : ArrayList() { + init { + add("183.60.56.29") - arrayOf( - "sz2.tencent.com", - "sz3.tencent.com", - "sz4.tencent.com", - "sz5.tencent.com", - "sz6.tencent.com", - "sz8.tencent.com", - "sz9.tencent.com" - ).forEach { this.add(InetAddress.getByName(it).hostAddress) } + arrayOf( + "sz2.tencent.com", + "sz3.tencent.com", + "sz4.tencent.com", + "sz5.tencent.com", + "sz6.tencent.com", + "sz8.tencent.com", + "sz9.tencent.com" + ).forEach { this.add(InetAddress.getByName(it).hostAddress) } - } } + } + get() = Collections.unmodifiableList(field) + const val head = "02" + const val ver = "37 13" + const val fixVer = "03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00" + const val tail = "03" + /** + * _fixVer + */ + const val fixVer2 = "02 00 00 00 01 01 01 00 00 68 20" + /** + * 0825data1 + */ + const val constantData0 = "00 18 00 16 00 01 " + /** + * 0825data2 + */ + const val constantData1 = "00 00 04 53 00 00 00 01 00 00 15 85 " + const val key0825 = "A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D" + const val redirectionKey = "A8 F2 14 5F 58 12 60 AF 07 63 97 D6 76 B2 1A 3B" + const val publicKey = "02 6D 28 41 D2 A5 6F D2 FC 3E 2A 1F 03 75 DE 6E 28 8F A8 19 3E 5F 16 49 D3" + const val shareKey = "1A E9 7F 7D C9 73 75 98 AC 02 E0 80 5F A9 C6 AF" + const val fix0836 = "06 A9 12 97 B7 F8 76 25 AF AF D3 EA B4 C8 BC E7 " - const val head = "02" - const val ver = "37 13" - const val fixVer = "03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00" - const val tail = "03" - /** - * _fixVer - */ - const val fixVer2 = "02 00 00 00 01 01 01 00 00 68 20" - /** - * 0825data1 - */ - const val constantData0 = "00 18 00 16 00 01 " - /** - * 0825data2 - */ - const val constantData1 = "00 00 04 53 00 00 00 01 00 00 15 85 " - const val key0825 = "A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D" - const val redirectionKey = "A8 F2 14 5F 58 12 60 AF 07 63 97 D6 76 B2 1A 3B" - const val publicKey = "02 6D 28 41 D2 A5 6F D2 FC 3E 2A 1F 03 75 DE 6E 28 8F A8 19 3E 5F 16 49 D3" - const val shareKey = "1A E9 7F 7D C9 73 75 98 AC 02 E0 80 5F A9 C6 AF" - const val fix0836 = "06 A9 12 97 B7 F8 76 25 AF AF D3 EA B4 C8 BC E7 " + const val key00BA = "C1 9C B8 C8 7B 8C 81 BA 9E 9E 7A 89 E1 7A EC 94" + const val key00BAFix = "69 20 D1 14 74 F5 B3 93 E4 D5 02 B3 71 1A CD 2A" - const val key00BA = "C1 9C B8 C8 7B 8C 81 BA 9E 9E 7A 89 E1 7A EC 94" - const val key00BAFix = "69 20 D1 14 74 F5 B3 93 E4 D5 02 B3 71 1A CD 2A" + const val encryptKey = "“BA 42 FF 01 CF B4 FF D2 12 F0 6E A7 1B 7C B3 08”" - const val encryptKey = "“BA 42 FF 01 CF B4 FF D2 12 F0 6E A7 1B 7C B3 08”" + /** + * 0836_622_fix2 + */ + const val passwordSubmissionKey2 = "00 15 00 30 00 01 01 27 9B C7 F5 00 10 65 03 FD 8B 00 00 00 00 00 00 00 00 00 00 00 00 02 90 49 55 33 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B"; + /** + * 0836_622_fix1 + */ + const val passwordSubmissionKey1 = "03 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 01 01 03 00 19"; + /** + * fix_0836_1 + */ + const val key0836 = "EF 4A 36 6A 16 A8 E6 3D 2E EA BD 1F 98 C1 3C DA" - /** - * 0836_622_fix2 - */ - const val passwordSubmissionKey2 = "00 15 00 30 00 01 01 27 9B C7 F5 00 10 65 03 FD 8B 00 00 00 00 00 00 00 00 00 00 00 00 02 90 49 55 33 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B"; - /** - * 0836_622_fix1 - */ - const val passwordSubmissionKey1 = "03 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 01 01 03 00 19"; - /** - * fix_0836_1 - */ - const val key0836 = "EF 4A 36 6A 16 A8 E6 3D 2E EA BD 1F 98 C1 3C DA" + private val hexToByteArrayCacheMap: MutableMap = mutableMapOf() - private val hexToByteArrayCacheMap: MutableMap = mutableMapOf() - - @ExperimentalUnsignedTypes - fun hexToBytes(hex: String): ByteArray { - hex.hashCode().let { id -> - if (hexToByteArrayCacheMap.containsKey(id)) { - return hexToByteArrayCacheMap[id]!!.clone() - } else { - hexToUBytes(hex).toByteArray().let { - hexToByteArrayCacheMap[id] = it.clone(); - return it - } + @ExperimentalUnsignedTypes + fun hexToBytes(hex: String): ByteArray { + hex.hashCode().let { id -> + if (hexToByteArrayCacheMap.containsKey(id)) { + return hexToByteArrayCacheMap[id]!!.clone() + } else { + hexToUBytes(hex).toByteArray().let { + hexToByteArrayCacheMap[id] = it.clone(); + return it } } } - - @ExperimentalUnsignedTypes - fun hexToUBytes(hex: String): UByteArray = Arrays - .stream(hex.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) - .map { value -> value.trim { it <= ' ' } } - .map { s -> s.toUByte(16) } - .collect(Collectors.toList()).toUByteArray() - } + + @ExperimentalUnsignedTypes + fun hexToUBytes(hex: String): UByteArray = Arrays + .stream(hex.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) + .map { value -> value.trim { it <= ' ' } } + .map { s -> s.toUByte(16) } + .collect(Collectors.toList()).toUByteArray() + } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index b19399d84..e6d784a0a 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -11,15 +11,15 @@ import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePack import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.network.packet.login.* import net.mamoe.mirai.task.MiraiThreadPool -import net.mamoe.mirai.utils.ClientLoginStatus -import net.mamoe.mirai.utils.MiraiLogger -import net.mamoe.mirai.utils.getGTK -import net.mamoe.mirai.utils.lazyEncode +import net.mamoe.mirai.utils.* import java.io.Closeable import java.net.DatagramPacket import java.net.DatagramSocket import java.net.InetSocketAddress +import java.util.* +import java.util.concurrent.ScheduledFuture import java.util.concurrent.TimeUnit +import kotlin.reflect.KClass /** * A RobotNetworkHandler is used to connect with Tencent servers. @@ -28,329 +28,421 @@ import java.util.concurrent.TimeUnit */ @Suppress("EXPERIMENTAL_API_USAGE")//to simplify code internal class RobotNetworkHandler(private val robot: Robot) : Closeable { + private val socketHandler: SocketHandler = SocketHandler() - private var socket: DatagramSocket = DatagramSocket((15314 + Math.random() * 100).toInt()) + val debugHandler = DebugHandler() + val loginHandler = LoginHandler() + val messageHandler = MessageHandler() + val actionHandler = ActionHandler() - private var serverIP: String = "" - set(value) { - serverAddress = InetSocketAddress(value, 8000) - field = value + private val packetHandlers: Map, PacketHandler> = mapOf( + DebugHandler::class to debugHandler, + LoginHandler::class to loginHandler, + MessageHandler::class to messageHandler, + ActionHandler::class to actionHandler + ) - restartSocket() - } - - private lateinit var serverAddress: InetSocketAddress private var closed: Boolean = false - private lateinit var token00BA: ByteArray //这些数据全部是login用的 - private lateinit var token0825: ByteArray - private var loginTime: Int = 0 - private lateinit var loginIP: String - private var tgtgtKey: ByteArray? = null - private var tlv0105: ByteArray - /** - * 0828_decr_key - */ - private lateinit var sessionResponseDecryptionKey: ByteArray - - private var verificationCodeSequence: Int = 0//这两个验证码使用 - private var verificationCodeCache: ByteArray? = null//每次包只发一部分验证码来 - private var verificationCodeCacheCount: Int = 1// - private lateinit var verificationToken: ByteArray - - private lateinit var sessionKey: ByteArray//这两个是登录成功后得到的 - private lateinit var sKey: String /** - * Used to access web API(for friends list etc.) + * Not async */ - private lateinit var cookies: String - private var gtk: Int = 0 - private var ignoreMessage: Boolean = false + @ExperimentalUnsignedTypes + fun sendPacket(packet: ClientPacket) { + socketHandler.sendPacket(packet) + } - private var loginState: LoginState? = null - set(value) { - field = value - if (value != null) { - loginHook?.invoke(value) + override fun close() { + this.packetHandlers.values.forEach { + it.close() + } + this.socketHandler.close() + } + + + //private | internal + + internal fun tryLogin(loginHook: ((LoginState) -> Unit)? = null) { + val ipQueue: LinkedList = LinkedList(Protocol.SERVER_IP) + fun login(): Boolean { + val ip = ipQueue.poll() + return if (ip != null) { + this@RobotNetworkHandler.socketHandler.touch(ip) { state -> + if (state == LoginState.UNKNOWN) { + login() + } else { + loginHook?.invoke(state) + } + } + true + } else false + } + login() + } + + @ExperimentalUnsignedTypes + internal fun onPacketReceived(packet: ServerPacket) { + this.packetHandlers.values.forEach { + it.onPacketReceived(packet) + } + } + + + private inner class SocketHandler : Closeable { + private lateinit var socket: DatagramSocket + + internal var serverIP: String = "" + set(value) { + serverAddress = InetSocketAddress(value, 8000) + field = value + + restartSocket() + } + + private var loginHook: ((LoginState) -> Unit)? = null + internal var loginState: LoginState? = null + set(value) { + field = value + if (value != null && value != LoginState.UNKNOWN) { + loginHook?.invoke(value) + } + } + + private lateinit var serverAddress: InetSocketAddress + + private fun restartSocket() { + + socket = DatagramSocket((15314 + Math.random() * 100).toInt()) + socket.close() + socket.connect(this.serverAddress) + Thread { + while (socket.isConnected) { + val packet = DatagramPacket(ByteArray(2048), 2048) + kotlin + .runCatching { socket.receive(packet) } + .onSuccess { + MiraiThreadPool.getInstance().submit { + try { + onPacketReceived(ServerPacket.ofByteArray(packet.data.removeZeroTail())) + } catch (e: Exception) { + e.printStackTrace() + } + } + }.onFailure { + if (it.message == "socket closed") { + if (!closed) { + restartSocket() + } + return@Thread + } + it.printStackTrace() + } + + } + }.start() + } + + /** + * Start network and touch the server + */ + internal fun touch(serverAddress: String, loginHook: ((LoginState) -> Unit)? = null) { + socketHandler.serverIP = serverAddress + if (loginHook != null) { + this.loginHook = loginHook + } + sendPacket(ClientTouchPacket(robot.account.qqNumber, socketHandler.serverIP)) + } + + /** + * Not async + */ + @ExperimentalUnsignedTypes + internal fun sendPacket(packet: ClientPacket) { + try { + packet.encode() + packet.writeHex(Protocol.tail) + + val data = packet.toByteArray() + socket.send(DatagramPacket(data, data.size)) + MiraiLogger info "Packet sent: $packet" + } catch (e: Throwable) { + e.printStackTrace() } } - private var loginHook: ((LoginState) -> Unit)? = null + override fun close() { + this.socket.close() + this.loginState = null + this.loginHook = null + } + } - init { - tlv0105 = lazyEncode { + + private lateinit var sessionKey: ByteArray + + abstract inner class PacketHandler : Closeable { + abstract fun onPacketReceived(packet: ServerPacket) + + override fun close() { + + } + } + + /** + * Kind of [PacketHandler] that prints all packets received in the format of hex byte array. + */ + inner class DebugHandler : PacketHandler() { + override fun onPacketReceived(packet: ServerPacket) { + packet.decode() + MiraiLogger info "Packet received: $packet" + if (packet is ServerEventPacket) { + sendPacket(ClientMessageResponsePacket(robot.account.qqNumber, packet.packetId, sessionKey, packet.eventIdentity)) + } + } + } + + /** + * 处理登录过程 + */ + inner class LoginHandler : PacketHandler() { + private lateinit var token00BA: ByteArray + private lateinit var token0825: ByteArray + private var loginTime: Int = 0 + private lateinit var loginIP: String + private var tgtgtKey: ByteArray? = null + + private var tlv0105: ByteArray = lazyEncode { it.writeHex("01 05 00 30") it.writeHex("00 01 01 02 00 14 01 01 00 10") it.writeRandom(16) it.writeHex("00 14 01 02 00 10") it.writeRandom(16) } - } - /** - * Try to login to server - */ - internal fun tryLogin(loginHook: ((LoginState) -> Unit)? = null) { -//"14.116.136.106", - tryLogin() - } + /** + * 0828_decr_key + */ + private lateinit var sessionResponseDecryptionKey: ByteArray - /** - * Try to login to server - */ - private fun tryLogin(serverAddress: String, loginHook: ((LoginState) -> Unit)? = null) { + private var verificationCodeSequence: Int = 0//这两个验证码使用 + private var verificationCodeCache: ByteArray? = null//每次包只发一部分验证码来 + private var verificationCodeCacheCount: Int = 1// + private lateinit var verificationToken: ByteArray - touch(serverAddress, loginHook) - } - /** - * Start network - */ - private fun touch(serverAddress: String, loginHook: ((LoginState) -> Unit)? = null) { - serverIP = serverAddress - if (loginHook != null) { - this.loginHook = loginHook - } - this.sendPacket(ClientTouchPacket(this.robot.account.qqNumber, this.serverIP)) - } + private var heartbeatFuture: ScheduledFuture<*>? = null + private var sKeyRefresherFuture: ScheduledFuture<*>? = null - private fun restartSocket() { - socket.close() - socket = DatagramSocket((15314 + Math.random() * 100).toInt()) - socket.connect(this.serverAddress) - val zeroByte: Byte = 0 - Thread { - while (true) { - val dp1 = DatagramPacket(ByteArray(2048), 2048) - try { - socket.receive(dp1) - } catch (e: Exception) { - if (e.message == "socket closed") { - if (!closed) { - restartSocket() - } - return@Thread + override fun onPacketReceived(packet: ServerPacket) { + when (packet) { + is ServerTouchResponsePacket -> { + if (packet.serverIP != null) {//redirection + socketHandler.serverIP = packet.serverIP!! + //connect(packet.serverIP!!) + sendPacket(ClientServerRedirectionPacket(packet.serverIP!!, robot.account.qqNumber)) + } else {//password submission + this.loginIP = packet.loginIP + this.loginTime = packet.loginTime + this.token0825 = packet.token0825 + this.tgtgtKey = packet.tgtgtKey + sendPacket(ClientPasswordSubmissionPacket(robot.account.qqNumber, robot.account.password, packet.loginTime, packet.loginIP, packet.tgtgtKey, packet.token0825)) } } - MiraiThreadPool.getInstance().submit { - var i = dp1.data.size - 1 - while (dp1.data[i] == zeroByte) { - --i - } - try { - onPacketReceived(ServerPacket.ofByteArray(dp1.data.copyOfRange(0, i + 1))) - } catch (e: Exception) { - e.printStackTrace() - } - } - } - }.start() - } - @ExperimentalUnsignedTypes - internal fun onPacketReceived(packet: ServerPacket) { - packet.decode() - MiraiLogger info "Packet received: $packet" - if (packet is ServerEventPacket) { - sendPacket(ClientMessageResponsePacket(this.robot.account.qqNumber, packet.packetId, this.sessionKey, packet.eventIdentity)) - } - when (packet) { - is ServerTouchResponsePacket -> { - if (packet.serverIP != null) {//redirection - serverIP = packet.serverIP!! - //connect(packet.serverIP!!) - sendPacket(ClientServerRedirectionPacket(packet.serverIP!!, this.robot.account.qqNumber)) - } else {//password submission - this.loginIP = packet.loginIP - this.loginTime = packet.loginTime - this.token0825 = packet.token0825 - this.tgtgtKey = packet.tgtgtKey - sendPacket(ClientPasswordSubmissionPacket(this.robot.account.qqNumber, this.robot.account.password, packet.loginTime, packet.loginIP, packet.tgtgtKey, packet.token0825)) - } - } - - is ServerLoginResponseFailedPacket -> { - this.loginState = packet.loginState - MiraiLogger error "Login failed: " + packet.loginState.toString() - return - } - - is ServerLoginResponseVerificationCodeInitPacket -> { - //[token00BA]来源之一: 验证码 - this.token00BA = packet.token00BA - this.verificationCodeCache = packet.verifyCodePart1 - - - if (packet.unknownBoolean != null && packet.unknownBoolean!!) { - this.verificationCodeSequence = 1 - sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, this.robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA)) - } - - } - - is ServerVerificationCodeRepeatPacket -> {//todo 这个名字正确么 - this.tgtgtKey = packet.tgtgtKeyUpdate - this.token00BA = packet.token00BA - sendPacket(ClientLoginResendPacket3105(this.robot.account.qqNumber, this.robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA)) - } - - is ServerVerificationCodeTransmissionPacket -> { - this.verificationCodeSequence++ - this.verificationCodeCache = this.verificationCodeCache!! + packet.verificationCodePartN - - this.verificationToken = packet.verificationToken - this.verificationCodeCacheCount++ - - this.token00BA = packet.token00BA - - - //todo 看易语言 count 和 sequence 是怎样变化的 - - - if (packet.transmissionCompleted) { - this.verificationCodeCache - TODO("验证码好了") - } else { - sendPacket(ClientVerificationCodeTransmissionRequestPacket(this.verificationCodeCacheCount, this.robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA)) - } - } - - is ServerLoginResponseSuccessPacket -> { - this.sessionResponseDecryptionKey = packet.sessionResponseDecryptionKey - sendPacket(ClientSessionRequestPacket(this.robot.account.qqNumber, this.serverIP, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105)) - } - - //是ClientPasswordSubmissionPacket之后服务器回复的 - is ServerLoginResponseResendPacket -> { - //if (packet.tokenUnknown != null) { - //this.token00BA = packet.token00BA!! - //println("token00BA changed!!! to " + token00BA.toUByteArray()) - //} - if (packet.flag == ServerLoginResponseResendPacket.Flag.`08 36 31 03`) { - this.tgtgtKey = packet.tgtgtKey - sendPacket(ClientLoginResendPacket3104( - this.robot.account.qqNumber, - this.robot.account.password, - this.loginTime, - this.loginIP, - this.tgtgtKey!!, - this.token0825, - when (packet.tokenUnknown != null) { - true -> packet.tokenUnknown!! - false -> this.token00BA - }, - packet._0836_tlv0006_encr - )) - } else { - sendPacket(ClientLoginResendPacket3106( - this.robot.account.qqNumber, - this.robot.account.password, - this.loginTime, - this.loginIP, - this.tgtgtKey!!, - this.token0825, - when (packet.tokenUnknown != null) { - true -> packet.tokenUnknown!! - false -> this.token00BA - }, - packet._0836_tlv0006_encr - )) - } - } - - - is ServerSessionKeyResponsePacket -> { - this.sessionKey = packet.sessionKey - MiraiThreadPool.getInstance().scheduleWithFixedDelay({ - sendPacket(ClientHeartbeatPacket(this.robot.account.qqNumber, this.sessionKey)) - }, 90000, 90000, TimeUnit.MILLISECONDS) - RobotLoginSucceedEvent(robot).broadcast() - - MiraiThreadPool.getInstance().schedule({ - ignoreMessage = false - }, 2, TimeUnit.SECONDS) - - this.tlv0105 = packet.tlv0105 - sendPacket(ClientChangeOnlineStatusPacket(this.robot.account.qqNumber, this.sessionKey, ClientLoginStatus.ONLINE)) - } - - is ServerLoginSuccessPacket -> { - loginState = LoginState.SUCCEED - sendPacket(ClientSKeyRequestPacket(this.robot.account.qqNumber, this.sessionKey)) - } - - is ServerSKeyResponsePacket -> { - this.sKey = packet.sKey - this.cookies = "uin=o" + this.robot.account.qqNumber + ";skey=" + this.sKey + ";" - - MiraiThreadPool.getInstance().scheduleWithFixedDelay({ - sendPacket(ClientSKeyRefreshmentRequestPacket(this.robot.account.qqNumber, this.sessionKey)) - }, 1800000, 1800000, TimeUnit.MILLISECONDS) - - this.gtk = getGTK(sKey) - sendPacket(ClientAccountInfoRequestPacket(this.robot.account.qqNumber, this.sessionKey)) - } - - is ServerHeartbeatResponsePacket -> { - - } - - is ServerAccountInfoResponsePacket -> { - - } - - - is ServerFriendMessageEventPacket -> { - if (ignoreMessage) { + is ServerLoginResponseFailedPacket -> { + socketHandler.loginState = packet.loginState + MiraiLogger error "Login failed: " + packet.loginState.toString() return } - FriendMessageEvent(this.robot, this.robot.contacts.getQQ(packet.qq), packet.message) + is ServerLoginResponseVerificationCodeInitPacket -> { + //[token00BA]来源之一: 验证码 + this.token00BA = packet.token00BA + this.verificationCodeCache = packet.verifyCodePart1 + + if (packet.unknownBoolean != null && packet.unknownBoolean!!) { + this.verificationCodeSequence = 1 + sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA)) + } + } + + is ServerVerificationCodeRepeatPacket -> {//todo 这个名字正确么 + this.tgtgtKey = packet.tgtgtKeyUpdate + this.token00BA = packet.token00BA + sendPacket(ClientLoginResendPacket3105(robot.account.qqNumber, robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA)) + } + + is ServerVerificationCodeTransmissionPacket -> { + this.verificationCodeSequence++ + this.verificationCodeCache = this.verificationCodeCache!! + packet.verificationCodePartN + + this.verificationToken = packet.verificationToken + this.verificationCodeCacheCount++ + + this.token00BA = packet.token00BA + + + //todo 看易语言 count 和 sequence 是怎样变化的 + + if (packet.transmissionCompleted) { + this.verificationCodeCache + TODO("验证码好了") + } else { + sendPacket(ClientVerificationCodeTransmissionRequestPacket(this.verificationCodeCacheCount, robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA)) + } + } + + is ServerLoginResponseSuccessPacket -> { + this.sessionResponseDecryptionKey = packet.sessionResponseDecryptionKey + sendPacket(ClientSessionRequestPacket(robot.account.qqNumber, socketHandler.serverIP, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105)) + } + + //是ClientPasswordSubmissionPacket之后服务器回复的 + is ServerLoginResponseResendPacket -> { + //if (packet.tokenUnknown != null) { + //this.token00BA = packet.token00BA!! + //println("token00BA changed!!! to " + token00BA.toUByteArray()) + //} + if (packet.flag == ServerLoginResponseResendPacket.Flag.`08 36 31 03`) { + this.tgtgtKey = packet.tgtgtKey + sendPacket(ClientLoginResendPacket3104( + robot.account.qqNumber, + robot.account.password, + this.loginTime, + this.loginIP, + this.tgtgtKey!!, + this.token0825, + when (packet.tokenUnknown != null) { + true -> packet.tokenUnknown!! + false -> this.token00BA + }, + packet._0836_tlv0006_encr + )) + } else { + sendPacket(ClientLoginResendPacket3106( + robot.account.qqNumber, + robot.account.password, + this.loginTime, + this.loginIP, + this.tgtgtKey!!, + this.token0825, + when (packet.tokenUnknown != null) { + true -> packet.tokenUnknown!! + false -> this.token00BA + }, + packet._0836_tlv0006_encr + )) + } + } + + is ServerSessionKeyResponsePacket -> { + sessionKey = packet.sessionKey + heartbeatFuture = MiraiThreadPool.getInstance().scheduleWithFixedDelay({ + sendPacket(ClientHeartbeatPacket(robot.account.qqNumber, sessionKey)) + }, 90000, 90000, TimeUnit.MILLISECONDS) + + RobotLoginSucceedEvent(robot).broadcast() + + //登录成功后会收到大量上次的消息, 忽略掉 + MiraiThreadPool.getInstance().schedule({ + (packetHandlers[MessageHandler::class] as MessageHandler).ignoreMessage = false + }, 2, TimeUnit.SECONDS) + + this.tlv0105 = packet.tlv0105 + sendPacket(ClientChangeOnlineStatusPacket(robot.account.qqNumber, sessionKey, ClientLoginStatus.ONLINE)) + } + + is ServerLoginSuccessPacket -> { + socketHandler.loginState = LoginState.SUCCEED + sendPacket(ClientSKeyRequestPacket(robot.account.qqNumber, sessionKey)) + } + + is ServerSKeyResponsePacket -> { + val actionHandler = packetHandlers[ActionHandler::class] as ActionHandler + actionHandler.sKey = packet.sKey + actionHandler.cookies = "uin=o" + robot.account.qqNumber + ";skey=" + actionHandler.sKey + ";" + + sKeyRefresherFuture = MiraiThreadPool.getInstance().scheduleWithFixedDelay({ + sendPacket(ClientSKeyRefreshmentRequestPacket(robot.account.qqNumber, sessionKey)) + }, 1800000, 1800000, TimeUnit.MILLISECONDS) + + actionHandler.gtk = getGTK(actionHandler.sKey) + sendPacket(ClientAccountInfoRequestPacket(robot.account.qqNumber, sessionKey)) + } + + is ServerEventPacket.Raw -> onPacketReceived(packet.distribute()) + + is ServerVerificationCodePacket.Encrypted -> onPacketReceived(packet.decrypt()) + is ServerLoginResponseVerificationCodeInitPacket.Encrypted -> onPacketReceived(packet.decrypt()) + is ServerLoginResponseResendPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) + is ServerLoginResponseSuccessPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) + is ServerSessionKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionResponseDecryptionKey)) + is ServerTouchResponsePacket.Encrypted -> onPacketReceived(packet.decrypt()) + is ServerSKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(sessionKey)) + is ServerAccountInfoResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(sessionKey)) + is ServerEventPacket.Raw.Encrypted -> onPacketReceived(packet.decrypt(sessionKey)) + + + is ServerAccountInfoResponsePacket, + is ServerHeartbeatResponsePacket, + is UnknownServerPacket -> { + //ignored + } + else -> { + + } } + } - is ServerGroupMessageEventPacket -> { - //todo message chain - //GroupMessageEvent(this.robot, this.robot.contacts.getGroupByNumber(packet.groupNumber), this.robot.contacts.getQQ(packet.qq), packet.message) - } + override fun close() { + this.verificationCodeCache = null + this.tgtgtKey = null - is UnknownServerEventPacket -> { - //unknown message event - } + this.heartbeatFuture?.cancel(true) + this.sKeyRefresherFuture?.cancel(true) - is UnknownServerPacket -> { - - } - - is ServerGroupUploadFileEventPacket -> { - - } - - is ServerEventPacket.Raw -> onPacketReceived(packet.distribute()) - - is ServerVerificationCodePacket.Encrypted -> onPacketReceived(packet.decrypt()) - is ServerLoginResponseVerificationCodeInitPacket.Encrypted -> onPacketReceived(packet.decrypt()) - is ServerLoginResponseResendPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) - is ServerLoginResponseSuccessPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) - is ServerSessionKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionResponseDecryptionKey)) - is ServerTouchResponsePacket.Encrypted -> onPacketReceived(packet.decrypt()) - is ServerSKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey)) - is ServerAccountInfoResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey)) - is ServerEventPacket.Raw.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey)) - - - is ServerSendFriendMessageResponsePacket, - is ServerSendGroupMessageResponsePacket -> { - - } - - else -> throw IllegalArgumentException(packet.toString()) + this.heartbeatFuture = null + this.sKeyRefresherFuture = null } } - internal val packetSystem: PacketSystem = PacketSystem() + /** + * 处理消息事件, 承担消息发送任务. + */ + inner class MessageHandler : PacketHandler() { + internal var ignoreMessage: Boolean = false + + override fun onPacketReceived(packet: ServerPacket) { + when (packet) { + is ServerGroupUploadFileEventPacket -> { + //todo + } + + is ServerFriendMessageEventPacket -> { + if (ignoreMessage) { + return + } + + FriendMessageEvent(robot, robot.contacts.getQQ(packet.qq), packet.message) + } + + is ServerGroupMessageEventPacket -> { + //todo message chain + //GroupMessageEvent(this.robot, robot.contacts.getGroupByNumber(packet.groupNumber), robot.contacts.getQQ(packet.qq), packet.message) + } + + is UnknownServerEventPacket, + is ServerSendFriendMessageResponsePacket, + is ServerSendGroupMessageResponsePacket -> { + //ignored + } + else -> { + //ignored + } + } + } - inner class PacketSystem { fun sendFriendMessage(qq: QQ, message: Message) { TODO() //sendPacket(ClientSendFriendMessagePacket(robot.account.qqNumber, qq.number, sessionKey, message)) @@ -360,31 +452,23 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { TODO() //sendPacket(ClientSendGroupMessagePacket(group.groupId, robot.account.qqNumber, sessionKey, message)) } - } /** - * Not async + * 动作: 获取好友列表, 点赞, 踢人等. + * 处理动作事件, 承担动作任务. */ - @ExperimentalUnsignedTypes - fun sendPacket(packet: ClientPacket) { - try { - packet.encode() - packet.writeHex(Protocol.tail) + inner class ActionHandler : PacketHandler() { + internal lateinit var cookies: String + internal lateinit var sKey: String + internal var gtk: Int = 0 + + override fun onPacketReceived(packet: ServerPacket) { + + } + + override fun close() { - val data = packet.toByteArray() - socket.send(DatagramPacket(data, data.size)) - MiraiLogger info "Packet sent: $packet" - } catch (e: Throwable) { - e.printStackTrace() } } - - override fun close() { - this.socket.close() - this.loginState = null - this.loginHook = null - this.verificationCodeCache = null - this.tgtgtKey = null - } -} +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt index 67d5d3113..73e1e38bc 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt @@ -17,6 +17,7 @@ class ClientAccountInfoRequestPacket( ) : ClientPacket() { override fun encode() { this.writeRandom(2)//part of packet id + this.writeQQ(qq) this.writeHex(Protocol.fixVer2) this.encryptAndWrite(sessionKey) { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt index 0a1c8b975..395b92e56 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt @@ -53,11 +53,13 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { 551, 487 -> LoginState.DEVICE_LOCK 359 -> LoginState.TAKEN_BACK + else -> LoginState.UNKNOWN + /* //unknown 63 -> throw IllegalArgumentException(bytes.size.toString() + " (Unknown error)") 351 -> throw IllegalArgumentException(bytes.size.toString() + " (Illegal package data or Unknown error)")//包数据有误 - else -> throw IllegalArgumentException(bytes.size.toString()) + else -> throw IllegalArgumentException(bytes.size.toString())*/ }, stream) } @@ -112,17 +114,6 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { } -fun DataInputStream.readUntil(byte: Byte): ByteArray { - var buff = byteArrayOf() - var b: Byte - b = readByte() - while (b != byte) { - buff += b - b = readByte() - } - return buff -} - @ExperimentalUnsignedTypes fun DataInputStream.readIP(): String { var buff = "" diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt index 7be53ad7d..e03d96855 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt @@ -14,5 +14,7 @@ enum class LoginState { DEVICE_LOCK,//设备锁 TAKEN_BACK,//被回收 // VERIFICATION_CODE,//需要验证码 - // SUCCEED, + + + UNKNOWN, } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java index d26bd145d..14a05bfdd 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/TEA.java @@ -11,9 +11,8 @@ import java.util.Random; * @author iweiz https://github.com/iweizime/StepChanger/blob/master/app/src/main/java/me/iweizi/stepchanger/qq/Cryptor.java */ public final class TEA { - public static final TEA CRYPTOR_SHARE_KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.shareKey)); - public static final TEA CRYPTOR_0825KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key0825)); - public static final TEA CRYPTOR_00BAKEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key00BA)); + public static final TEA CRYPTOR_SHARE_KEY = new TEA(Protocol.INSTANCE.hexToBytes(Protocol.shareKey)); + public static final TEA CRYPTOR_0825KEY = new TEA(Protocol.INSTANCE.hexToBytes(Protocol.key0825)); private static final long UINT32_MASK = 0xffffffffL; private final long[] mKey; diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt b/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt index 0157ffa82..0d3fd2fca 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt @@ -79,7 +79,7 @@ operator fun File.plus(child: String): File = File(this, child) private const val GTK_BASE_VALUE: Int = 5381 -fun getGTK(sKey: String): Int { +internal fun getGTK(sKey: String): Int { var value = GTK_BASE_VALUE for (c in sKey.toCharArray()) { value += (value shl 5) + c.toInt() @@ -89,7 +89,7 @@ fun getGTK(sKey: String): Int { return value } -fun getCrc32(key: ByteArray): Int = CRC32().let { it.update(key); it.value.toInt() } +internal fun getCrc32(key: ByteArray): Int = CRC32().let { it.update(key); it.value.toInt() } /** @@ -122,3 +122,13 @@ fun Any.getAllDeclaredFields(): List { return list } + +private const val ZERO_BYTE: Byte = 0 + +fun ByteArray.removeZeroTail(): ByteArray { + var i = this.size - 1 + while (this[i] == ZERO_BYTE) { + --i + } + return this.copyOfRange(0, i + 1) +} \ No newline at end of file From 402e8fbb3275a331b02f7fb17ef0fd045cb3f48e Mon Sep 17 00:00:00 2001 From: Him188moe Date: Thu, 5 Sep 2019 22:10:40 +0800 Subject: [PATCH 16/19] Updated robot & network structure --- mirai-core/pom.xml | 6 + .../java/net/mamoe/mirai/MiraiServer.java | 2 +- .../src/main/java/net/mamoe/mirai/Robot.java | 1 - ...MiraiEventManagerKt.kt => EventManager.kt} | 3 + .../mamoe/mirai/event/MiraiEventManager.java | 6 +- .../mamoe/mirai/event/events/MiraiEvent.java | 2 +- .../event/events/network/PacketEvent.java | 19 +++ .../events/network/PacketReceivedEvent.java | 7 + .../events/network/ServerPacketEvent.java | 17 +++ .../network/ServerPacketReceivedEvent.java | 13 ++ .../java/net/mamoe/mirai/network/Protocol.kt | 4 +- .../mirai/network/RobotNetworkHandler.kt | 107 ++++++++++----- .../mirai/network/packet/ClientPacket.kt | 6 +- .../net/mamoe/mirai/network/packet/Session.kt | 6 +- .../net/mamoe/mirai/network/packet/Touch.kt | 2 +- .../mirai/network/packet/VerificationCode.kt | 2 +- .../mirai/network/packet/login/LoginState.kt | 5 +- .../main/java/net/mamoe/mirai/utils/Utils.kt | 2 +- mirai-core/src/test/java/BadQQFilter.kt | 127 ++++++++++++++++++ 19 files changed, 281 insertions(+), 56 deletions(-) rename mirai-core/src/main/java/net/mamoe/mirai/event/{MiraiEventManagerKt.kt => EventManager.kt} (90%) create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketEvent.java create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketReceivedEvent.java create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketEvent.java create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketReceivedEvent.java create mode 100644 mirai-core/src/test/java/BadQQFilter.kt diff --git a/mirai-core/pom.xml b/mirai-core/pom.xml index 3a43788e1..7f61f476c 100644 --- a/mirai-core/pom.xml +++ b/mirai-core/pom.xml @@ -56,6 +56,12 @@ snakeyaml 1.18 + + org.jetbrains.kotlin + kotlin-reflect + 1.3.41 + compile + diff --git a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java index 9d9074da2..a2a1556c0 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java @@ -120,7 +120,7 @@ public class MiraiServer { this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> { try { Robot robot = new Robot(section); - robot.network.tryLogin$mirai_core(state -> { + robot.network.tryLogin$mirai_core((robot1, state) -> { if (state == LoginState.SUCCEED) { Robot.instances.add(robot); } else { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java index 0c3a1c169..7d25a04f0 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java @@ -89,7 +89,6 @@ public final class Robot implements Closeable { public void close() { this.network.close(); - this.owners.clear(); this.contacts.groups.values().forEach(Group::close); this.contacts.groups.clear(); this.contacts.qqs.clear(); diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManagerKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/EventManager.kt similarity index 90% rename from mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManagerKt.kt rename to mirai-core/src/main/java/net/mamoe/mirai/event/EventManager.kt index 1ae0337c2..42e6765f0 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManagerKt.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/EventManager.kt @@ -3,6 +3,9 @@ package net.mamoe.mirai.event import net.mamoe.mirai.event.events.MiraiEvent import kotlin.reflect.KClass +object EventManager : MiraiEventManager() +typealias MiraiEventManagerKt = EventManager +typealias EventMgr = EventManager fun , E : MiraiEvent> C.hookAlways(hook: (E) -> Unit) { MiraiEventManager.getInstance().hookAlways(MiraiEventHook(this, hook)) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManager.java b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManager.java index 385d83632..d93ba6684 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManager.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManager.java @@ -10,14 +10,12 @@ import java.util.function.Predicate; import java.util.stream.Collectors; public class MiraiEventManager { - private MiraiEventManager() { + MiraiEventManager() { } - private static MiraiEventManager instance = new MiraiEventManager(); - public static MiraiEventManager getInstance() { - return MiraiEventManager.instance; + return EventManager.INSTANCE; } private final ReentrantReadWriteLock hooksLock = new ReentrantReadWriteLock(); diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/MiraiEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/MiraiEvent.java index 0915b523a..a8509e7f3 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/MiraiEvent.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/MiraiEvent.java @@ -11,7 +11,7 @@ public abstract class MiraiEvent { public boolean isCancelled() { if (!(this instanceof Cancellable)) { - throw new EventException("Event is not Cancellable"); + return false; } return this.cancelled; } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketEvent.java new file mode 100644 index 000000000..119f87933 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketEvent.java @@ -0,0 +1,19 @@ +package net.mamoe.mirai.event.events.network; + +import net.mamoe.mirai.event.events.MiraiEvent; +import net.mamoe.mirai.network.packet.Packet; + +/** + * @author Him188moe + */ +public abstract class PacketEvent extends MiraiEvent { + private final Packet packet; + + public PacketEvent(Packet packet) { + this.packet = packet; + } + + public Packet getPacket() { + return packet; + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketReceivedEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketReceivedEvent.java new file mode 100644 index 000000000..77b697050 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketReceivedEvent.java @@ -0,0 +1,7 @@ +package net.mamoe.mirai.event.events.network; + +/** + * @author Him188moe + */ +public class PacketReceivedEvent { +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketEvent.java new file mode 100644 index 000000000..c90e6a284 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketEvent.java @@ -0,0 +1,17 @@ +package net.mamoe.mirai.event.events.network; + +import net.mamoe.mirai.network.packet.ServerPacket; + +/** + * @author Him188moe + */ +public abstract class ServerPacketEvent extends PacketEvent { + public ServerPacketEvent(ServerPacket packet) { + super(packet); + } + + @Override + public ServerPacket getPacket() { + return (ServerPacket) super.getPacket(); + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketReceivedEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketReceivedEvent.java new file mode 100644 index 000000000..77fa219ea --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketReceivedEvent.java @@ -0,0 +1,13 @@ +package net.mamoe.mirai.event.events.network; + +import net.mamoe.mirai.event.events.Cancellable; +import net.mamoe.mirai.network.packet.ServerPacket; + +/** + * @author Him188moe + */ +public class ServerPacketReceivedEvent extends ServerPacketEvent implements Cancellable { + public ServerPacketReceivedEvent(ServerPacket packet) { + super(packet); + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt index 2e33a4f20..d639dffa7 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt @@ -13,13 +13,13 @@ object Protocol { add("183.60.56.29") arrayOf( - "sz2.tencent.com", "sz3.tencent.com", "sz4.tencent.com", "sz5.tencent.com", "sz6.tencent.com", "sz8.tencent.com", - "sz9.tencent.com" + "sz9.tencent.com", + "sz2.tencent.com" ).forEach { this.add(InetAddress.getByName(it).hostAddress) } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index e6d784a0a..22081cc11 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -3,8 +3,10 @@ package net.mamoe.mirai.network import net.mamoe.mirai.Robot import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.event.events.network.ServerPacketReceivedEvent import net.mamoe.mirai.event.events.qq.FriendMessageEvent import net.mamoe.mirai.event.events.robot.RobotLoginSucceedEvent +import net.mamoe.mirai.event.hookWhile import net.mamoe.mirai.message.Message import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket @@ -35,7 +37,7 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { val messageHandler = MessageHandler() val actionHandler = ActionHandler() - private val packetHandlers: Map, PacketHandler> = mapOf( + private val packetHandlers: Map, PacketHandler> = linkedMapOf( DebugHandler::class to debugHandler, LoginHandler::class to loginHandler, MessageHandler::class to messageHandler, @@ -63,16 +65,22 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { //private | internal - internal fun tryLogin(loginHook: ((LoginState) -> Unit)? = null) { + /** + * 仅当 [LoginState] 非 [LoginState.UNKNOWN] 且非 [LoginState.TIMEOUT] 才会调用 [loginHook]. + * 如果要输入验证码, 那么会以参数 [LoginState.VERIFICATION_CODE] 调用 [loginHandler], 登录完成后再以 [LoginState.SUCCEED] 调用 [loginHandler] + */ + internal fun tryLogin(loginHook: (Robot.(LoginState) -> Unit)? = null) { val ipQueue: LinkedList = LinkedList(Protocol.SERVER_IP) fun login(): Boolean { val ip = ipQueue.poll() return if (ip != null) { this@RobotNetworkHandler.socketHandler.touch(ip) { state -> - if (state == LoginState.UNKNOWN) { + if (state == LoginState.UNKNOWN || state == LoginState.TIMEOUT) { login() } else { - loginHook?.invoke(state) + if (loginHook != null) { + robot.loginHook(state) + } } } true @@ -82,7 +90,12 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { } @ExperimentalUnsignedTypes - internal fun onPacketReceived(packet: ServerPacket) { + internal fun distributePacket(packet: ServerPacket) { + packet.decode() + if (ServerPacketReceivedEvent(packet).broadcast().isCancelled) { + debugHandler.onPacketReceived(packet) + return + } this.packetHandlers.values.forEach { it.onPacketReceived(packet) } @@ -90,11 +103,10 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { private inner class SocketHandler : Closeable { - private lateinit var socket: DatagramSocket + private var socket: DatagramSocket? = null internal var serverIP: String = "" set(value) { - serverAddress = InetSocketAddress(value, 8000) field = value restartSocket() @@ -104,36 +116,29 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { internal var loginState: LoginState? = null set(value) { field = value - if (value != null && value != LoginState.UNKNOWN) { + if (value != null) { loginHook?.invoke(value) } } - private lateinit var serverAddress: InetSocketAddress - private fun restartSocket() { - - socket = DatagramSocket((15314 + Math.random() * 100).toInt()) - socket.close() - socket.connect(this.serverAddress) + socket?.close() + socket = DatagramSocket(0) + socket!!.connect(InetSocketAddress(serverIP, 8000)) Thread { - while (socket.isConnected) { + while (socket!!.isConnected) { val packet = DatagramPacket(ByteArray(2048), 2048) - kotlin - .runCatching { socket.receive(packet) } + kotlin.runCatching { socket!!.receive(packet) } .onSuccess { MiraiThreadPool.getInstance().submit { try { - onPacketReceived(ServerPacket.ofByteArray(packet.data.removeZeroTail())) + distributePacket(ServerPacket.ofByteArray(packet.data.removeZeroTail())) } catch (e: Exception) { e.printStackTrace() } } }.onFailure { - if (it.message == "socket closed") { - if (!closed) { - restartSocket() - } + if (it.message == "Socket closed" || it.message == "socket closed") { return@Thread } it.printStackTrace() @@ -147,11 +152,16 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { * Start network and touch the server */ internal fun touch(serverAddress: String, loginHook: ((LoginState) -> Unit)? = null) { + MiraiLogger.info("Connecting server: $serverAddress") socketHandler.serverIP = serverAddress if (loginHook != null) { this.loginHook = loginHook } sendPacket(ClientTouchPacket(robot.account.qqNumber, socketHandler.serverIP)) + waitForPacket(ServerTouchResponsePacket::class, 100) { + MiraiLogger.error(" Timeout") + loginHook?.invoke(LoginState.TIMEOUT) + } } /** @@ -159,20 +169,46 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { */ @ExperimentalUnsignedTypes internal fun sendPacket(packet: ClientPacket) { + checkNotNull(socket) { "socket closed" } + try { packet.encode() packet.writeHex(Protocol.tail) val data = packet.toByteArray() - socket.send(DatagramPacket(data, data.size)) + socket!!.send(DatagramPacket(data, data.size)) MiraiLogger info "Packet sent: $packet" } catch (e: Throwable) { e.printStackTrace() } } + @Suppress("UNCHECKED_CAST") + private fun

waitForPacket(packetClass: KClass

, timeoutMillis: Long, timeout: () -> Unit) { + var got = false + ServerPacketReceivedEvent::class.hookWhile { + if (packetClass.isInstance(it.packet)) { + got = true + true + } else { + false + } + } + + MiraiThreadPool.getInstance().submit { + val startingTime = System.currentTimeMillis() + while (!got) { + if (System.currentTimeMillis() - startingTime > timeoutMillis) { + timeout.invoke() + return@submit + } + Thread.sleep(10) + } + } + } + override fun close() { - this.socket.close() + this.socket?.close() this.loginState = null this.loginHook = null } @@ -194,7 +230,6 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { */ inner class DebugHandler : PacketHandler() { override fun onPacketReceived(packet: ServerPacket) { - packet.decode() MiraiLogger info "Packet received: $packet" if (packet is ServerEventPacket) { sendPacket(ClientMessageResponsePacket(robot.account.qqNumber, packet.packetId, sessionKey, packet.eventIdentity)) @@ -274,6 +309,8 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { } is ServerVerificationCodeTransmissionPacket -> { + socketHandler.loginState = LoginState.VERIFICATION_CODE + this.verificationCodeSequence++ this.verificationCodeCache = this.verificationCodeCache!! + packet.verificationCodePartN @@ -371,17 +408,17 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { sendPacket(ClientAccountInfoRequestPacket(robot.account.qqNumber, sessionKey)) } - is ServerEventPacket.Raw -> onPacketReceived(packet.distribute()) + is ServerEventPacket.Raw -> distributePacket(packet.distribute()) - is ServerVerificationCodePacket.Encrypted -> onPacketReceived(packet.decrypt()) - is ServerLoginResponseVerificationCodeInitPacket.Encrypted -> onPacketReceived(packet.decrypt()) - is ServerLoginResponseResendPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) - is ServerLoginResponseSuccessPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) - is ServerSessionKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionResponseDecryptionKey)) - is ServerTouchResponsePacket.Encrypted -> onPacketReceived(packet.decrypt()) - is ServerSKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(sessionKey)) - is ServerAccountInfoResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(sessionKey)) - is ServerEventPacket.Raw.Encrypted -> onPacketReceived(packet.decrypt(sessionKey)) + is ServerVerificationCodePacket.Encrypted -> distributePacket(packet.decrypt()) + is ServerLoginResponseVerificationCodeInitPacket.Encrypted -> distributePacket(packet.decrypt()) + is ServerLoginResponseResendPacket.Encrypted -> distributePacket(packet.decrypt(this.tgtgtKey!!)) + is ServerLoginResponseSuccessPacket.Encrypted -> distributePacket(packet.decrypt(this.tgtgtKey!!)) + is ServerSessionKeyResponsePacket.Encrypted -> distributePacket(packet.decrypt(this.sessionResponseDecryptionKey)) + is ServerTouchResponsePacket.Encrypted -> distributePacket(packet.decrypt()) + is ServerSKeyResponsePacket.Encrypted -> distributePacket(packet.decrypt(sessionKey)) + is ServerAccountInfoResponsePacket.Encrypted -> distributePacket(packet.decrypt(sessionKey)) + is ServerEventPacket.Raw.Encrypted -> distributePacket(packet.decrypt(sessionKey)) is ServerAccountInfoResponsePacket, diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt index a31ed32e9..e21289fd9 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt @@ -152,10 +152,6 @@ fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, lo } } -fun main() { - -} - /* @ExperimentalUnsignedTypes fun main() { @@ -164,7 +160,7 @@ fun main() { @ExperimentalUnsignedTypes @TestedSuccessfully -fun DataOutputStream.writeCRC32() = writeCRC32(getRandomKey(16)) +fun DataOutputStream.writeCRC32() = writeCRC32(getRandomByteArray(16)) @ExperimentalUnsignedTypes diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt index ee1dadd85..6d69bef64 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt @@ -3,7 +3,7 @@ package net.mamoe.mirai.network.packet import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.utils.ByteArrayDataOutputStream import net.mamoe.mirai.utils.TEA -import net.mamoe.mirai.utils.getRandomKey +import net.mamoe.mirai.utils.getRandomByteArray import net.mamoe.mirai.utils.lazyEncode import java.io.DataInputStream import java.net.InetAddress @@ -44,12 +44,12 @@ class ClientSessionRequestPacket( this.write(tlv0105) this.writeHex("01 0B 00 85 00 02") this.writeHex("B9 ED EF D7 CD E5 47 96 7A B5 28 34 CA 93 6B 5C")//fix2 - this.write(getRandomKey(1)) + this.write(getRandomByteArray(1)) this.writeHex("10 00 00 00 00 00 00 00 02") //fix3 this.writeHex("00 63 3E 00 63 02 04 03 06 02 00 04 00 52 D9 00 00 00 00 A9 58 3E 6D 6D 49 AA F6 A6 D9 33 0A E7 7E 36 84 03 01 00 00 68 20 15 8B 00 00 01 02 00 00 03 00 07 DF 00 0A 00 0C 00 01 00 04 00 03 00 04 20 5C 00") - this.write(getRandomKey(32))//md5 32 + this.write(getRandomByteArray(32))//md5 32 this.writeHex("68") this.writeHex("00 00 00 00 00 2D 00 06 00 01") diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt index 6e10d37a9..ca14e3b38 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt @@ -40,7 +40,7 @@ class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inp loginTime = input.readInt() loginIP = input.readIP() - tgtgtKey = getRandomKey(16) + tgtgtKey = getRandomByteArray(16) } else -> { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt index e2e3366a3..5f4b6bdae 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt @@ -82,7 +82,7 @@ class ServerVerificationCodeRepeatPacket(input: DataInputStream) : ServerVerific @ExperimentalUnsignedTypes override fun decode() { token00BA = this.input.readNBytesAt(10, 56) - tgtgtKeyUpdate = getRandomKey(16) + tgtgtKeyUpdate = getRandomByteArray(16) } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt index e03d96855..c2168c03c 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt @@ -13,8 +13,11 @@ enum class LoginState { UNKNOWN_QQ_NUMBER,//你输入的帐号不存在 DEVICE_LOCK,//设备锁 TAKEN_BACK,//被回收 - // VERIFICATION_CODE,//需要验证码 + + + VERIFICATION_CODE,//需要验证码 UNKNOWN, + TIMEOUT, } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt b/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt index 0d3fd2fca..9f6d6b347 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt @@ -69,7 +69,7 @@ open class ByteArrayDataOutputStream : DataOutputStream(ByteArrayOutputStream()) fun lazyEncode(t: (ByteArrayDataOutputStream) -> Unit): ByteArray = ByteArrayDataOutputStream().let { t(it); return it.toByteArray() } @ExperimentalUnsignedTypes -fun getRandomKey(length: Int): ByteArray { +fun getRandomByteArray(length: Int): ByteArray { val bytes = LinkedList() repeat(length) { bytes.add((Math.random() * 255).toByte()) } return bytes.toByteArray() diff --git a/mirai-core/src/test/java/BadQQFilter.kt b/mirai-core/src/test/java/BadQQFilter.kt new file mode 100644 index 000000000..22114508e --- /dev/null +++ b/mirai-core/src/test/java/BadQQFilter.kt @@ -0,0 +1,127 @@ +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import net.mamoe.mirai.Robot +import net.mamoe.mirai.network.packet.login.LoginState +import net.mamoe.mirai.utils.RobotAccount +import java.util.* + +/** + * @author Him188moe + */ + +val qqList = "2258868346----123456789.\n" + + "1545483785----yuk7k1dxnf3jn5\n" + + "2948786488----123123123\n" + + "3059674084----qq123456\n" + + "1918079979----123456789.\n" + + "3050478794----18872590321\n" + + "3331537204----123456789.\n" + + "2128659972----123456789.\n" + + "3435376516----abc123456\n" + + "2980527804----a123456\n" + + "2752195782----qq123456789\n" + + "3130257966----13415986622\n" + + "1802730396----123456789\n" + + "3021732783----15866103923\n" + + "306499606----abc123456\n" + + "2893904328----abc123456\n" + + "1765904806----123456789\n" + + "3254202261----15223045268\n" + + "2947707697----abc123456\n" + + "3500959200----123456789.\n" + + "2169513531----123456789.\n" + + "2983688661----a123456\n" + + "1246882194----pz49779866\n" + + "2315275635----147258369\n" + + "2802294904----123456789\n" + + "2955364492----1234567890\n" + + "1753325115----123456789\n" + + "2642725191----qq123456\n" + + "2152972686----123456789.\n" + + "2845953617----123456789.\n" + + "3329641753----123456789.\n" + + "1458302685----123456789a\n" + + "2351156352----987654321\n" + + "2304786984----fkhwt53787\n" + + "3322756212----123456789.\n" + + "3187253283----123456789.\n" + + "3168715730----147258369\n" + + "2189916732----18831892323\n" + + "2965337631----123456789.\n" + + "1901802165----123456789.\n" + + "414015319----abc123456\n" + + "3400636089----123456789a\n" + + "3530336304----seoua80060\n" + + "3147312971----123456789.\n" + + "3011083526----yp70y9\n" + + "286888078----abc123456\n" + + "3126754112----1234567890\n" + + "2924643025----123123123\n" + + "341870356----ncvhZtQD\n" + + "3358177328----123456789a\n" + + "1396419201----eakuj14475\n" + + "3541159580----123456789.\n" + + "2540245592----1234567890\n" + + "2024802855----123456789.\n" + + "2578309660----1234567890\n" + + "1934965091----123456789.\n" + + "3449408956----a123456789\n" + + "2509348670----123456789.\n" + + "2305961679----123456789.\n" + + "3532858521----123456789.\n" + + "3308276898----123456789a\n" + + "1760897490----123456789\n" + + "2920800012----123123123\n" + + "2923942248----123123123\n" + + "3216600579----13882755274\n" + + "3100259299----qq123456\n" + + "3242723735----1234567890\n" + + "2142733062----123456789.\n" + + "1557689693----123456789\n" + + "3505693439----sb2662vqy6q\n" + + "3231125974----123456789.\n" + + "3433048975----13893690883\n" + + "3168017129----18780999209\n" + + "2922045831----123123123\n" + + "3578152022----a123456789\n" + + "2116254935----147258369\n" + + "3158479284----1234567890\n" + + "3149394424----qq123456789\n" + + "2829521712----123456789.\n" + + "3218671461----123456789.\n" + + "3035873094----123456789a\n" + + "2224518667----147258369\n" + + "3175801590----123456789.\n" + + "3203228181----123456789a\n" + + "3213497536----123456789a\n" + + "3377317115----123456789\n" + + "2672537341----qq123456789\n" + + "2945957617----123123123\n" + + "2763390197----123456789.\n" + + "3322711709----123456789." + + +fun main() { + val goodRobotList = Collections.synchronizedList(mutableListOf()) + + qqList.split("\n").forEach { + GlobalScope.launch { + val strings = it.split("----") + Robot(RobotAccount(strings[0].toLong(), strings[1].let { password -> + if (password.endsWith(".")) { + return@let password.substring(0, password.length - 1) + } + return@let password + }), listOf()).network.tryLogin { state -> + if (!(state == LoginState.BLOCKED || state == LoginState.DEVICE_LOCK || state == LoginState.WRONG_PASSWORD)) { + goodRobotList.add(this) + } + } + } + } + + Thread.sleep(9 * 3000) + + println(goodRobotList.joinToString("\n") { it.account.qqNumber.toString() + " " + it.account.password }) +} + From 305a7a6f73105d35e797548e84aeb97c17e78670 Mon Sep 17 00:00:00 2001 From: Him188moe Date: Fri, 6 Sep 2019 22:00:16 +0800 Subject: [PATCH 17/19] Updated events and KDocs --- .../java/net/mamoe/mirai/MiraiServer.java | 88 +++++++-------- .../src/main/java/net/mamoe/mirai/Robot.java | 15 +++ .../main/java/net/mamoe/mirai/contact/QQ.kt | 7 +- .../net/mamoe/mirai/event/AsyncEvent.java | 27 +++++ .../net/mamoe/mirai/event/AsyncEventKt.kt | 14 +++ .../mirai/event/{events => }/Cancellable.java | 2 +- .../net/mamoe/mirai/event/MiraiEvent.java | 35 ++++++ .../net/mamoe/mirai/event/MiraiEventHook.java | 23 ++-- .../net/mamoe/mirai/event/MiraiEventHookKt.kt | 31 ++++++ .../net/mamoe/mirai/event/MiraiEventKt.kt | 8 ++ .../mamoe/mirai/event/MiraiEventManager.java | 51 ++++++--- ...EventManager.kt => MiraiEventManagerKt.kt} | 36 ++++++- .../mamoe/mirai/event/events/MiraiEvent.java | 53 --------- .../events/network/BeforePacketSendEvent.java | 14 +++ .../events/network/ClientPacketEvent.java | 18 ++++ .../event/events/network/PacketEvent.java | 9 +- .../events/network/PacketReceivedEvent.java | 7 -- .../network/ServerPacketReceivedEvent.java | 8 +- .../mirai/event/events/robot/RobotEvent.java | 2 +- .../mirai/event/events/robot/RobotEvents.kt | 3 +- .../events/robot/RobotLoginSucceedEvent.java | 1 - .../events/server/ServerDisableEvent.java | 7 -- .../events/server/ServerDisabledEvent.java | 8 ++ .../events/server/ServerEnableEvent.java | 8 -- .../events/server/ServerEnabledEvent.java | 9 ++ .../java/net/mamoe/mirai/message/Message.java | 9 +- .../java/net/mamoe/mirai/message/MessageKt.kt | 5 + .../net/mamoe/mirai/message/defaults/At.java | 2 + .../mirai/network/RobotNetworkHandler.kt | 102 +++++++++++------- .../mirai/network/packet/ServerPacket.kt | 4 +- .../mirai/network/packet/VerificationCode.kt | 1 - .../mirai/network/packet/login/LoginState.kt | 39 +++++-- .../mamoe/mirai/plugin/MiraiPluginBase.java | 12 ++- .../mamoe/mirai/task/MiraiTaskManager.java | 4 +- .../{MiraiSetting.java => MiraiSettings.java} | 16 ++- mirai-core/src/test/java/BadQQFilter.kt | 8 +- 36 files changed, 467 insertions(+), 219 deletions(-) create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEvent.java create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEventKt.kt rename mirai-core/src/main/java/net/mamoe/mirai/event/{events => }/Cancellable.java (79%) create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEvent.java create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHookKt.kt create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventKt.kt rename mirai-core/src/main/java/net/mamoe/mirai/event/{EventManager.kt => MiraiEventManagerKt.kt} (63%) delete mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/events/MiraiEvent.java create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/events/network/BeforePacketSendEvent.java create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ClientPacketEvent.java delete mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketReceivedEvent.java delete mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisableEvent.java create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisabledEvent.java delete mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnableEvent.java create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnabledEvent.java rename mirai-core/src/main/java/net/mamoe/mirai/utils/setting/{MiraiSetting.java => MiraiSettings.java} (83%) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java index a2a1556c0..81ba8639c 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java @@ -2,22 +2,25 @@ package net.mamoe.mirai; import lombok.Getter; import net.mamoe.mirai.event.MiraiEventManager; -import net.mamoe.mirai.event.events.server.ServerDisableEvent; -import net.mamoe.mirai.event.events.server.ServerEnableEvent; +import net.mamoe.mirai.event.events.server.ServerDisabledEvent; +import net.mamoe.mirai.event.events.server.ServerEnabledEvent; import net.mamoe.mirai.network.packet.login.LoginState; import net.mamoe.mirai.task.MiraiTaskManager; import net.mamoe.mirai.utils.LoggerTextFormat; import net.mamoe.mirai.utils.MiraiLogger; import net.mamoe.mirai.utils.config.MiraiConfig; import net.mamoe.mirai.utils.config.MiraiConfigSection; -import net.mamoe.mirai.utils.setting.MiraiSetting; import net.mamoe.mirai.utils.setting.MiraiSettingListSection; import net.mamoe.mirai.utils.setting.MiraiSettingMapSection; +import net.mamoe.mirai.utils.setting.MiraiSettings; import java.io.File; import java.io.IOException; import java.util.Scanner; +/** + * @author NaturalHG + */ public class MiraiServer { private static MiraiServer instance; @@ -25,10 +28,8 @@ public class MiraiServer { return instance; } - //mirai version private final static String MIRAI_VERSION = "1.0.0"; - //qq version private final static String QQ_VERSION = "4.9.0"; @@ -46,30 +47,30 @@ public class MiraiServer { @Getter MiraiLogger logger; - MiraiSetting setting; + MiraiSettings settings; MiraiConfig qqs; - protected MiraiServer() { + MiraiServer() { instance = this; - this.onLoad(); - this.onEnable(); + this.onLoaded(); + this.onEnabled(); } private boolean enabled; - protected void shutdown() { + void shutdown() { if (this.enabled) { getLogger().info("About to shutdown Mirai"); - this.getEventManager().broadcastEvent(new ServerDisableEvent()); + this.eventManager.broadcastEventAsync(new ServerDisabledEvent()); getLogger().info("Data have been saved"); } } - private void onLoad() { + private void onLoaded() { this.parentFolder = new File(System.getProperty("user.dir")); this.unix = !System.getProperties().getProperty("os.name").toUpperCase().contains("WINDOWS"); @@ -86,7 +87,7 @@ public class MiraiServer { if (!setting.exists()) { this.initSetting(setting); } else { - this.setting = new MiraiSetting(setting); + this.settings = new MiraiSettings(setting); } File qqs = new File(this.parentFolder + "/QQ.yml"); @@ -114,27 +115,6 @@ public class MiraiServer { }); */ - getLogger().info("ready to connect"); - - - this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> { - try { - Robot robot = new Robot(section); - robot.network.tryLogin$mirai_core((robot1, state) -> { - if (state == LoginState.SUCCEED) { - Robot.instances.add(robot); - } else { - robot.close(); - } - return null; - }); - - } catch (Throwable e) { - e.printStackTrace(); - getLogger().error("Could not load QQ robots config!"); - System.exit(1); - } - }); } private void initSetting(File setting) { @@ -147,21 +127,21 @@ public class MiraiServer { } catch (IOException e) { e.printStackTrace(); } - this.setting = new MiraiSetting(setting); - MiraiSettingMapSection network = this.setting.getMapSection("network"); + this.settings = new MiraiSettings(setting); + MiraiSettingMapSection network = this.settings.getMapSection("network"); network.set("enable_proxy", "not supporting yet"); - MiraiSettingListSection proxy = this.setting.getListSection("proxy"); + MiraiSettingListSection proxy = this.settings.getListSection("proxy"); proxy.add("1.2.3.4:95"); proxy.add("1.2.3.4:100"); - MiraiSettingMapSection worker = this.setting.getMapSection("worker"); + MiraiSettingMapSection worker = this.settings.getMapSection("worker"); worker.set("core_task_pool_worker_amount", 5); - MiraiSettingMapSection plugin = this.setting.getMapSection("plugin"); + MiraiSettingMapSection plugin = this.settings.getMapSection("plugin"); plugin.set("debug", false); - this.setting.save(); + this.settings.save(); getLogger().info("initialized; changing can be made in setting file: " + setting.toString()); } @@ -187,11 +167,35 @@ public class MiraiServer { getLogger().info("QQ account initialized; changing can be made in Config file: " + qqConfig.toString()); } - private void onEnable() { - this.eventManager.broadcastEvent(new ServerEnableEvent()); + private void onEnabled() { this.enabled = true; + this.eventManager.broadcastEventAsync(new ServerEnabledEvent()); getLogger().info(LoggerTextFormat.GREEN + "Server enabled; Welcome to Mirai"); getLogger().info("Mirai Version=" + MiraiServer.MIRAI_VERSION + " QQ Version=" + MiraiServer.QQ_VERSION); + + getLogger().info("Initializing [Robot]s"); + + this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> { + getLogger().info("Initializing [Robot] " + section.getString("account")); + try { + Robot robot = new Robot(section); + var state = robot.network.tryLogin$mirai_core().get(); + //robot.network.tryLogin$mirai_core().whenComplete((state, e) -> { + if (state == LoginState.SUCCEED) { + Robot.instances.add(robot); + getLogger().info(" Succeed"); + } else { + getLogger().error(" Failed with error " + state); + robot.close(); + } + // }).get(); + + } catch (Throwable e) { + e.printStackTrace(); + getLogger().error("Could not load QQ robots config!"); + System.exit(1); + } + }); } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java index 7d25a04f0..d4e711deb 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java @@ -13,6 +13,21 @@ import java.io.Closeable; import java.util.*; /** + * Mirai 的机器人. 一个机器人实例登录一个 QQ 账号. + * Mirai 为多账号设计, 可同时维护多个机器人账号. + *
+ * {@link Robot} 由 2 个模块组成. + * {@linkplain ContactSystem 联系人管理}: 可通过 {@link Robot#contacts} 访问 + * {@linkplain RobotNetworkHandler 网络处理器}: 可通过 {@link Robot#network} 访问 + *
+ * 另外地, 若你需要得到机器人的 QQ 账号, 请访问 {@link Robot#account} + * 若你需要得到服务器上所有机器人列表, 请访问 {@link Robot#instances} + * + * @author Him188moe + * @author NatrualHG + * @see net.mamoe.mirai.contact.Contact + * + *

* Robot that is the base of the whole program. * It contains a {@link ContactSystem}, which manage contacts such as {@link QQ} and {@link Group}. */ diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt index 2b8fb792d..af009045e 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt @@ -5,8 +5,11 @@ import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.defaults.At /** + * QQ 账号. + * 注意: 一个 [QQ] 实例并不是独立的, 它属于一个 [Robot]. + * * A QQ instance helps you to receive message from or send message to. - * Notice that one QQ instance belong to one [Robot], that is, QQ instances from different [Robot] are NOT the same. + * Notice that, one QQ instance belong to one [Robot], that is, QQ instances from different [Robot] are NOT the same. * * @author Him188moe */ @@ -21,6 +24,8 @@ class QQ(robot: Robot, number: Long) : Contact(robot, number) { /** * At(@) this account. + * + * @return an instance of [Message]. */ fun at(): At { return At(this) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEvent.java new file mode 100644 index 000000000..583f0dc2a --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEvent.java @@ -0,0 +1,27 @@ +package net.mamoe.mirai.event; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +/** + * 实现这个接口的事件可以被异步执行或阻塞执行 + * + * @author Him188moe + * @see AsyncEventKt 若你使用 kotlin, 请查看针对 kotlin 的优化实现 + */ +public interface AsyncEvent { + + default CompletableFuture broadcastAsync() { + return MiraiEventManager.getInstance().broadcastEventAsync(this); + } + + @SuppressWarnings("unchecked") + default CompletableFuture broadcastEventAsync(Consumer callback) { + return MiraiEventManager.getInstance().broadcastEventAsync((E) this, callback); + } + + @SuppressWarnings("unchecked") + default CompletableFuture broadcastEventAsync(Runnable callback) { + return MiraiEventManager.getInstance().broadcastEventAsync((E) this, callback); + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEventKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEventKt.kt new file mode 100644 index 000000000..32490d42a --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEventKt.kt @@ -0,0 +1,14 @@ +@file:JvmName("AsyncEventKt") + +package net.mamoe.mirai.event + +import java.util.concurrent.CompletableFuture +import java.util.function.Consumer + +fun E.broadcastAsync(callback: Consumer): CompletableFuture { + return MiraiEventManager.getInstance().broadcastEventAsync(this, callback) +} + +fun E.broadcastAsync(callback: Runnable): CompletableFuture { + return MiraiEventManager.getInstance().broadcastEventAsync(this, callback) +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/Cancellable.java b/mirai-core/src/main/java/net/mamoe/mirai/event/Cancellable.java similarity index 79% rename from mirai-core/src/main/java/net/mamoe/mirai/event/events/Cancellable.java rename to mirai-core/src/main/java/net/mamoe/mirai/event/Cancellable.java index 59167fda0..e12d0cb9b 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/Cancellable.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/Cancellable.java @@ -1,4 +1,4 @@ -package net.mamoe.mirai.event.events; +package net.mamoe.mirai.event; /** * @author NaturalHG diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEvent.java new file mode 100644 index 000000000..efa532ff0 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEvent.java @@ -0,0 +1,35 @@ +package net.mamoe.mirai.event; + +import net.mamoe.mirai.utils.EventException; + +/** + * @author NatrualHG + * @see AsyncEvent + */ +public abstract class MiraiEvent { + + private boolean cancelled; + + public boolean isCancelled() { + if (!(this instanceof Cancellable)) { + return false; + } + return this.cancelled; + } + + public void cancel() { + cancel(true); + } + + public void cancel(boolean value) { + if (!(this instanceof Cancellable)) { + throw new EventException("Event is not Cancellable"); + } + this.cancelled = value; + } + + public final MiraiEvent broadcast() { + MiraiEventManager.getInstance().broadcastEvent(this); + return this; + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHook.java b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHook.java index c8088be6e..d46deb7d8 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHook.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHook.java @@ -2,20 +2,21 @@ package net.mamoe.mirai.event; import lombok.Getter; import lombok.Setter; -import net.mamoe.mirai.event.events.Cancellable; -import net.mamoe.mirai.event.events.MiraiEvent; import java.io.Closeable; import java.util.function.Consumer; import java.util.function.Predicate; +/** + * @author NatrualHG + */ public class MiraiEventHook implements Closeable { @Getter Class eventClass; @Getter - private volatile Consumer handler; + protected volatile Consumer handler; @Getter private volatile int priority = 0; @@ -31,7 +32,7 @@ public class MiraiEventHook implements Closeable { * return true -> this hook need to be removed */ @Getter - private Predicate valid; + protected Predicate validChecker; public MiraiEventHook(Class eventClass) { this(eventClass,null); @@ -58,26 +59,26 @@ public class MiraiEventHook implements Closeable { } - private MiraiEventHook setValid(Predicate valid) { - this.valid = valid; + private MiraiEventHook setValidChecker(Predicate validChecker) { + this.validChecker = validChecker; return this; } public MiraiEventHook setValidUntil(Predicate valid) { - return this.setValid(valid); + return this.setValidChecker(valid); } public MiraiEventHook setValidWhile(Predicate valid) { - return this.setValid(valid.negate()); + return this.setValidChecker(valid.negate()); } @SuppressWarnings("unchecked") public boolean accept(MiraiEvent event) { if(!(event instanceof Cancellable && event.isCancelled() && this.isIgnoreCancelled())){ - this.getHandler().accept((T) event); + this.getHandler().accept((T) event); } - return this.valid == null || this.valid.test((T) event); + return this.validChecker == null || this.validChecker.test((T) event); } /** @@ -103,6 +104,6 @@ public class MiraiEventHook implements Closeable { @Override public void close(){ this.handler = null; - this.valid = null; + this.validChecker = null; } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHookKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHookKt.kt new file mode 100644 index 000000000..4a072a2be --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventHookKt.kt @@ -0,0 +1,31 @@ +package net.mamoe.mirai.event + +import java.util.function.Consumer +import java.util.function.Predicate + +/** + * @author Him188moe + */ +class MiraiEventHookKt(eventClass: Class) : MiraiEventHook(eventClass) { + fun onEvent(handler: (E) -> Unit) { + this@MiraiEventHookKt.handler = Consumer(handler) + } + + fun validChecker(predicate: (E) -> Boolean) { + this@MiraiEventHookKt.validChecker = Predicate(predicate) + } +} + + +/** + * Kotlin 风格回调 + * 你的代码可以这样(并且 validChecker 是可选的): + * + * event.hook { + * onEvent {} + * validChecker {} + * } + */ +fun E.hook(handler: MiraiEventHookKt.() -> Unit): MiraiEventHookKt { + return MiraiEventHookKt(this.javaClass).apply(handler) +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventKt.kt new file mode 100644 index 000000000..d4441bb62 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventKt.kt @@ -0,0 +1,8 @@ +@file:JvmName("MiraiEventKt") + +package net.mamoe.mirai.event + +fun E.broadcast(): E { + MiraiEventManager.getInstance().broadcastEvent(this as MiraiEvent) + return this +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManager.java b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManager.java index d93ba6684..90622b1e2 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManager.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManager.java @@ -1,21 +1,25 @@ package net.mamoe.mirai.event; -import net.mamoe.mirai.MiraiServer; -import net.mamoe.mirai.event.events.MiraiEvent; - import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; +/** + * 线程安全的事件管理器. + * + * @author NaturalHG + * @see MiraiEventManagerKt 若你使用 kotlin, 请查看针对 kotlin 的优化实现 + */ public class MiraiEventManager { MiraiEventManager() { } public static MiraiEventManager getInstance() { - return EventManager.INSTANCE; + return EventManager.INSTANCE;//实例来自 kotlin 的 singleton } private final ReentrantReadWriteLock hooksLock = new ReentrantReadWriteLock(); @@ -115,23 +119,40 @@ public class MiraiEventManager { } - public void asyncBroadcastEvent(MiraiEvent event) { - this.asyncBroadcastEvent(event, a -> { - }); - } + public CompletableFuture broadcastEventAsync(E event) { + Objects.requireNonNull(event); + if (!(event instanceof MiraiEvent)) { + throw new IllegalArgumentException("event must be instanceof MiraiEvent"); + } - public void asyncBroadcastEvent(D event, Consumer callback) { - MiraiServer.getInstance().getTaskManager().ansycTask(() -> { - MiraiEventManager.this.broadcastEvent(event); + CompletableFuture future = new CompletableFuture<>(); + future.completeAsync(() -> { + MiraiEventManager.this.broadcastEvent((MiraiEvent) event); return event; - }, callback); + }); + return future; + } + + public CompletableFuture broadcastEventAsync(E event, Consumer callback) { + Objects.requireNonNull(event); + Objects.requireNonNull(callback); + if (!(event instanceof MiraiEvent)) { + throw new IllegalArgumentException("event must be instanceof MiraiEvent"); + } + + CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((a, b) -> callback.accept(event)); + future.completeAsync(() -> { + MiraiEventManager.this.broadcastEvent((MiraiEvent) event); + return event; + }); + return future; } - public void asyncBroadcastEvent(D event, Runnable callback) { - asyncBroadcastEvent(event, t -> callback.run()); + public CompletableFuture broadcastEventAsync(D event, Runnable callback) { + return broadcastEventAsync(event, t -> callback.run()); } - } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/EventManager.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManagerKt.kt similarity index 63% rename from mirai-core/src/main/java/net/mamoe/mirai/event/EventManager.kt rename to mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManagerKt.kt index 42e6765f0..e3cd769a1 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/EventManager.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManagerKt.kt @@ -1,33 +1,59 @@ +@file:JvmName("MiraiEventManagerKt") + package net.mamoe.mirai.event -import net.mamoe.mirai.event.events.MiraiEvent import kotlin.reflect.KClass -object EventManager : MiraiEventManager() -typealias MiraiEventManagerKt = EventManager -typealias EventMgr = EventManager +/** + * [MiraiEventManager] 的 kotlin 简易化实现. + * 若要 hook 一个事件, 你可以: + * FriendMessageEvent::class.hookOnce {} + * FriendMessageEvent::class.hookAlways {} + * + * @author Him188moe + */ +object EventManager : MiraiEventManager() + +/** + * 每次事件触发时都会调用 hook + */ fun , E : MiraiEvent> C.hookAlways(hook: (E) -> Unit) { MiraiEventManager.getInstance().hookAlways(MiraiEventHook(this, hook)) } +/** + * 当下一次事件触发时调用 hook + */ fun , E : MiraiEvent> C.hookOnce(hook: (E) -> Unit) { MiraiEventManager.getInstance().hookOnce(MiraiEventHook(this, hook)) } +/** + * 每次事件触发时都会调用 hook, 直到 hook 返回 false 时停止 hook + */ fun , E : MiraiEvent> C.hookWhile(hook: (E) -> Boolean) { - MiraiEventManager.getInstance().hookAlways(MiraiEventHookSimple(this, hook)) + MiraiEventManager.getInstance().hookAlways(MiraiEventHookSimple(this, hook)) } +/** + * 每次事件触发时都会调用 hook + */ fun , E : MiraiEvent> C.hookAlways(hook: (E) -> Unit) { this.java.hookAlways(hook) } +/** + * 当下一次事件触发时调用 hook + */ fun , E : MiraiEvent> C.hookOnce(hook: (E) -> Unit) { this.java.hookOnce(hook) } +/** + * 每次事件触发时都会调用 hook, 直到 hook 返回 false 时停止 hook + */ fun , E : MiraiEvent> C.hookWhile(hook: (E) -> Boolean) { this.java.hookWhile(hook) } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/MiraiEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/MiraiEvent.java deleted file mode 100644 index a8509e7f3..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/MiraiEvent.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.mamoe.mirai.event.events; - -import net.mamoe.mirai.event.MiraiEventManager; -import net.mamoe.mirai.utils.EventException; - -import java.util.function.Consumer; - -public abstract class MiraiEvent { - - private boolean cancelled; - - public boolean isCancelled() { - if (!(this instanceof Cancellable)) { - return false; - } - return this.cancelled; - } - - public void cancel() { - cancel(true); - } - - public void cancel(boolean value) { - if (!(this instanceof Cancellable)) { - throw new EventException("Event is not Cancellable"); - } - this.cancelled = value; - } - - protected String eventName; - - public String getEventName() { - if (this.eventName == null) { - return this.getClass().getSimpleName(); - } - return this.eventName; - } - - public final MiraiEvent broadcast() { - MiraiEventManager.getInstance().broadcastEvent(this); - return this; - } - - @SuppressWarnings("unchecked") - public final void asyncBroadcast(Consumer callback) { - MiraiEventManager.getInstance().asyncBroadcastEvent((D) this, callback); - } - - @SuppressWarnings("unchecked") - public final void asyncBroadcast(Runnable callback) { - MiraiEventManager.getInstance().asyncBroadcastEvent((D) this, callback); - } -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/BeforePacketSendEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/BeforePacketSendEvent.java new file mode 100644 index 000000000..2996d08ee --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/BeforePacketSendEvent.java @@ -0,0 +1,14 @@ +package net.mamoe.mirai.event.events.network; + +import net.mamoe.mirai.event.Cancellable; +import net.mamoe.mirai.network.packet.ClientPacket; +import org.jetbrains.annotations.NotNull; + +/** + * @author Him188moe + */ +public final class BeforePacketSendEvent extends ClientPacketEvent implements Cancellable { + public BeforePacketSendEvent(@NotNull ClientPacket packet) { + super(packet); + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ClientPacketEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ClientPacketEvent.java new file mode 100644 index 000000000..e25920e95 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ClientPacketEvent.java @@ -0,0 +1,18 @@ +package net.mamoe.mirai.event.events.network; + +import net.mamoe.mirai.network.packet.ClientPacket; +import org.jetbrains.annotations.NotNull; + +/** + * @author Him188moe + */ +public abstract class ClientPacketEvent extends PacketEvent { + public ClientPacketEvent(@NotNull ClientPacket packet) { + super(packet); + } + + @Override + public ClientPacket getPacket() { + return (ClientPacket) super.getPacket(); + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketEvent.java index 119f87933..08d4b6a79 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketEvent.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketEvent.java @@ -1,7 +1,10 @@ package net.mamoe.mirai.event.events.network; -import net.mamoe.mirai.event.events.MiraiEvent; +import net.mamoe.mirai.event.MiraiEvent; import net.mamoe.mirai.network.packet.Packet; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; /** * @author Him188moe @@ -9,8 +12,8 @@ import net.mamoe.mirai.network.packet.Packet; public abstract class PacketEvent extends MiraiEvent { private final Packet packet; - public PacketEvent(Packet packet) { - this.packet = packet; + public PacketEvent(@NotNull Packet packet) { + this.packet = Objects.requireNonNull(packet); } public Packet getPacket() { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketReceivedEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketReceivedEvent.java deleted file mode 100644 index 77b697050..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketReceivedEvent.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.mamoe.mirai.event.events.network; - -/** - * @author Him188moe - */ -public class PacketReceivedEvent { -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketReceivedEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketReceivedEvent.java index 77fa219ea..79a302b46 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketReceivedEvent.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/ServerPacketReceivedEvent.java @@ -1,12 +1,16 @@ package net.mamoe.mirai.event.events.network; -import net.mamoe.mirai.event.events.Cancellable; +import net.mamoe.mirai.event.Cancellable; import net.mamoe.mirai.network.packet.ServerPacket; +import net.mamoe.mirai.network.packet.ServerVerificationCodePacket; /** + * 服务器接到某数据包时触发这个事件. + * 注意, 当接收到数据包的加密包(如 {@link ServerVerificationCodePacket.Encrypted})也会触发这个事件, 随后才会 + * * @author Him188moe */ -public class ServerPacketReceivedEvent extends ServerPacketEvent implements Cancellable { +public final class ServerPacketReceivedEvent extends ServerPacketEvent implements Cancellable { public ServerPacketReceivedEvent(ServerPacket packet) { super(packet); } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvent.java index ab410af4a..70d85ed78 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvent.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvent.java @@ -1,7 +1,7 @@ package net.mamoe.mirai.event.events.robot; import net.mamoe.mirai.Robot; -import net.mamoe.mirai.event.events.MiraiEvent; +import net.mamoe.mirai.event.MiraiEvent; import org.jetbrains.annotations.NotNull; import java.util.Objects; diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvents.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvents.kt index 737c47d58..9b452b1fd 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvents.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotEvents.kt @@ -1,7 +1,7 @@ package net.mamoe.mirai.event.events.robot import net.mamoe.mirai.Robot -import net.mamoe.mirai.event.events.MiraiEvent +import net.mamoe.mirai.event.MiraiEvent /** * @author Him188moe @@ -16,4 +16,3 @@ class RobotMessageReceivedEvent(val robot: Robot, val type: Type, val message: S GROUP } } - diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotLoginSucceedEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotLoginSucceedEvent.java index 15151ea91..a49d5f213 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotLoginSucceedEvent.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/robot/RobotLoginSucceedEvent.java @@ -7,5 +7,4 @@ public final class RobotLoginSucceedEvent extends RobotEvent { public RobotLoginSucceedEvent(Robot robot) { super(robot); } - } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisableEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisableEvent.java deleted file mode 100644 index dd0be1c57..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisableEvent.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.mamoe.mirai.event.events.server; - -import net.mamoe.mirai.event.events.MiraiEvent; - -public final class ServerDisableEvent extends MiraiEvent { - -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisabledEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisabledEvent.java new file mode 100644 index 000000000..294498f1d --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerDisabledEvent.java @@ -0,0 +1,8 @@ +package net.mamoe.mirai.event.events.server; + +import net.mamoe.mirai.event.AsyncEvent; +import net.mamoe.mirai.event.MiraiEvent; + +public final class ServerDisabledEvent extends MiraiEvent implements AsyncEvent { + +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnableEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnableEvent.java deleted file mode 100644 index 18aeefccf..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnableEvent.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.mamoe.mirai.event.events.server; - -import net.mamoe.mirai.event.events.MiraiEvent; - -public final class ServerEnableEvent extends MiraiEvent { - - -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnabledEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnabledEvent.java new file mode 100644 index 000000000..83b4772b9 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/server/ServerEnabledEvent.java @@ -0,0 +1,9 @@ +package net.mamoe.mirai.event.events.server; + +import net.mamoe.mirai.event.AsyncEvent; +import net.mamoe.mirai.event.MiraiEvent; + +public final class ServerEnabledEvent extends MiraiEvent implements AsyncEvent { + + +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java b/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java index e56f328b6..16954515c 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java @@ -1,7 +1,9 @@ package net.mamoe.mirai.message; +import net.mamoe.mirai.contact.Contact; import net.mamoe.mirai.contact.QQ; import net.mamoe.mirai.message.defaults.At; +import net.mamoe.mirai.message.defaults.Image; import net.mamoe.mirai.message.defaults.MessageChain; import net.mamoe.mirai.message.defaults.PlainText; import org.jetbrains.annotations.NotNull; @@ -11,7 +13,12 @@ import java.io.File; import java.util.Objects; /** + * 可发送的或从服务器接收的消息. + * 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 {@linkplain PlainText 纯文本}, {@linkplain Image 图片} 等. + * * @author Him188moe + * @see Contact#sendMessage(Message) 发送这个消息 + * @see MessageKt 若你使用 kotlin, 请查看针对 kotlin 的优化实现 */ public abstract class Message { @Override @@ -38,7 +45,7 @@ public abstract class Message { return new MessageChain(this, Objects.requireNonNull(tail)); } - public Message concat(String tail) { + public final Message concat(String tail) { return concat(new PlainText(tail)); } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt index 6ae5be4b9..0257cbf57 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt @@ -1,3 +1,5 @@ +@file:JvmName("MessageKt") + package net.mamoe.mirai.message import net.mamoe.mirai.message.defaults.PlainText @@ -12,4 +14,7 @@ infix operator fun Message.plus(another: Message): Message = this.concat(another */ infix operator fun Message.plus(another: String): Message = this.concat(another) +/** + * 连接 [String] 与 [Message] + */ infix fun String.concat(another: Message): Message = PlainText(this).concat(another) \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java index d552e53c4..dbae4f45a 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java @@ -7,6 +7,8 @@ import org.jetbrains.annotations.NotNull; import java.util.Objects; /** + * At 一个人的消息. + * * @author Him188moe */ public final class At extends Message { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index 22081cc11..52f5e056b 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -1,3 +1,5 @@ +@file:JvmMultifileClass +@file:JvmName("RobotNetworkHandler") package net.mamoe.mirai.network import net.mamoe.mirai.Robot @@ -8,6 +10,7 @@ import net.mamoe.mirai.event.events.qq.FriendMessageEvent import net.mamoe.mirai.event.events.robot.RobotLoginSucceedEvent import net.mamoe.mirai.event.hookWhile import net.mamoe.mirai.message.Message +import net.mamoe.mirai.network.RobotNetworkHandler.* import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket @@ -19,17 +22,33 @@ import java.net.DatagramPacket import java.net.DatagramSocket import java.net.InetSocketAddress import java.util.* +import java.util.concurrent.CompletableFuture import java.util.concurrent.ScheduledFuture import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException import kotlin.reflect.KClass + /** + * Mirai 的网络处理器, 它处理所有数据包([Packet])的发送和接收. + * [RobotNetworkHandler] 是全程异步和线程安全的. + * + * [RobotNetworkHandler] 由 2 个模块构成: + * - [SocketHandler]: 处理数据包底层的发送([ByteArray]) + * - [PacketHandler]: 制作 [Packet] 并传递给 [SocketHandler] 继续处理; 分析来自服务器的数据包并处理 + * + * 其中, [PacketHandler] 由 4 个子模块构成: + * - [DebugHandler] 输出 [Packet.toString] + * - [LoginHandler] 处理 touch/login/verification code 相关 + * - [MessageHandler] 处理消息相关(群消息/好友消息)([ServerEventPacket]) + * - [ActionHandler] 处理动作相关(踢人/加入群/好友列表等) + * * A RobotNetworkHandler is used to connect with Tencent servers. * * @author Him188moe */ @Suppress("EXPERIMENTAL_API_USAGE")//to simplify code -internal class RobotNetworkHandler(private val robot: Robot) : Closeable { +class RobotNetworkHandler(private val robot: Robot) : Closeable { private val socketHandler: SocketHandler = SocketHandler() val debugHandler = DebugHandler() @@ -44,9 +63,6 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { ActionHandler::class to actionHandler ) - private var closed: Boolean = false - - /** * Not async */ @@ -65,30 +81,49 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { //private | internal + internal fun tryLogin(): CompletableFuture = this.tryLogin(500, TimeUnit.MILLISECONDS) + + /** * 仅当 [LoginState] 非 [LoginState.UNKNOWN] 且非 [LoginState.TIMEOUT] 才会调用 [loginHook]. * 如果要输入验证码, 那么会以参数 [LoginState.VERIFICATION_CODE] 调用 [loginHandler], 登录完成后再以 [LoginState.SUCCEED] 调用 [loginHandler] + * + * @param connectingTimeout 连接每个服务器的 timeout */ - internal fun tryLogin(loginHook: (Robot.(LoginState) -> Unit)? = null) { + internal fun tryLogin(connectingTimeout: Long, unit: TimeUnit = TimeUnit.MILLISECONDS): CompletableFuture { val ipQueue: LinkedList = LinkedList(Protocol.SERVER_IP) - fun login(): Boolean { + val future = CompletableFuture() + + fun login() { val ip = ipQueue.poll() - return if (ip != null) { - this@RobotNetworkHandler.socketHandler.touch(ip) { state -> - if (state == LoginState.UNKNOWN || state == LoginState.TIMEOUT) { - login() - } else { - if (loginHook != null) { - robot.loginHook(state) + if (ip != null) { + // val future = this@RobotNetworkHandler.socketHandler.touch(ip) + + this@RobotNetworkHandler.socketHandler.touch(ip).runCatching { + this@runCatching.get(connectingTimeout, unit).let { state -> + if (state == LoginState.UNKNOWN) { + login() + } else { + future.complete(state) } } + }.onFailure { + when (it) { + is TimeoutException -> login() + else -> throw it + } } - true - } else false + } else { + future.complete(LoginState.UNKNOWN)//所有服务器均返回 UNKNOWN + } } login() + return future } + /** + * 分配收到的数据包 + */ @ExperimentalUnsignedTypes internal fun distributePacket(packet: ServerPacket) { packet.decode() @@ -112,14 +147,7 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { restartSocket() } - private var loginHook: ((LoginState) -> Unit)? = null - internal var loginState: LoginState? = null - set(value) { - field = value - if (value != null) { - loginHook?.invoke(value) - } - } + internal var loginFuture: CompletableFuture? = null private fun restartSocket() { socket?.close() @@ -151,17 +179,14 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { /** * Start network and touch the server */ - internal fun touch(serverAddress: String, loginHook: ((LoginState) -> Unit)? = null) { + internal fun touch(serverAddress: String): CompletableFuture { MiraiLogger.info("Connecting server: $serverAddress") + this.loginFuture = CompletableFuture() + socketHandler.serverIP = serverAddress - if (loginHook != null) { - this.loginHook = loginHook - } sendPacket(ClientTouchPacket(robot.account.qqNumber, socketHandler.serverIP)) - waitForPacket(ServerTouchResponsePacket::class, 100) { - MiraiLogger.error(" Timeout") - loginHook?.invoke(LoginState.TIMEOUT) - } + + return this.loginFuture!! } /** @@ -209,8 +234,12 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { override fun close() { this.socket?.close() - this.loginState = null - this.loginHook = null + if (this.loginFuture != null) { + if (!this.loginFuture!!.isDone) { + this.loginFuture!!.cancel(true) + } + this.loginFuture = null + } } } @@ -286,8 +315,7 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { } is ServerLoginResponseFailedPacket -> { - socketHandler.loginState = packet.loginState - MiraiLogger error "Login failed: " + packet.loginState.toString() + socketHandler.loginFuture!!.complete(packet.loginState) return } @@ -309,8 +337,6 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { } is ServerVerificationCodeTransmissionPacket -> { - socketHandler.loginState = LoginState.VERIFICATION_CODE - this.verificationCodeSequence++ this.verificationCodeCache = this.verificationCodeCache!! + packet.verificationCodePartN @@ -391,7 +417,7 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { } is ServerLoginSuccessPacket -> { - socketHandler.loginState = LoginState.SUCCEED + socketHandler.loginFuture!!.complete(LoginState.SUCCEED) sendPacket(ClientSKeyRequestPacket(robot.account.qqNumber, sessionKey)) } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt index 395b92e56..4e54a750b 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt @@ -46,8 +46,8 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { } return ServerLoginResponseFailedPacket(when (bytes.size) { - 319 -> LoginState.WRONG_PASSWORD - 135 -> LoginState.RETYPE_PASSWORD + 319, 135 -> LoginState.WRONG_PASSWORD + //135 -> LoginState.RETYPE_PASSWORD 279 -> LoginState.BLOCKED 263 -> LoginState.UNKNOWN_QQ_NUMBER 551, 487 -> LoginState.DEVICE_LOCK diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt index 5f4b6bdae..3abf7a2f2 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt @@ -4,7 +4,6 @@ import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.utils.* import java.io.DataInputStream - /** * 客户端请求验证码图片数据的第几部分 */ diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt index c2168c03c..482c057a9 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/LoginState.kt @@ -4,20 +4,43 @@ package net.mamoe.mirai.network.packet.login * @author Him188moe */ enum class LoginState { + /** + * 登录成功 + */ SUCCEED, + /** + * 密码错误 + */ WRONG_PASSWORD, - // UNKNOWN,//? 要再次发送某数据包 - RETYPE_PASSWORD,//similar to [WRONG_PASSWORD] - BLOCKED,//你的帐号存在被盗风险,已进入保护模式 - UNKNOWN_QQ_NUMBER,//你输入的帐号不存在 - DEVICE_LOCK,//设备锁 - TAKEN_BACK,//被回收 + /** + * 被冻结 + */ + BLOCKED, - VERIFICATION_CODE,//需要验证码 + /** + * QQ 号码输入有误 + */ + UNKNOWN_QQ_NUMBER, + /** + * 账号开启了设备锁. 暂不支持设备锁登录 + */ + DEVICE_LOCK, + /** + * 账号被回收 + */ + TAKEN_BACK, + + /** + * 需要验证码登录 + */ + VERIFICATION_CODE, + + /** + * 未知. 更换服务器或等几分钟再登录可能解决. + */ UNKNOWN, - TIMEOUT, } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/plugin/MiraiPluginBase.java b/mirai-core/src/main/java/net/mamoe/mirai/plugin/MiraiPluginBase.java index 085ee1aab..8bec23692 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/plugin/MiraiPluginBase.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/plugin/MiraiPluginBase.java @@ -1,4 +1,14 @@ package net.mamoe.mirai.plugin; -public class MiraiPluginBase { +import net.mamoe.mirai.Robot; + +/** + * 插件基类. + *

+ * 插件属于整个 Mirai, 而不是属于单个 {@link Robot}. + * + * @see net.mamoe.mirai.event.MiraiEventManager + * @see net.mamoe.mirai.event.MiraiEventManagerKt + */ +public abstract class MiraiPluginBase { } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskManager.java b/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskManager.java index 1f623387d..4e950374b 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskManager.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/task/MiraiTaskManager.java @@ -2,7 +2,7 @@ package net.mamoe.mirai.task; import net.mamoe.mirai.event.MiraiEventHook; -import net.mamoe.mirai.event.events.server.ServerDisableEvent; +import net.mamoe.mirai.event.events.server.ServerDisabledEvent; import java.util.concurrent.Callable; import java.util.concurrent.Future; @@ -24,7 +24,7 @@ public final class MiraiTaskManager { this.pool = new MiraiThreadPool(); MiraiEventHook - .onEvent(ServerDisableEvent.class) + .onEvent(ServerDisabledEvent.class) .handler(a -> this.pool.close()) .mount(); diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSetting.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSettings.java similarity index 83% rename from mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSetting.java rename to mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSettings.java index 851cdd862..7eaa08cb7 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSetting.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/setting/MiraiSettings.java @@ -1,5 +1,6 @@ package net.mamoe.mirai.utils.setting; +import net.mamoe.mirai.plugin.MiraiPluginBase; import org.ini4j.Config; import org.ini4j.Ini; @@ -15,7 +16,7 @@ import java.util.concurrent.ConcurrentHashMap; * Only supports INI format
* Supports {@link Map} and {@link List} */ -public class MiraiSetting { +public class MiraiSettings { private File file; @@ -23,14 +24,21 @@ public class MiraiSetting { private volatile Map cacheSection = new ConcurrentHashMap<>(); - public MiraiSetting(File file){ + public MiraiSettings(MiraiPluginBase pluginBase, String filename) { + // TODO: 2019/9/6 每个插件独立文件夹存放 + this(new File(filename)); + } + + public MiraiSettings(File file) { if(!file.getName().contains(".")){ - file = new File(file.getParent() + file.getName() + ".ini"); + file = new File(file.getPath() + ".ini"); } this.file = file; try { if(file.exists()){ - file.createNewFile(); + if (!file.createNewFile()) { + throw new RuntimeException("cannot create config file " + file); + } } Config config = new Config(); config.setMultiSection(true); diff --git a/mirai-core/src/test/java/BadQQFilter.kt b/mirai-core/src/test/java/BadQQFilter.kt index 22114508e..7cac454e1 100644 --- a/mirai-core/src/test/java/BadQQFilter.kt +++ b/mirai-core/src/test/java/BadQQFilter.kt @@ -107,14 +107,16 @@ fun main() { qqList.split("\n").forEach { GlobalScope.launch { val strings = it.split("----") - Robot(RobotAccount(strings[0].toLong(), strings[1].let { password -> + val robot = Robot(RobotAccount(strings[0].toLong(), strings[1].let { password -> if (password.endsWith(".")) { return@let password.substring(0, password.length - 1) } return@let password - }), listOf()).network.tryLogin { state -> + }), listOf()) + + robot.network.tryLogin().whenComplete { state, _ -> if (!(state == LoginState.BLOCKED || state == LoginState.DEVICE_LOCK || state == LoginState.WRONG_PASSWORD)) { - goodRobotList.add(this) + goodRobotList.add(robot) } } } From 70dc6cf63c9a735322dde55ffca46e1f6cddfcfe Mon Sep 17 00:00:00 2001 From: Him188moe Date: Fri, 6 Sep 2019 22:10:35 +0800 Subject: [PATCH 18/19] Updated sth --- .../src/main/java/net/mamoe/mirai/event/AsyncEventKt.kt | 6 +++++- .../src/main/java/net/mamoe/mirai/event/MiraiEventKt.kt | 2 +- .../main/java/net/mamoe/mirai/message/defaults/Face.java | 2 ++ .../src/main/java/net/mamoe/mirai/network/Protocol.kt | 2 -- mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt | 8 ++++++-- mirai-core/src/test/java/HexComparator.java | 2 +- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEventKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEventKt.kt index 32490d42a..10008103d 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEventKt.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/AsyncEventKt.kt @@ -9,6 +9,10 @@ fun E.broadcastAsync(callback: Consumer): CompletableFuture< return MiraiEventManager.getInstance().broadcastEventAsync(this, callback) } -fun E.broadcastAsync(callback: Runnable): CompletableFuture { +fun E.broadcastAsync(callback: Runnable): CompletableFuture { return MiraiEventManager.getInstance().broadcastEventAsync(this, callback) +} + +fun E.broadcastAsyncSmart(): CompletableFuture { + return MiraiEventManager.getInstance().broadcastEventAsync(this) } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventKt.kt index d4441bb62..8183738b0 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventKt.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventKt.kt @@ -2,7 +2,7 @@ package net.mamoe.mirai.event -fun E.broadcast(): E { +fun E.broadcastSmart(): E { MiraiEventManager.getInstance().broadcastEvent(this as MiraiEvent) return this } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.java index b1708fd11..3311de4e5 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.java @@ -4,6 +4,8 @@ import net.mamoe.mirai.message.FaceID; import net.mamoe.mirai.message.Message; /** + * QQ 自带表情 + * * @author Him188moe */ public final class Face extends Message { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt index d639dffa7..dea09bf68 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/Protocol.kt @@ -51,8 +51,6 @@ object Protocol { const val key00BA = "C1 9C B8 C8 7B 8C 81 BA 9E 9E 7A 89 E1 7A EC 94" const val key00BAFix = "69 20 D1 14 74 F5 B3 93 E4 D5 02 B3 71 1A CD 2A" - const val encryptKey = "“BA 42 FF 01 CF B4 FF D2 12 F0 6E A7 1B 7C B3 08”" - /** * 0836_622_fix2 */ diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt b/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt index 9f6d6b347..bcf62f885 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt @@ -8,7 +8,9 @@ import java.lang.reflect.Field import java.util.* import java.util.zip.CRC32 +@JvmSynthetic fun ByteArray.toHexString(): String = toHexString(" ") + fun ByteArray.toHexString(separator: String = " "): String = this.joinToString(separator) { var ret = it.toString(16).toUpperCase() if (ret.length == 1) { @@ -20,12 +22,12 @@ fun ByteArray.toHexString(separator: String = " "): String = this.joinToString(s @ExperimentalUnsignedTypes fun ByteArray.toUHexString(separator: String = " "): String = this.toUByteArray().toUHexString(separator) -fun ByteArray.__toUHexString(separator: String = " "): String = this.toUByteArray().toUHexString(separator) - @ExperimentalUnsignedTypes +@JvmSynthetic fun ByteArray.toUHexString(): String = this.toUByteArray().toUHexString() @ExperimentalUnsignedTypes +@JvmSynthetic fun UByteArray.toUHexString(separator: String = " "): String { return this.joinToString(separator) { var ret = it.toString(16).toUpperCase() @@ -37,6 +39,7 @@ fun UByteArray.toUHexString(separator: String = " "): String { } @ExperimentalUnsignedTypes +@JvmSynthetic fun UByteArray.toUHexString(): String = this.toUHexString(" ") @ExperimentalUnsignedTypes @@ -75,6 +78,7 @@ fun getRandomByteArray(length: Int): ByteArray { return bytes.toByteArray() } +@JvmSynthetic operator fun File.plus(child: String): File = File(this, child) private const val GTK_BASE_VALUE: Int = 5381 diff --git a/mirai-core/src/test/java/HexComparator.java b/mirai-core/src/test/java/HexComparator.java index e3a1571ca..51f6677e2 100644 --- a/mirai-core/src/test/java/HexComparator.java +++ b/mirai-core/src/test/java/HexComparator.java @@ -50,7 +50,7 @@ public class HexComparator { @SuppressWarnings({"unused", "NonAsciiCharacters"}) private static class TestConsts { - private static final String 牛逼 = UtilsKt.__toUHexString("牛逼".getBytes(), " "); + private static final String 牛逼 = UtilsKt.toUHexString("牛逼".getBytes(), " "); private static final String _1994701021 = ClientPacketKt.toHexString(1994701021, " "); private static final String _1040400290 = ClientPacketKt.toHexString(1040400290, " "); private static final String _580266363 = ClientPacketKt.toHexString(580266363, " "); From 9a0092ffca52d4fdc99e181dab0b28e365f5e8e9 Mon Sep 17 00:00:00 2001 From: Him188 Date: Fri, 6 Sep 2019 22:20:16 +0800 Subject: [PATCH 19/19] Updated packets --- .../events/network/BeforePacketSendEvent.java | 2 + .../event/events/network/PacketSentEvent.java | 15 ++++++++ .../mirai/network/RobotNetworkHandler.kt | 11 +++++- .../mirai/network/packet/ClientPacket.kt | 38 ++++++++----------- 4 files changed, 41 insertions(+), 25 deletions(-) create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketSentEvent.java diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/BeforePacketSendEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/BeforePacketSendEvent.java index 2996d08ee..97672e5d8 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/BeforePacketSendEvent.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/BeforePacketSendEvent.java @@ -5,6 +5,8 @@ import net.mamoe.mirai.network.packet.ClientPacket; import org.jetbrains.annotations.NotNull; /** + * Packet 已经 {@link ClientPacket#encode()}, 即将被发送 + * * @author Him188moe */ public final class BeforePacketSendEvent extends ClientPacketEvent implements Cancellable { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketSentEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketSentEvent.java new file mode 100644 index 000000000..963812029 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/network/PacketSentEvent.java @@ -0,0 +1,15 @@ +package net.mamoe.mirai.event.events.network; + +import net.mamoe.mirai.network.packet.ClientPacket; +import org.jetbrains.annotations.NotNull; + +/** + * Packet 已经发出 + * + * @author Him188moe + */ +public final class PacketSentEvent extends ClientPacketEvent { + public PacketSentEvent(@NotNull ClientPacket packet) { + super(packet); + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index 52f5e056b..bd533f20e 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -5,6 +5,8 @@ package net.mamoe.mirai.network import net.mamoe.mirai.Robot import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.event.events.network.BeforePacketSendEvent +import net.mamoe.mirai.event.events.network.PacketSentEvent import net.mamoe.mirai.event.events.network.ServerPacketReceivedEvent import net.mamoe.mirai.event.events.qq.FriendMessageEvent import net.mamoe.mirai.event.events.robot.RobotLoginSucceedEvent @@ -197,12 +199,17 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable { checkNotNull(socket) { "socket closed" } try { - packet.encode() - packet.writeHex(Protocol.tail) + packet.encodePacket() + + if (BeforePacketSendEvent(packet).broadcast().isCancelled) { + return + } val data = packet.toByteArray() socket!!.send(DatagramPacket(data, data.size)) MiraiLogger info "Packet sent: $packet" + + PacketSentEvent(packet).broadcast() } catch (e: Throwable) { e.printStackTrace() } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt index e21289fd9..1f4891942 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt @@ -14,11 +14,13 @@ import java.security.MessageDigest @ExperimentalUnsignedTypes abstract class ClientPacket : ByteArrayDataOutputStream(), Packet { @Getter - val packageId: String + val idHex: String + + var encoded: Boolean = false init { val annotation = this.javaClass.getAnnotation(PacketId::class.java) - packageId = annotation.value + idHex = annotation.value try { this.writeHex(Protocol.head) @@ -32,7 +34,7 @@ abstract class ClientPacket : ByteArrayDataOutputStream(), Packet { @Throws(IOException::class) fun writePacketId() { - this.writeHex(this@ClientPacket.packageId) + this.writeHex(this@ClientPacket.idHex) } /** @@ -42,11 +44,19 @@ abstract class ClientPacket : ByteArrayDataOutputStream(), Packet { * Before sending the packet, a [tail][Protocol.tail] will be added. */ @Throws(IOException::class) - abstract fun encode() + protected abstract fun encode() + + fun encodePacket() { + if (encoded) { + return + } + encode() + writeHex(Protocol.tail) + } @Throws(IOException::class) fun encodeToByteArray(): ByteArray { - encode() + encodePacket() return toByteArray() } @@ -88,24 +98,6 @@ fun DataOutputStream.writeHex(hex: String) { } } -@ExperimentalUnsignedTypes -fun DataOutputStream.writeVarInt(dec: UInt) { - /*.判断开始 (n < 256) - 返回 (取文本右边 (“0” + 取十六进制文本 (n), 2)) - .判断 (n ≥ 256) - hex = 取文本右边 (“0” + 取十六进制文本 (n), 4) - 返回 (取文本左边 (hex, 2) + “ ” + 取文本右边 (hex, 2)) - .默认 - 返回 (“”) - .判断结束*/ - - when { - dec < 256u -> this.writeByte(dec.toByte().toInt())//drop other bits - dec > 256u -> this.writeShort(dec.toShort().toInt()) - else -> throw IllegalArgumentException(dec.toString()) - } -} - fun DataOutputStream.encryptAndWrite(byteArray: ByteArray, key: ByteArray) { this.write(TEA.encrypt(byteArray, key)) }