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 58408640c..f46bd6345 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacket.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacket.kt @@ -74,67 +74,100 @@ internal class IncomingPacket private constructor( } } +internal enum class PacketEncryptType { + NoEncrypt { // 0x00 + override fun defaultKey(client: QQAndroidClient): ByteArray = NO_ENCRYPT + }, + D2 { //0x01 + override fun defaultKey(client: QQAndroidClient): ByteArray { + return client.wLoginSigInfo.d2Key + } + }, + Empty { // 16 zeros,// 0x02 + override fun defaultKey(client: QQAndroidClient): ByteArray { + return KEY_16_ZEROS + } + }, + ; + + inline val codec: Byte get() = ordinal.toByte() + + abstract fun defaultKey(client: QQAndroidClient): ByteArray +} + + @Suppress("DuplicatedCode") -internal inline fun <R : Packet?> OutgoingPacketFactory<R>.buildOutgoingUniPacket( +internal fun <R : Packet?> buildRawUniPacket( client: QQAndroidClient, - bodyType: Byte = 1, // 1: PB? - remark: String? = this.commandName, - commandName: String = this.commandName, - key: ByteArray = client.wLoginSigInfo.d2Key, + encryptMethod: PacketEncryptType = PacketEncryptType.D2, + remark: String?, + commandName: String, + key: ByteArray = encryptMethod.defaultKey(client), extraData: ByteReadPacket = BRP_STUB, + uin: String = client.uin.toString(), sequenceId: Int = client.nextSsoSequenceId(), - crossinline body: BytePacketBuilder.(sequenceId: Int) -> Unit + body: BytePacketBuilder.(sequenceId: Int) -> Unit ): OutgoingPacketWithRespType<R> { return OutgoingPacketWithRespType(remark, commandName, sequenceId, buildPacket { writeIntLVPacket(lengthOffset = { it + 4 }) { - writeInt(0x0B) - writeByte(bodyType) + writeInt(0x0B) // req type simple + writeByte(encryptMethod.codec) writeInt(sequenceId) writeByte(0) - client.uin.toString().let { + uin.let { writeInt(it.length + 4) writeText(it) } - encryptAndWrite(key) { + + if (encryptMethod === PacketEncryptType.NoEncrypt) { writeUniPacket(commandName, client.outgoingPacketSessionId, extraData) { body(sequenceId) } + } else { + encryptAndWrite(key) { + writeUniPacket(commandName, client.outgoingPacketSessionId, extraData) { + body(sequenceId) + } + } } } }) } +@Suppress("DuplicatedCode") +internal inline fun <R : Packet?> OutgoingPacketFactory<R>.buildOutgoingUniPacket( + client: QQAndroidClient, + encryptMethod: PacketEncryptType = PacketEncryptType.D2, + remark: String? = this.commandName, + commandName: String = this.commandName, + key: ByteArray = encryptMethod.defaultKey(client), + extraData: ByteReadPacket = BRP_STUB, + uin: String = client.uin.toString(), + sequenceId: Int = client.nextSsoSequenceId(), + noinline body: BytePacketBuilder.(sequenceId: Int) -> Unit +): OutgoingPacketWithRespType<R> = + buildRawUniPacket(client, encryptMethod, remark, commandName, key, extraData, uin, sequenceId, body) internal inline fun <R : Packet?> IncomingPacketFactory<R>.buildResponseUniPacket( client: QQAndroidClient, - bodyType: Byte = 1, // 1: PB? - name: String? = this.responseCommandName, + encryptMethod: PacketEncryptType = PacketEncryptType.D2, // 1: PB? + remark: String? = this.responseCommandName, commandName: String = this.responseCommandName, - key: ByteArray = client.wLoginSigInfo.d2Key, + key: ByteArray = encryptMethod.defaultKey(client), extraData: ByteReadPacket = BRP_STUB, sequenceId: Int = client.nextSsoSequenceId(), - crossinline body: BytePacketBuilder.(sequenceId: Int) -> Unit = {} -): OutgoingPacketWithRespType<R> { - @Suppress("DuplicatedCode") - return OutgoingPacketWithRespType(name, commandName, sequenceId, buildPacket { - writeIntLVPacket(lengthOffset = { it + 4 }) { - writeInt(0x0B) - writeByte(bodyType) - writeInt(sequenceId) - writeByte(0) - client.uin.toString().let { - writeInt(it.length + 4) - writeText(it) - } - encryptAndWrite(key) { - writeUniPacket(commandName, client.outgoingPacketSessionId, extraData) { - body(sequenceId) - } - } - } - }) -} + noinline body: BytePacketBuilder.(sequenceId: Int) -> Unit = {} +): OutgoingPacketWithRespType<R> = buildRawUniPacket( + client = client, + encryptMethod = encryptMethod, + remark = remark, + commandName = commandName, + key = key, + extraData = extraData, + sequenceId = sequenceId, + body = body +) private inline fun BytePacketBuilder.writeUniPacket( @@ -169,26 +202,28 @@ internal val NO_ENCRYPT: ByteArray = ByteArray(0) /** * com.tencent.qphone.base.util.CodecWarpper#encodeRequest(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int, int, java.lang.String, byte, byte, byte, byte[], byte[], boolean) */ -internal inline fun <R : Packet?> OutgoingPacketFactory<R>.buildLoginOutgoingPacket( +internal fun <R : Packet?> OutgoingPacketFactory<R>.buildLoginOutgoingPacket( client: QQAndroidClient, - bodyType: Byte, + encryptMethod: PacketEncryptType, uin: String = client.uin.toString(), - extraData: ByteArray = EMPTY_BYTE_ARRAY, + extraData: ByteArray = if (encryptMethod == PacketEncryptType.D2) client.wLoginSigInfo.d2.data else EMPTY_BYTE_ARRAY, remark: String? = null, commandName: String = this.commandName, - key: ByteArray = KEY_16_ZEROS, - crossinline body: BytePacketBuilder.(sequenceId: Int) -> Unit + key: ByteArray = encryptMethod.defaultKey(client), + body: BytePacketBuilder.(sequenceId: Int) -> Unit ): OutgoingPacketWithRespType<R> { val sequenceId: Int = client.nextSsoSequenceId() return OutgoingPacketWithRespType(remark, commandName, sequenceId, buildPacket { writeIntLVPacket(lengthOffset = { it + 4 }) { - writeInt(0x00_00_00_0A) - writeByte(bodyType) - extraData.let { + writeInt(0x00_00_00_0A) // packet login + writeByte(encryptMethod.codec) // encrypt type + + extraData.let { // actually d2 key if encryptMethod = d2 writeInt(it.size + 4) writeFully(it) } + writeByte(0x00) uin.let { @@ -196,7 +231,7 @@ internal inline fun <R : Packet?> OutgoingPacketFactory<R>.buildLoginOutgoingPac writeText(it) } - if (key === NO_ENCRYPT) { + if (encryptMethod == PacketEncryptType.NoEncrypt) { body(sequenceId) } else { encryptAndWrite(key) { body(sequenceId) } diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/list/FriendList.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/list/FriendList.kt index 73f23cd53..8df9c6afe 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/list/FriendList.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/list/FriendList.kt @@ -42,7 +42,7 @@ internal class FriendList { targetGroupUin: Long, targetGroupCode: Long, nextUin: Long = 0 - ) = buildOutgoingUniPacket(client, bodyType = 1, key = client.wLoginSigInfo.d2Key) { + ) = buildOutgoingUniPacket(client) { writeJceStruct( RequestPacket.serializer(), RequestPacket( @@ -91,7 +91,7 @@ internal class FriendList { operator fun invoke( client: QQAndroidClient - ) = buildOutgoingUniPacket(client, bodyType = 1, key = client.wLoginSigInfo.d2Key) { + ) = buildOutgoingUniPacket(client) { writeJceStruct( RequestPacket.serializer(), RequestPacket( @@ -134,7 +134,7 @@ internal class FriendList { operator fun invoke( client: QQAndroidClient, friend: Friend - ) = buildOutgoingUniPacket(client, bodyType = 1, key = client.wLoginSigInfo.d2Key) { + ) = buildOutgoingUniPacket(client) { writeJceStruct( RequestPacket.serializer(), RequestPacket( @@ -188,7 +188,7 @@ internal class FriendList { fun forSingleFriend( client: QQAndroidClient, uin: Long - ) = buildOutgoingUniPacket(client, bodyType = 1, key = client.wLoginSigInfo.d2Key) { + ) = buildOutgoingUniPacket(client) { writeJceStruct( RequestPacket.serializer(), RequestPacket( @@ -237,7 +237,7 @@ internal class FriendList { friendListCount: Int, groupListStartIndex: Int, groupListCount: Int - ) = buildOutgoingUniPacket(client, bodyType = 1, key = client.wLoginSigInfo.d2Key) { + ) = buildOutgoingUniPacket(client) { writeJceStruct( RequestPacket.serializer(), RequestPacket( diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/Heartbeat.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/Heartbeat.kt index 34b46ccc3..e92328b42 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/Heartbeat.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/Heartbeat.kt @@ -13,8 +13,8 @@ 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.QQAndroidClient -import net.mamoe.mirai.internal.network.protocol.packet.NO_ENCRYPT import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory +import net.mamoe.mirai.internal.network.protocol.packet.PacketEncryptType import net.mamoe.mirai.internal.network.protocol.packet.buildLoginOutgoingPacket import net.mamoe.mirai.internal.network.protocol.packet.writeSsoPacket import net.mamoe.mirai.internal.network.subAppId @@ -28,7 +28,7 @@ internal class Heartbeat { operator fun invoke( client: QQAndroidClient - ) = buildLoginOutgoingPacket(client, 0, key = NO_ENCRYPT) { + ) = buildLoginOutgoingPacket(client, encryptMethod = PacketEncryptType.NoEncrypt) { writeSsoPacket(client, client.subAppId, commandName, sequenceId = it) { } diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt index 4ce1364ed..43a3e1e47 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt @@ -78,7 +78,7 @@ internal class StatSvc { operator fun invoke( client: QQAndroidClient - ) = buildLoginOutgoingPacket(client, 1) { + ) = buildLoginOutgoingPacket(client, PacketEncryptType.D2) { writeProtoBuf( StatSvcGetOnline.ReqBody.serializer(), StatSvcGetOnline.ReqBody( uin = client.uin, @@ -112,9 +112,7 @@ internal class StatSvc { client: QQAndroidClient ) = buildLoginOutgoingPacket( client, - bodyType = 1, - extraData = client.wLoginSigInfo.d2.data, - key = client.wLoginSigInfo.d2Key + encryptMethod = PacketEncryptType.D2 ) { writeSsoPacket(client, client.subAppId, commandName, sequenceId = it) { @@ -205,7 +203,7 @@ internal class StatSvc { applyAction: SvcReqRegister.() -> Unit = {} ) = buildLoginOutgoingPacket( client, - bodyType = 1, + encryptMethod = PacketEncryptType.D2, extraData = client.wLoginSigInfo.d2.data, key = client.wLoginSigInfo.d2Key, remark = name, diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/WtLogin.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/WtLogin.kt index 74a48caa2..bb5879234 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/WtLogin.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/WtLogin.kt @@ -115,7 +115,7 @@ internal class WtLogin { object SubCommand17 { operator fun invoke( client: QQAndroidClient - ) = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId -> + ) = buildLoginOutgoingPacket(client, encryptMethod = PacketEncryptType.Empty) { sequenceId -> writeSsoPacket( client, client.subAppId, @@ -669,7 +669,7 @@ internal class WtLogin { size: Int, margin: Int, ecLevel: Int - ) = TransEmp.buildLoginOutgoingPacket(client, bodyType = 2, uin = "") { sequenceId -> + ) = TransEmp.buildLoginOutgoingPacket(client, encryptMethod = PacketEncryptType.Empty, uin = "") { sequenceId -> writeSsoPacket(client, client.subAppId, TransEmp.commandName, sequenceId = sequenceId) { writeOicqRequestPacket(client, uin = 0, commandId = 0x812) { val code2dPacket = buildCode2dPacket(0, 0, 0x31) { @@ -742,7 +742,7 @@ internal class WtLogin { fun QueryQRCodeStatus( client: QQAndroidClient, sig: ByteArray, - ) = TransEmp.buildLoginOutgoingPacket(client, bodyType = 2, uin = "") { sequenceId -> + ) = TransEmp.buildLoginOutgoingPacket(client, encryptMethod = PacketEncryptType.Empty, uin = "") { sequenceId -> writeSsoPacket(client, client.subAppId, TransEmp.commandName, sequenceId = sequenceId) { writeOicqRequestPacket(client, uin = 0, commandId = 0x812) { val code2dPacket = buildCode2dPacket(1, 0, 0x12) { diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin10.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin10.kt index 5cc594e39..004599f7a 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin10.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin10.kt @@ -30,7 +30,7 @@ internal object WtLogin10 : WtLoginExt { mainSigMap: Int = client.mainSigMap, remark: String = "10:fast-login", ) = WtLogin.ExchangeEmp.buildLoginOutgoingPacket( - client, bodyType = 2, key = ByteArray(16), remark = remark + client, encryptMethod = PacketEncryptType.Empty, remark = remark ) { sequenceId -> writeSsoPacket( client, diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin15.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin15.kt index 8ce1733fe..61fc1c2ff 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin15.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin15.kt @@ -27,7 +27,7 @@ internal object WtLogin15 : WtLoginExt { operator fun invoke( client: QQAndroidClient, ) = WtLogin.ExchangeEmp.buildOutgoingUniPacket( - client, bodyType = 2, key = ByteArray(16), remark = "15:refresh-keys" + client, encryptMethod = PacketEncryptType.Empty, remark = "15:refresh-keys" ) { sequenceId -> // writeSsoPacket(client, client.subAppId, WtLogin.ExchangeEmp.commandName, sequenceId = sequenceId) { writeOicqRequestPacket( diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin2.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin2.kt index ed5b3079f..9599083e1 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin2.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin2.kt @@ -20,7 +20,7 @@ internal object WtLogin2 : WtLoginExt { fun SubmitSliderCaptcha( client: QQAndroidClient, ticket: String - ) = WtLogin.Login.buildLoginOutgoingPacket(client, bodyType = 2, remark = "2:submit-slider") { sequenceId -> + ) = WtLogin.Login.buildLoginOutgoingPacket(client, encryptMethod = PacketEncryptType.Empty, remark = "2:submit-slider") { sequenceId -> writeSsoPacket(client, client.subAppId, WtLogin.Login.commandName, sequenceId = sequenceId) { writeOicqRequestPacket(client, commandId = 0x0810) { writeShort(2) // subCommand @@ -50,7 +50,7 @@ internal object WtLogin2 : WtLoginExt { client: QQAndroidClient, captchaSign: ByteArray, captchaAnswer: String - ) = WtLogin.Login.buildLoginOutgoingPacket(client, bodyType = 2, remark = "2:submit-captcha") { sequenceId -> + ) = WtLogin.Login.buildLoginOutgoingPacket(client, encryptMethod = PacketEncryptType.Empty, remark = "2:submit-captcha") { sequenceId -> writeSsoPacket(client, client.subAppId, WtLogin.Login.commandName, sequenceId = sequenceId) { writeOicqRequestPacket(client, commandId = 0x0810) { writeShort(2) // subCommand diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin20.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin20.kt index 8b3035c6f..edf4b0523 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin20.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin20.kt @@ -21,7 +21,7 @@ import net.mamoe.mirai.utils._writeTlvMap internal object WtLogin20 : WtLoginExt { operator fun invoke( client: QQAndroidClient - ) = WtLogin.Login.buildLoginOutgoingPacket(client, bodyType = 2, remark = "20:dev-lock") { sequenceId -> + ) = WtLogin.Login.buildLoginOutgoingPacket(client, encryptMethod = PacketEncryptType.Empty, remark = "20:dev-lock") { sequenceId -> writeSsoPacket(client, client.subAppId, WtLogin.Login.commandName, sequenceId = sequenceId) { writeOicqRequestPacket(client, commandId = 0x0810) { writeShort(20) // subCommand diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin7.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin7.kt index 5103be3a4..b83b980e9 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin7.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin7.kt @@ -26,7 +26,7 @@ internal object WtLogin7 : WtLoginExt { t174: ByteArray, code: String ) = WtLogin.Login.buildLoginOutgoingPacket( - client, bodyType = 2, remark = "7:submit-sms" + client, encryptMethod = PacketEncryptType.Empty, remark = "7:submit-sms" ) { sequenceId -> writeSsoPacket(client, client.subAppId, WtLogin.Login.commandName, sequenceId = sequenceId) { writeOicqRequestPacket(client, commandId = 0x0810) { diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin8.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin8.kt index 724f3a152..1238a61dc 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin8.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin8.kt @@ -29,7 +29,7 @@ internal object WtLogin8 : WtLoginExt { client: QQAndroidClient, t174: ByteArray ) = WtLogin.Login.buildLoginOutgoingPacket( - client, bodyType = 2, remark = "8:request-sms" + client, encryptMethod = PacketEncryptType.Empty, remark = "8:request-sms" ) { sequenceId -> writeSsoPacket(client, client.subAppId, WtLogin.Login.commandName, sequenceId = sequenceId) { writeOicqRequestPacket(client, commandId = 0x0810) { diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin9.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin9.kt index d75881a80..81f80f7ad 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin9.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin9.kt @@ -25,7 +25,7 @@ internal object WtLogin9 : WtLoginExt { passwordMd5: ByteArray, allowSlider: Boolean ) = WtLogin.Login.buildLoginOutgoingPacket( - client, bodyType = 2, remark = "9:password-login" + client, encryptMethod = PacketEncryptType.Empty, remark = "9:password-login" ) { sequenceId -> writeSsoPacket(client, client.subAppId, WtLogin.Login.commandName, sequenceId = sequenceId) { writeOicqRequestPacket(client, commandId = 0x0810) { @@ -154,7 +154,7 @@ internal object WtLogin9 : WtLoginExt { client: QQAndroidClient, data: QRCodeLoginData, ) = WtLogin.Login.buildLoginOutgoingPacket( - client, bodyType = 2, remark = "9:qrcode-login" + client, encryptMethod = PacketEncryptType.Empty, remark = "9:qrcode-login" ) { sequenceId -> writeSsoPacket(client, client.subAppId, WtLogin.Login.commandName, sequenceId = sequenceId) { writeOicqRequestPacket(client, commandId = 0x0810) {