diff --git a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt index 2b64d85a0..a9d4bfc99 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt @@ -18,6 +18,7 @@ import net.mamoe.mirai.internal.network.components.PacketCodecException.Kind.* import net.mamoe.mirai.internal.network.handler.selector.NetworkException import net.mamoe.mirai.internal.network.protocol.packet.* import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin +import net.mamoe.mirai.internal.network.protocol.packet.sso.PREFIX_TRPC_SSO import net.mamoe.mirai.internal.utils.crypto.Ecdh import net.mamoe.mirai.internal.utils.crypto.TEA import net.mamoe.mirai.utils.* @@ -95,6 +96,17 @@ internal class PacketCodecException( // } } +internal enum class IncomingPacketType(val value: Int) { + Login(0x0A), + Simple(0x0B), + Unknown(-1) + ; + + companion object { + internal fun of(value: Int) = enumValues().find { it.value == value } ?: Unknown + } +} + internal class PacketCodecImpl : PacketCodec { override fun decodeRaw( @@ -102,15 +114,15 @@ internal class PacketCodecImpl : PacketCodec { input: ByteReadPacket ): RawIncomingPacket = input.run { // packet type - val type = readInt() + val packetType = IncomingPacketType.of(readInt()) PacketLogger.verbose { "开始处理一个包" } - val encryptMethod = readByte().toInt() + val encryptMethod = PacketEncryptType.of(readByte().toInt()) val flag3 = readByte().toInt() val flag3Exception = if (flag3 != 0) { PacketCodecException( - "Illegal flag3. Expected 0, whereas got $flag3. packet type=$type, encrypt method=$encryptMethod. ", + "Illegal flag3. Expected 0, whereas got $flag3. packet type=$packetType, encrypt method=$encryptMethod. ", kind = PROTOCOL_UPDATED ) } else null @@ -122,10 +134,8 @@ internal class PacketCodecImpl : PacketCodec { val raw = try { when (encryptMethod) { - // empty key - 2 -> TEA.decrypt(buffer, DECRYPTER_16_ZERO, size) - // d2 key - 1 -> { + PacketEncryptType.Empty -> TEA.decrypt(buffer, DECRYPTER_16_ZERO, size) + PacketEncryptType.D2 -> { TEA.decrypt(buffer, kotlin.runCatching { client.wLoginSigInfo.d2Key }.getOrElse { throw PacketCodecException( "Received packet needed d2Key to decrypt but d2Key doesn't existed, ignoring. Please report to https://github.com/mamoe/mirai/issues/new/choose if you see anything abnormal", @@ -133,17 +143,18 @@ internal class PacketCodecImpl : PacketCodec { ) }, size) } - // no encrypt - 0 -> buffer + + PacketEncryptType.NoEncrypt -> buffer else -> throw PacketCodecException("Unknown encrypt type=$encryptMethod", PROTOCOL_UPDATED) }.let { decryptedData -> - when (type) { - // login - 0x0A -> parseSsoFrame(client, decryptedData) - // simple - 0x0B -> parseSsoFrame(client, decryptedData) // 这里可能是 uni?? 但测试时候发现结构跟 sso 一样. + when (packetType) { + IncomingPacketType.Login -> parseSsoFrame(client, decryptedData) + IncomingPacketType.Simple -> parseSsoFrame( + client, + decryptedData + ) // 这里可能是 uni?? 但测试时候发现结构跟 sso 一样. else -> throw PacketCodecException( - "unknown packet type: ${type.toByte().toUHexString()}", + "unknown packet type: ${packetType.value.toUHexString()}", PROTOCOL_UPDATED ) } @@ -163,25 +174,39 @@ internal class PacketCodecImpl : PacketCodec { "which may means protocol is updated.", flag3Exception ) + } else if (raw.commandName.startsWith(PREFIX_TRPC_SSO)) { + PacketLogger.verbose { "received a trpc native packet: ${raw.commandName}" } } else { throw flag3Exception } } when (encryptMethod) { - 0, 1 -> RawIncomingPacket(raw.commandName, raw.sequenceId, raw.body.readBytes()) - 2 -> RawIncomingPacket( + PacketEncryptType.NoEncrypt, + PacketEncryptType.D2 -> RawIncomingPacket( raw.commandName, raw.sequenceId, - raw.body.withUse { - try { - parseOicqResponse(client, raw.commandName) - } catch (e: Throwable) { - throw PacketCodecException(e, PacketCodecException.Kind.OTHER) - } - } + raw.body.readBytes() ) + PacketEncryptType.Empty -> { + RawIncomingPacket( + raw.commandName, + raw.sequenceId, + raw.body.withUse { + if (raw.commandName.startsWith(PREFIX_TRPC_SSO)) { + readBytes() + } else { + try { + parseOicqResponse(client, raw.commandName) + } catch (e: Throwable) { + throw PacketCodecException(e, PacketCodecException.Kind.OTHER) + } + } + } + ) + } + else -> error("unreachable") } } diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacket.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacket.kt index 0f41833b7..18bca022a 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacket.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacket.kt @@ -16,7 +16,7 @@ import net.mamoe.mirai.internal.network.* import net.mamoe.mirai.internal.network.components.EcdhInitialPublicKeyUpdater import net.mamoe.mirai.internal.network.protocol.data.proto.SSOReserveField import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbSendMsg -import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin +import net.mamoe.mirai.internal.network.protocol.packet.sso.SsoEstablishShareKey import net.mamoe.mirai.internal.spi.EncryptService import net.mamoe.mirai.internal.spi.EncryptServiceContext import net.mamoe.mirai.internal.utils.io.encryptAndWrite @@ -75,25 +75,34 @@ internal class IncomingPacket private constructor( } } -internal enum class PacketEncryptType { - NoEncrypt { // 0x00 +internal enum class PacketEncryptType(val value: Int) { + NoEncrypt(0x00) { // 0x00 override fun defaultKey(client: QQAndroidClient): ByteArray = NO_ENCRYPT }, - D2 { //0x01 + D2(0x01) { //0x01 override fun defaultKey(client: QQAndroidClient): ByteArray { return client.wLoginSigInfo.d2Key } }, - Empty { // 16 zeros,// 0x02 + Empty(0x02) { // 16 zeros,// 0x02 override fun defaultKey(client: QQAndroidClient): ByteArray { return KEY_16_ZEROS } }, + Unknown(-1) { + override fun defaultKey(client: QQAndroidClient): ByteArray { + error("unreachable") + } + } ; inline val codec: Byte get() = ordinal.toByte() abstract fun defaultKey(client: QQAndroidClient): ByteArray + + companion object { + internal fun of(value: Int) = enumValues().find { it.value == value } ?: Unknown + } } @@ -251,9 +260,9 @@ internal fun createChannelProxy(client: QQAndroidClient): EncryptService.Channel uin: Long, data: ByteArray ): EncryptService.ChannelResult? { - if (commandName == "trpc.o3.ecdh_access.EcdhAccess.SsoEstablishShareKey") { - val packet = client.bot.network.sendAndExpect( - WtLogin.Login.buildLoginOutgoingPacket( + if (commandName == SsoEstablishShareKey.commandName) { + val packet = client.bot.network.sendAndExpect( + SsoEstablishShareKey.buildLoginOutgoingPacket( client = client, encryptMethod = PacketEncryptType.Empty, uin = uin.toString(), @@ -268,7 +277,7 @@ internal fun createChannelProxy(client: QQAndroidClient): EncryptService.Channel ) } ) - TODO("parse packet to ChannelResult") + return EncryptService.ChannelResult(SsoEstablishShareKey.commandName, packet.data) } return null } diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt index a80683f3c..93bd1d34a 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt @@ -26,11 +26,11 @@ import net.mamoe.mirai.internal.network.protocol.packet.login.ConfigPushSvc import net.mamoe.mirai.internal.network.protocol.packet.login.Heartbeat import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin +import net.mamoe.mirai.internal.network.protocol.packet.sso.SsoEstablishShareKey import net.mamoe.mirai.internal.network.protocol.packet.summarycard.ChangeFriendRemark import net.mamoe.mirai.internal.network.protocol.packet.summarycard.SummaryCard import net.mamoe.mirai.utils.DeprecatedSinceMirai import net.mamoe.mirai.utils.MiraiLoggerWithSwitch -import kotlin.jvm.JvmName internal sealed class PacketFactory { /** @@ -132,6 +132,7 @@ internal object KnownPacketFactories { WtLogin.Login, WtLogin.ExchangeEmp, WtLogin.TransEmp, + SsoEstablishShareKey, StatSvc.Register, StatSvc.GetOnlineStatus, StatSvc.SimpleGet, diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/sso/SsoEstablishShareKey.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/sso/SsoEstablishShareKey.kt new file mode 100644 index 000000000..c46942d4a --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/sso/SsoEstablishShareKey.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2019-2023 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package net.mamoe.mirai.internal.network.protocol.packet.sso + +import io.ktor.utils.io.core.* +import net.mamoe.mirai.internal.QQAndroidBot +import net.mamoe.mirai.internal.network.Packet +import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory + +internal object SsoEstablishShareKey : OutgoingPacketFactory( + "trpc.o3.ecdh_access.EcdhAccess.SsoEstablishShareKey" +) { + internal class RawData(val data: ByteArray) : Packet + + override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): RawData { + return RawData(readBytes()) + } +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/sso/prefix.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/sso/prefix.kt new file mode 100644 index 000000000..313193824 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/sso/prefix.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2019-2023 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package net.mamoe.mirai.internal.network.protocol.packet.sso + +internal const val PREFIX_TRPC_SSO = "trpc.o3" \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/spi/EncryptService.kt b/mirai-core/src/commonMain/kotlin/spi/EncryptService.kt index 3c2657bb4..a374f7a14 100644 --- a/mirai-core/src/commonMain/kotlin/spi/EncryptService.kt +++ b/mirai-core/src/commonMain/kotlin/spi/EncryptService.kt @@ -72,8 +72,6 @@ public interface EncryptService : BaseService { public class ChannelResult( public val cmd: String, public val data: ByteArray, - public val success: Int, - public val callbackId: Long ) public interface ChannelProxy {