From 39204730eb3fe07664cda5bea8fbebf0eb30e33c Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 8 Dec 2019 21:00:04 +0800 Subject: [PATCH] Fix StackOverflowError --- .../net/mamoe/mirai/network/BotSession.kt | 7 +- .../contact/GroupIdConvertions.kt | 7 +- .../kotlin/net.mamoe.mirai/contact/QQ.kt | 8 ++ .../net.mamoe.mirai/network/BotSession.kt | 9 +- .../protocol/tim/TIMBotNetworkHandler.kt | 2 +- .../network/protocol/tim/packet/PacketId.kt | 1 + .../protocol/tim/packet/action/FriendList.kt | 29 ++++ .../protocol/tim/packet/action/Profile.kt | 129 +++++++++++++++++- .../net/mamoe/mirai/MiraiEnvironmentJvm.kt | 21 ++- .../net/mamoe/mirai/network/BotSessionJvm.kt | 7 +- .../test/packetdebugger/PacketDebugger.kt | 28 ++-- 11 files changed, 215 insertions(+), 33 deletions(-) create mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/FriendList.kt diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/BotSession.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/BotSession.kt index 902c48ff5..d9d141c0f 100644 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/BotSession.kt +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/BotSession.kt @@ -2,14 +2,12 @@ package net.mamoe.mirai.network import android.graphics.Bitmap import android.graphics.BitmapFactory -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.io.core.use import kotlinx.io.streams.inputStream import net.mamoe.mirai.Bot import net.mamoe.mirai.message.Image -import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter import net.mamoe.mirai.network.protocol.tim.packet.SessionKey import net.mamoe.mirai.utils.MiraiInternalAPI import java.io.InputStream @@ -21,8 +19,9 @@ import java.io.InputStream */ @UseExperimental(MiraiInternalAPI::class) actual class BotSession internal actual constructor( - bot: Bot -) : BotSessionBase(bot) { + bot: Bot, + sessionKey: SessionKey +) : BotSessionBase(bot, sessionKey) { suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream() suspend inline fun Image.downloadAsBitmap(): Bitmap = withContext(Dispatchers.IO) { downloadAsStream().use { BitmapFactory.decodeStream(it) } } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/GroupIdConvertions.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/GroupIdConvertions.kt index 14df009cc..de6cc8a7c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/GroupIdConvertions.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/GroupIdConvertions.kt @@ -41,10 +41,11 @@ fun GroupId.toInternalId(): GroupInternalId {//求你别出错 ) } -fun GroupInternalId.toId(): GroupId {//求你别出错 +fun GroupInternalId.toId(): GroupId = with(value) { + //求你别出错 var left: UInt = this.toString().let { if (it.length < 6) { - return GroupId(this.value) + return GroupId(value) } it.substring(0 until it.length - 6).toUInt() } @@ -96,6 +97,6 @@ fun GroupInternalId.toId(): GroupId {//求你别出错 left = left.toString().substring(0 until 3).toUInt() ((left - 349u).toString() + right.toString()).toUInt() } - else -> this.value + else -> value }) } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt index 2f4e7f855..5a968d64d 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt @@ -6,8 +6,10 @@ import kotlinx.coroutines.CoroutineScope import net.mamoe.mirai.Bot import net.mamoe.mirai.contact.data.Profile import net.mamoe.mirai.network.BotSession +import net.mamoe.mirai.network.protocol.tim.packet.action.AvatarLink import net.mamoe.mirai.network.protocol.tim.packet.action.FriendNameRemark import net.mamoe.mirai.network.protocol.tim.packet.action.PreviousNameList +import net.mamoe.mirai.utils.MiraiExperimentalAPI /** * QQ 对象. @@ -22,6 +24,12 @@ import net.mamoe.mirai.network.protocol.tim.packet.action.PreviousNameList * @author Him188moe */ interface QQ : Contact, CoroutineScope { + /** + * 请求头像下载链接 + */ + // @MiraiExperimentalAPI + //suspend fun queryAvatar(): AvatarLink + /** * 查询用户资料 */ diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt index 3a4b28dfd..8a1ac5850 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt @@ -31,7 +31,7 @@ import kotlin.coroutines.coroutineContext * 构造 [BotSession] 的捷径 */ @Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun TIMBotNetworkHandler.BotSession(): BotSession = BotSession(bot) +internal inline fun TIMBotNetworkHandler.BotSession(sessionKey: SessionKey): BotSession = BotSession(bot, sessionKey) /** * 登录会话. 当登录完成后, 客户端会拿到 sessionKey. @@ -43,7 +43,8 @@ internal inline fun TIMBotNetworkHandler.BotSession(): BotSession = BotSession(b */ @UseExperimental(MiraiInternalAPI::class) expect class BotSession internal constructor( - bot: Bot + bot: Bot, + sessionKey: SessionKey ) : BotSessionBase /** @@ -52,9 +53,9 @@ expect class BotSession internal constructor( @MiraiInternalAPI // cannot be internal because of `public BotSession` abstract class BotSessionBase internal constructor( - val bot: Bot + val bot: Bot, + internal val sessionKey: SessionKey ) { - internal val sessionKey: SessionKey get() = bot.sessionKey val socket: DataPacketSocketAdapter get() = bot.network.socket val NetworkScope: CoroutineScope get() = bot.network diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt index 7b0490d21..dc925f735 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt @@ -474,7 +474,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou BotLoginSucceedEvent(bot).broadcast() - session = BotSession() + session = BotSession(sessionKey) val configuration = currentBotConfiguration() heartbeatJob = this@TIMBotNetworkHandler.launch { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/PacketId.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/PacketId.kt index db4ddd7b0..028cc77ad 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/PacketId.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/PacketId.kt @@ -79,6 +79,7 @@ internal enum class KnownPacketId(override inline val value: UShort, override in inline REQUEST_PROFILE_AVATAR(0x0031u, RequestProfileAvatarPacket), inline REQUEST_PROFILE_DETAILS(0x003Cu, RequestProfileDetailsPacket), + inline QUERY_NICKNAME(0x0126u, QueryNicknamePacket), inline QUERY_PREVIOUS_NAME(0x01BCu, QueryPreviousNamePacket), diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/FriendList.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/FriendList.kt new file mode 100644 index 000000000..4ad460f88 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/FriendList.kt @@ -0,0 +1,29 @@ +package net.mamoe.mirai.network.protocol.tim.packet.action + + +// 0001 +// 已确认 查好友列表的列表 + +// send +// 20 01 00 00 00 00 01 00 00 + +// receive +// 20 00 01 03 00 00 00 15 01 01 03 +// 00 0C 01 02 [09] E4 BF A1 E7 94 A8 E5 8D A1 +// 00 0F 02 03 [0C] E8 BD AF E4 BB B6 E6 B3 A8 E5 86 8C +// 00 09 03 04 [06] E6 BA 90 E7 A0 81 +// 00 00 + + + + +// 0134 +// 这里有好友也有群(为 internal id) 97208217 +// 不太确定. 可能是查好友与群列表?? +// send +// 00 00 01 5B 5D EB 58 AD 00 00 03 E8 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +// receive +// 00 00 19 00 00 01 5D 5D EB 5D C6 00 00 00 00 01 00 00 00 19 00 54 E5 06 01 00 00 00 00 00 01 00 00 00 64 B2 1D 01 00 00 00 00 00 01 00 00 00 66 7C C5 01 00 00 00 00 00 01 00 00 01 60 31 EC 01 00 00 00 00 00 01 00 00 01 B3 E6 AC 01 00 00 00 00 00 01 00 00 02 45 16 DF 01 00 00 00 00 00 01 00 00 03 37 67 20 01 00 00 00 00 00 01 00 00 05 B0 F4 6F 01 00 00 00 00 00 01 00 00 0C D9 1F 45 01 00 00 00 00 00 01 00 00 0F 0D 35 E1 01 00 00 00 00 00 01 00 00 10 18 86 83 01 00 00 00 00 00 01 00 00 11 A9 8B F7 01 00 00 00 00 00 01 00 00 31 05 12 1C 01 00 00 00 00 00 01 00 00 37 99 77 D7 01 00 00 00 00 00 01 00 00 37 C8 4D C7 04 00 00 00 00 00 00 37 E9 68 46 01 00 00 00 00 00 01 00 00 37 E9 94 CF 01 00 00 00 00 00 01 00 00 3E 03 3F A2 01 00 00 00 00 00 01 00 00 50 BA 4A 8F 01 00 00 00 00 00 01 00 00 55 7A D6 86 01 00 00 00 00 00 01 00 00 6C 78 B1 E0 01 00 00 00 00 00 01 00 00 78 59 79 87 01 00 00 00 00 00 01 00 00 79 9B 1B 59 04 00 00 00 00 00 00 A6 81 A4 9D 01 00 00 00 00 00 01 00 00 A6 A0 EE EF 01 00 00 00 00 00 01 00 00 00 00 + + diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/Profile.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/Profile.kt index 878a1818f..b2a424d5a 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/Profile.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/Profile.kt @@ -10,12 +10,133 @@ import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.protocol.tim.packet.* import net.mamoe.mirai.utils.io.* +inline class AvatarLink(val value: String) : Packet + +inline class NicknameMap(val delegate: Map) : Packet + +/** + * 批量查询昵称. + */ +@AnnotatedId(KnownPacketId.QUERY_NICKNAME) +internal object QueryNicknamePacket : SessionPacketFactory() { + /** + * 单个查询. + */ + @PacketVersion(date = "2019.12.7", timVersion = "2.3.2 (21173)") + operator fun invoke( + bot: UInt, + sessionKey: SessionKey, + qq: UInt + ): OutgoingPacket = buildSessionPacket(bot, sessionKey) { + writeHex("03 00 00 00 00 00 00 00 00 00 00") + writeByte(1) + writeUInt(qq) + } + + /** + * 批量查询. + * 注意!! 服务器不一定全都返回... 需要重复查没返回的 + */ + @PacketVersion(date = "2019.12.7", timVersion = "2.3.2 (21173)") + operator fun invoke( + bot: UInt, + sessionKey: SessionKey, + qq: Array + ): OutgoingPacket = buildSessionPacket(bot, sessionKey) { + writeHex("03 00 00 00 00 00 00 00 00 00 00") + writeUByte(qq.size.toUByte()) + qq.forEach { + writeUInt(it) + } + } + +/* + +批量查询昵称 + +发出包ID = UnknownPacketId(01 26) +sequence = 44 57 +fixVer2=02 00 00 00 01 2E 01 00 00 69 35 +解密body=03 00 00 00 00 00 00 00 00 00 00 [24] +(02 45 16 DF) (6C 78 B1 E0) (11 73 69 76) (36 79 19 E1) (49 28 A4 F4) (81 66 8B BC) (2D 6B 19 EC) (28 3D 91 25) (00 54 E5 06) (37 E9 94 CF) (55 7A D6 86) +(01 60 31 EC) (2F B1 5E EF) (05 B0 F4 6F) (0F 0D 35 E1) (00 66 7C C5) A6 81 A4 9D 31 05 12 1C A6 A0 EE EF 10 18 86 83 37 99 77 D7 50 BA 4A 8F 10 CE 72 4C 32 71 EE 30 79 63 C6 98 (3E C2 FA 6E) 02 27 13 93 01 2E E5 D7 37 E9 68 46 00 64 B2 1D 03 37 67 20 0A 9C 58 FB 05 94 75 87 +(0B 9F C6 B6) +(18 BE 4B 0E) + +接收包id=UnknownPacketId(01 26), +sequence=44 57 + 解析body=UnknownPacket(01 26) +body= 03 00 00 00 00 00 00 00 00 00 00 12 04 14 37 +(02 45 16 DF) 00 36 FF 00 + [0F] E6 94 BE E7 9D 9B E3 81 AE E5 A4 A9 E7 A9 BA + 11 88 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 80 08 80 00 41 +(6C 78 B1 E0) 00 2D 1C 01 + [19] 61 2E E8 B4 A2 E7 A5 9E 7C 20 E6 8E A5 E5 90 84 E7 A7 8D E4 B8 9A E5 8A A1 + 11 C0 02 40 07 C7 08 1C 00 4D 59 53 00 00 4B 4C 00 4B 55 4C 00 00 00 00 00 00 04 00 00 E2 10 34 +(11 73 69 76) 01 DD 19 00 + [0C] E5 BC 80 E5 BF 83 E5 B0 B1 E5 A5 BD + 11 08 82 46 07 CA 00 00 00 00 00 31 00 00 33 32 00 00 00 35 08 04 08 04 08 04 04 01 17 E3 10 32 +(36 79 19 E1) 00 00 1F 00 + [0A] 45 70 69 6D 65 74 68 65 75 73 + 00 08 02 00 07 C4 02 08 00 41 42 57 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 10 49 +(49 28 A4 F4) 02 B5 17 01 + [21] E9 A1 B9 E7 9B AE 6B 61 6B 61 6F 74 61 6C 6B EF BC 88 E6 9C 89 E4 BA 8B E6 8A 96 E6 88 91 EF BC 89 + 11 80 02 00 07 CC 06 0B 00 00 00 31 00 00 34 34 00 00 00 31 00 00 00 00 00 00 04 00 00 80 10 2E +(81 66 8B BC) 02 64 77 00 + [06] E4 B8 87 E7 A0 81 + 00 80 02 00 07 6C 0A 03 00 00 00 31 00 00 33 31 00 00 00 35 00 00 00 00 00 00 04 00 00 00 00 37 +(2D 6B 19 EC) 02 58 16 01 + [0F] E5 93 A5 E5 8F AA E6 98 AF E4 BC A0 E9 80 81 + 11 00 02 00 07 CC 0C 0F 00 00 00 31 00 00 35 33 00 00 00 33 00 00 00 00 00 00 04 00 00 00 00 31 +28 3D 91 25 02 D9 FF FF 09 E5 B0 8F E8 A1 A8 E5 BC 9F 11 C8 02 46 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 04 08 04 08 04 04 20 06 E2 00 3B 00 54 E5 06 02 5B 78 00 13 61 E5 85 A8 E6 96 B0 E5 9F 9F E5 90 8D E6 89 B9 E5 8F 91 00 08 82 46 07 6B 08 16 00 00 00 31 00 00 34 33 00 00 00 31 00 00 00 00 00 00 04 00 08 02 00 4C 37 E9 94 CF 00 00 00 FF 24 E6 B3 89 E5 B7 9E E5 B8 82 E6 86 A8 E9 BC A0 E7 BD 91 E7 BB 9C E7 A7 91 E6 8A 80 E6 9C 89 E9 99 90 E5 85 AC 01 00 00 00 00 00 00 00 00 00 00 31 00 00 33 35 00 00 00 35 00 00 00 00 00 00 04 00 00 40 02 30 55 7A D6 86 02 49 1B 01 08 E5 AE A2 E6 9C 8D 56 36 11 00 02 00 07 C8 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 12 00 4A 01 60 31 EC 02 58 FF 00 22 E5 BC 80 E5 BD A9 E7 BD 91 2D E5 B0 8F E8 B1 86 28 31 32 E5 88 B0 32 32 E7 82 B9 E5 9C A8 E7 BA BF 29 00 40 00 00 00 00 05 1E 00 00 00 31 00 00 35 31 00 00 00 31 08 04 04 09 0C 04 04 00 00 02 00 38 2F B1 5E EF 00 00 00 FF 10 E4 B8 8A E6 96 B9 65 E6 8E A8 E8 BD AF E4 BB B6 01 80 00 00 00 00 00 00 00 00 00 31 00 00 34 34 00 00 00 33 00 00 00 00 00 00 04 00 00 00 00 39 05 B0 F4 6F 00 78 23 01 11 E2 99 A1 20 E2 9C BF E2 80 BF E2 9C BF 20 52 4F 4E 11 88 82 42 07 C0 09 0C 00 00 00 31 00 00 33 35 00 00 00 35 00 00 00 00 00 00 04 00 00 80 00 2E 0F 0D 35 E1 00 00 23 00 06 E5 9C B0 E8 A1 A3 00 40 02 46 07 C0 02 08 00 00 00 31 00 00 34 35 00 00 00 33 00 00 00 00 00 00 04 10 00 02 00 31 00 66 7C C5 00 00 0A 00 09 E8 B5 9A E5 B0 8F E5 AE A2 00 C8 02 42 07 D8 0C 0C 00 00 00 31 00 00 34 31 00 00 00 31 00 00 00 00 00 00 04 24 02 00 00 3A +(A6 81 A4 9D) 02 25 29 00 12 E6 96 B0 E6 98 93 E9 80 9A E5 AE A2 E6 9C 8D E4 B8 89 11 80 02 01 07 BA 0A 10 00 00 00 31 00 00 33 35 00 00 00 35 00 00 00 00 00 00 04 00 00 00 00 3A 31 05 12 1C 01 86 1C 00 12 E5 BF A7 E4 BC A4 E8 BF 98 E6 98 AF E5 BF AB E4 B9 90 00 88 02 02 07 C7 04 13 00 00 00 31 00 00 33 35 00 00 00 35 00 00 00 00 00 00 04 00 08 20 00 00 04 5D EC AF 48 + +--------------------------- + +发出包ID = UnknownPacketId(01 26) +sequence = 44 58 + fixVer2=02 00 00 00 01 2E 01 00 00 69 35 + 解密body=03 00 00 00 00 00 00 00 00 00 00 12 A6 A0 EE EF 10 18 86 83 37 99 77 D7 50 BA 4A 8F 10 CE 72 4C 32 71 EE 30 79 63 C6 98 + (3E C2 FA 6E) 02 27 13 93 01 2E E5 D7 37 E9 68 46 (00 64 B2 1D) (03 37 67 20) 0A 9C 58 FB 05 94 75 87 (11 48 2B 1A) 0B 9F C6 B6 18 BE 4B 0E + +接收包id=UnknownPacketId(01 26), +sequence=44 58 + 解析body=UnknownPacket(01 26) +body=03 00 00 00 00 00 00 00 00 00 00 00 03 8E 3C A6 A0 EE EF 02 07 6C 01 14 E8 8B B9 E6 9E 9C 49 44 E4 B8 93 E4 B8 9A E8 A7 A3 E9 94 81 11 00 02 01 07 77 01 01 00 00 00 31 00 00 31 31 00 00 00 31 00 00 00 00 00 00 04 00 00 02 00 31 10 18 86 83 00 C3 22 00 09 35 35 38 E7 94 B5 E8 AE AF 00 08 02 40 07 C1 0C 01 00 00 00 31 00 00 33 35 00 00 00 35 08 04 08 04 08 04 04 00 04 00 10 35 37 99 77 D7 02 5B 2A 00 0D E8 BF 9C E6 8B 93 E7 94 B5 E8 AE AF 33 00 C0 00 02 07 B9 09 0E 00 00 00 31 00 00 33 35 00 00 00 35 00 00 00 00 00 00 04 00 00 40 00 2E 50 BA 4A 8F 02 1C 09 00 06 E6 96 B9 E5 80 8D 11 40 02 00 07 DA 01 01 00 00 00 31 00 00 34 34 00 00 00 33 00 00 00 00 00 00 04 00 00 82 00 2C 10 CE 72 4C 00 00 23 00 04 4C 6F 73 74 11 08 02 00 07 C0 02 12 00 00 00 31 00 00 31 31 00 00 00 38 08 04 00 00 00 00 04 00 08 72 00 30 32 71 EE 30 00 93 21 00 08 69 57 65 62 53 68 6F 70 00 00 02 00 07 C2 01 01 00 00 00 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 12 00 2B 79 63 C6 98 02 A6 12 00 03 5E 4F 5E 11 80 02 00 07 D1 08 12 00 00 00 31 00 00 33 37 00 00 00 32 00 00 00 00 00 00 04 00 00 60 00 3D 3E C2 FA 6E 02 2B 1D 01 15 E9 A3 8E E9 93 83 E8 8D 89 E6 95 99 E8 82 B2 E6 9C 8D E5 8A A1 00 80 00 00 07 C6 06 10 00 00 00 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 2E 02 27 13 93 02 0D FF FF 06 E7 83 82 E8 8F 9C 00 08 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 04 A2 00 33 01 2E E5 D7 00 D8 22 00 0B 4F 28 E2 88 A9 5F E2 88 A9 29 4F 11 48 82 46 07 C1 08 1A 00 00 00 31 00 00 33 35 00 00 00 35 08 04 08 04 08 04 04 00 0C 80 08 30 37 E9 68 46 00 00 00 FF 08 33 35 E4 BA 92 E8 81 94 01 00 00 00 00 00 00 00 00 00 00 31 00 00 33 35 00 00 00 32 00 00 00 00 00 00 04 00 00 40 02 37 00 64 B2 1D 00 00 FF FF 0F E5 98 89 E4 BC A6 E8 99 8E E8 99 8E E8 99 8E 01 48 06 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 40 8C 00 34 03 37 67 20 00 93 24 00 0C E8 93 9D E6 98 9F E7 A7 91 E6 8A 80 00 08 02 46 07 BF 0A 1A 00 00 00 31 00 00 33 35 00 00 00 35 08 04 08 04 08 04 04 00 00 00 10 2C 0A 9C 58 FB 01 53 00 00 04 4B E3 80 81 00 48 02 02 07 E3 00 00 00 00 00 31 00 00 00 00 00 00 00 00 0C 04 08 04 04 09 04 FD 03 02 00 2E 05 94 75 87 02 25 1F 00 06 54 4E 54 50 52 4F 00 40 02 00 07 C4 01 01 00 00 00 31 00 00 34 33 00 00 00 31 00 00 00 00 00 00 04 00 00 02 00 2E 11 48 2B 1A 02 0A 0B 00 06 E6 9D 8E E9 98 B3 11 08 02 02 07 D8 03 1C 00 00 00 31 00 00 34 34 00 00 00 33 00 00 00 00 00 00 04 00 00 6C 00 30 0B 9F C6 B6 00 AE 14 00 08 F0 9F 91 BC F0 9F 91 BF 11 00 02 42 07 CF 01 18 00 00 00 00 00 00 00 00 00 00 00 00 08 04 08 04 04 07 04 00 04 A0 00 34 +(18 BE 4B 0E) 00 00 36 00 + [0C] E5 B3 B0 E5 9B 9E E8 B7 AF E8 BD AC + 00 08 02 00 07 AD 02 03 00 00 00 31 00 00 31 35 00 00 32 32 00 00 00 00 00 00 04 00 00 00 00 00 + +04 5D EC AF 48 +*/ + + override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): NicknameMap { + //03 00 00 00 00 00 00 00 00 00 00 12 04 14 37 + val type = readUByte().toInt() + if (type == 15) { + discardExact(14) + + val map = linkedMapOf() + while (remaining != 5L) { // 最后总是会剩余 04 5D EC AF 48 + val qq = readUInt() + discardExact(4) // 4 个状态信息, 未知 + val nickname = readString(readUByte().toInt()) + discardExact(32) // 未知 + map[qq] = nickname + } + return NicknameMap(map) + } else { + error("Unsupported type $type") + } + } +} + // 用户资料的头像 /** * 请求获取头像 - */ + */ // ? 这个包的数据跟下面那个包一样 @AnnotatedId(KnownPacketId.REQUEST_PROFILE_AVATAR) -internal object RequestProfileAvatarPacket : SessionPacketFactory() { +internal object RequestProfileAvatarPacket : SessionPacketFactory() { //00 01 00 17 D4 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 29 4E 22 4E 25 4E 26 4E 27 4E 29 4E 2A 4E 2B 4E 2D 4E 2E 4E 2F 4E 30 4E 31 4E 33 4E 35 4E 36 4E 37 4E 38 4E 3F 4E 40 4E 41 4E 42 4E 43 4E 45 4E 49 4E 4B 4E 4F 4E 54 4E 5B 52 0B 52 0F 5D C2 5D C8 65 97 69 9D 69 A9 9D A5 A4 91 A4 93 A4 94 A4 9C A4 B5 operator fun invoke( bot: UInt, @@ -27,9 +148,9 @@ internal object RequestProfileAvatarPacket : SessionPacketFactory() { writeHex("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 29 4E 22 4E 25 4E 26 4E 27 4E 29 4E 2A 4E 2B 4E 2D 4E 2E 4E 2F 4E 30 4E 31 4E 33 4E 35 4E 36 4E 37 4E 38 4E 3F 4E 40 4E 41 4E 42 4E 43 4E 45 4E 49 4E 4B 4E 4F 4E 54 4E 5B 52 0B 52 0F 5D C2 5D C8 65 97 69 9D 69 A9 9D A5 A4 91 A4 93 A4 94 A4 9C A4 B5") } - override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): NoPacket { + override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): AvatarLink { println(" RequestProfileAvatarPacket body=${this.readBytes().toUHexString()}") - return NoPacket + TODO() } } diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/MiraiEnvironmentJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/MiraiEnvironmentJvm.kt index 66860df99..976404c16 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/MiraiEnvironmentJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/MiraiEnvironmentJvm.kt @@ -2,7 +2,26 @@ package net.mamoe.mirai +import kotlinx.io.core.buildPacket +import kotlinx.io.core.readBytes +import net.mamoe.mirai.contact.GroupInternalId +import net.mamoe.mirai.contact.toId +import net.mamoe.mirai.utils.io.toByteArray +import net.mamoe.mirai.utils.io.toUHexString + actual object MiraiEnvironment { @JvmStatic - actual val platform: Platform get() = Platform.JVM + actual val platform: Platform + get() = Platform.JVM +} + +@ExperimentalUnsignedTypes +fun main() { + println(GroupInternalId(2793514141u).toId().value.toLong()) + println(GroupInternalId(2040208217u).toId().value.toLong()) + println(289942298u.toByteArray().toUHexString()) + println(1040400290u.toByteArray().toUHexString()) + println(buildPacket { + writeStringUtf8("信用卡") + }.readBytes().toUByteArray().toUHexString()) } \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/BotSessionJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/BotSessionJvm.kt index 992d4bf26..3fec90adc 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/BotSessionJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/network/BotSessionJvm.kt @@ -1,13 +1,11 @@ package net.mamoe.mirai.network -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.withContext import kotlinx.io.core.use import kotlinx.io.streams.inputStream import net.mamoe.mirai.Bot import net.mamoe.mirai.message.Image -import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter import net.mamoe.mirai.network.protocol.tim.packet.SessionKey import net.mamoe.mirai.utils.ExternalImage import net.mamoe.mirai.utils.MiraiInternalAPI @@ -24,8 +22,9 @@ import javax.imageio.ImageIO @UseExperimental(MiraiInternalAPI::class) @Suppress("unused") actual class BotSession internal actual constructor( - bot: Bot -) : BotSessionBase(bot) { + bot: Bot, + sessionKey: SessionKey +) : BotSessionBase(bot, sessionKey) { suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream() suspend inline fun Image.downloadAsBufferedImage(): BufferedImage = withContext(IO) { downloadAsStream().use { ImageIO.read(it) } } diff --git a/mirai-core/src/jvmTest/kotlin/mirai/test/packetdebugger/PacketDebugger.kt b/mirai-core/src/jvmTest/kotlin/mirai/test/packetdebugger/PacketDebugger.kt index acb5f967a..2e5b04c49 100644 --- a/mirai-core/src/jvmTest/kotlin/mirai/test/packetdebugger/PacketDebugger.kt +++ b/mirai-core/src/jvmTest/kotlin/mirai/test/packetdebugger/PacketDebugger.kt @@ -134,27 +134,29 @@ suspend fun main() { println("Ready perfectly") } - suspend fun decryptRecordedPackets(filename: String) { - File(filename).toRecorder() - .list.forEach { + suspend fun decryptRecordedPackets(filename: String?) { + (if (filename == null) File(".").listFiles()?.maxBy { it.lastModified() }!! + else File(filename)).toRecorder().also { + println("total count = " + it.list.size) + println() + }.list.forEach { if (it.isSend) { try { dataSent(it.data) } catch (e: Exception) { - e.printStackTrace() + //e.printStackTrace() } } else { try { dataReceived(it.data) } catch (e: Exception) { - e.printStackTrace() - + // e.printStackTrace() } } } } - decryptRecordedPackets("GMTDate(seconds=3, minutes=46, hours=7, dayOfWeek=SATURDAY, dayOfMonth=7, dayOfYear=341, month=DECEMBER, year=2019, timestamp=1575704763731).record") + decryptRecordedPackets(null) //startPacketListening() } @@ -180,13 +182,13 @@ internal object PacketDebugger { * 7. 运行完 `mov eax,dword ptr ss:[ebp+10]` * 8. 查看内存, `eax` 到 `eax+10` 的 16 字节就是 `sessionKey` */ - val sessionKey: SessionKey = SessionKey("98 4C 42 37 0F 87 BB A2 97 57 A1 77 A9 A9 74 37".hexToBytes()) + val sessionKey: SessionKey = SessionKey("F3 4A 4E F4 79 C4 92 62 EF 0F D8 6E D3 AB E3 80".hexToBytes()) // TODO: 2019/12/7 无法访问 internal 是 kotlin bug, KT-34849 /** * null 则不筛选 */ - val qq: UInt? = null + val qq: UInt? = 215555909u /** * 打开后则记录每一个包到文件. */ @@ -229,7 +231,7 @@ internal object PacketDebugger { } .runCatching { decode(id, sequenceId, DebugNetworkHandler) - }.getOrElse { it.printStackTrace(); null } + }.getOrElse { /*it.printStackTrace();*/ null } } } @@ -237,7 +239,9 @@ internal object PacketDebugger { if (packet !is IgnoredEventPacket) { println("--------------") println("接收包id=$id, \nsequence=${sequenceId.toUHexString()}") - println(" 解密body=${decodedBody.toUHexString()}") + if (packet !is UnknownPacket) { + println(" 解密body=${decodedBody.toUHexString()}") + } println(" 解析body=$packet") } @@ -390,7 +394,7 @@ internal object DebugNetworkHandler : BotNetworkHandler } override val bot: Bot = Bot(qq ?: 0u, "", coroutineContext) - override val session = BotSession(bot) + override val session = BotSession(bot, SessionKey(byteArrayOf())) override suspend fun login(): LoginResult = LoginResult.SUCCESS