1
0
mirror of https://github.com/mamoe/mirai.git synced 2025-04-14 23:20:49 +08:00

Merge remote-tracking branch 'origin/master'

This commit is contained in:
jiahua.liu 2020-01-23 20:01:51 +08:00
commit 2e17ea6815
19 changed files with 2594 additions and 94 deletions

View File

@ -11,7 +11,6 @@ import net.mamoe.mirai.qqandroid.event.PacketReceivedEvent
import net.mamoe.mirai.qqandroid.network.protocol.packet.KnownPacketFactories
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.RegPushReason
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.SvcReqRegisterPacket
import net.mamoe.mirai.utils.*
@ -101,12 +100,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
*/
suspend fun parsePacket(input: Input) {
try {
KnownPacketFactories.parseIncomingPacket(bot, input) { packet: Packet, packetId: PacketId, sequenceId: Int ->
KnownPacketFactories.parseIncomingPacket(bot, input) { packet: Packet, commandName: String, sequenceId: Int ->
if (PacketReceivedEvent(packet).broadcast().cancelled) {
return@parseIncomingPacket
}
packetListeners.forEach { listener ->
if (listener.filter(packetId, sequenceId) && packetListeners.remove(listener)) {
if (listener.filter(commandName, sequenceId) && packetListeners.remove(listener)) {
listener.complete(packet)
}
}
@ -202,7 +201,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
}
suspend fun <E : Packet> OutgoingPacket.sendAndExpect(): E {
val handler = PacketListener(packetId = packetId, sequenceId = sequenceId)
val handler = PacketListener(commandName = commandName, sequenceId = sequenceId)
packetListeners.addLast(handler)
//println(delegate.readBytes().toUHexString())
println("Sending length=" + delegate.remaining)
@ -217,10 +216,10 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
@PublishedApi
internal inner class PacketListener(
val packetId: PacketId,
val commandName: String,
val sequenceId: Int
) : CompletableDeferred<Packet> by CompletableDeferred(supervisor) {
fun filter(packetId: PacketId, sequenceId: Int) = this.packetId == packetId && this.sequenceId == sequenceId
fun filter(commandName: String, sequenceId: Int) = this.commandName == commandName && this.sequenceId == sequenceId
}
override suspend fun awaitDisconnection() = supervisor.join()

View File

@ -6,8 +6,6 @@ import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.buildPacket
import kotlinx.io.core.writeFully
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.cryptor.DecrypterByteArray
import net.mamoe.mirai.utils.cryptor.encryptAndWrite
@ -23,12 +21,12 @@ import net.mamoe.mirai.utils.io.writeQQ
@UseExperimental(ExperimentalUnsignedTypes::class)
internal class OutgoingPacket constructor(
name: String?,
val packetId: PacketId,
val commandName: String,
val sequenceId: Int,
val delegate: ByteReadPacket
) {
val name: String by lazy {
name ?: packetId.toString()
name ?: commandName.toString()
}
}
@ -66,13 +64,13 @@ internal val EMPTY_BYTE_ARRAY = ByteArray(0)
internal inline fun PacketFactory<*>.buildOutgingPacket(
client: QQAndroidClient,
name: String? = null,
id: PacketId = this.id,
commandName: String = this.commandName,
key: ByteArray,
body: BytePacketBuilder.(sequenceId: Int) -> Unit
): OutgoingPacket {
val sequenceId: Int = client.nextSsoSequenceId()
return OutgoingPacket(name, id, sequenceId, buildPacket {
return OutgoingPacket(name, commandName, sequenceId, buildPacket {
writeIntLVPacket(lengthOffset = { it + 4 }) {
writeInt(0x0B)
writeByte(1)
@ -113,13 +111,13 @@ internal inline fun PacketFactory<*>.buildLoginOutgoingPacket(
bodyType: Byte,
extraData: ByteArray = EMPTY_BYTE_ARRAY,
name: String? = null,
id: PacketId = this.id,
commandName: String = this.commandName,
key: ByteArray = KEY_16_ZEROS,
body: BytePacketBuilder.(sequenceId: Int) -> Unit
): OutgoingPacket {
val sequenceId: Int = client.nextSsoSequenceId()
return OutgoingPacket(name, id, sequenceId, buildPacket {
return OutgoingPacket(name, commandName, sequenceId, buildPacket {
writeIntLVPacket(lengthOffset = { it + 4 }) {
writeInt(0x00_00_00_0A)
writeByte(bodyType)
@ -168,10 +166,10 @@ private val BRP_STUB = ByteReadPacket(EMPTY_BYTE_ARRAY)
* byte[] body()
*/
@UseExperimental(MiraiInternalAPI::class)
internal inline fun BytePacketBuilder.writeLoginSsoPacket(
internal inline fun BytePacketBuilder.writeSsoPacket(
client: QQAndroidClient,
subAppId: Long,
packetId: PacketId,
commandName: String,
extraData: ByteReadPacket = BRP_STUB,
sequenceId: Int,
body: BytePacketBuilder.() -> Unit
@ -187,7 +185,7 @@ internal inline fun BytePacketBuilder.writeLoginSsoPacket(
writeInt((extraData.remaining + 4).toInt())
writePacket(extraData)
}
packetId.commandName.let {
commandName.let {
writeInt(it.length + 4)
writeStringUtf8(it)
}
@ -269,7 +267,7 @@ internal inline fun PacketFactory<*>.buildSessionOutgoingPacket(
internal fun BytePacketBuilder.writeOicqRequestPacket(
client: QQAndroidClient,
encryptMethod: EncryptMethod,
packetId: PacketId,
commandId: Int,
bodyBlock: BytePacketBuilder.() -> Unit
) {
val body = encryptMethod.makeBody(client, bodyBlock)
@ -278,7 +276,7 @@ internal fun BytePacketBuilder.writeOicqRequestPacket(
writeByte(0x02) // head
writeShort((27 + 2 + body.remaining).toShort()) // orthodox algorithm
writeShort(client.protocolVersion)
writeShort(packetId.commandId.toShort())
writeShort(commandId.toShort())
writeShort(1) // const??
writeQQ(client.uin)
writeByte(3) // originally const

View File

@ -6,13 +6,12 @@ import kotlinx.serialization.Serializable
import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId
import net.mamoe.mirai.utils.currentTimeSeconds
@UseExperimental(ExperimentalUnsignedTypes::class)
internal object ImagePacket : PacketFactory<ImagePacket.RequestImgUrlResponse>() {
init {
this._id = PacketId(commandId = 0x0000, commandName = "LongConn.OffPicDown")
this._commandName = "LongConn.OffPicDown"
}
@ -21,7 +20,7 @@ internal object ImagePacket : PacketFactory<ImagePacket.RequestImgUrlResponse>()
}
fun createCmd0x325Packet(req: ImgReq, networkType: Int = 5): Cmd0x352Packet {
private fun createCmd0x325Packet(req: ImgReq, networkType: Int = 5): Cmd0x352Packet {
if (req is UploadImgReq)
return Cmd0x352Packet(
1,

View File

@ -25,7 +25,7 @@ import net.mamoe.mirai.utils.io.discardExact
@UseExperimental(ExperimentalUnsignedTypes::class)
internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>() {
init {
this._id = PacketId(commandId = 0x0810, commandName = "wtlogin.login")
this._commandName = "wtlogin.login"
}
object SubCommand9 {
@ -36,8 +36,8 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>() {
operator fun invoke(
client: QQAndroidClient
): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId ->
writeLoginSsoPacket(client, subAppId, id, sequenceId = sequenceId) {
writeOicqRequestPacket(client, EncryptMethodECDH7(client.ecdh), id) {
writeSsoPacket(client, subAppId, commandName, sequenceId = sequenceId) {
writeOicqRequestPacket(client, EncryptMethodECDH7(client.ecdh), 0x0810) {
writeShort(9) // subCommand
writeShort(17) // count of TLVs, probably ignored by server?
//writeShort(LoginType.PASSWORD.value.toShort())
@ -563,21 +563,4 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>() {
// SEE oicq_request.java at method analysisT17f
}
}
}
@Suppress("FunctionName")
internal fun PacketId(commandId: Int, commandName: String) = object : PacketId {
override val commandId: Int get() = commandId
override val commandName: String get() = commandName
}
internal interface PacketId {
val commandId: Int // ushort actually
val commandName: String
}
internal object NullPacketId : PacketId {
override val commandId: Int get() = error("uninitialized")
override val commandName: String get() = error("uninitialized")
}
}

View File

@ -15,7 +15,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.oidb0x769.Oidb0x769
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeLoginSsoPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket
import net.mamoe.mirai.qqandroid.utils.NetworkType
import net.mamoe.mirai.utils.currentTimeSeconds
import net.mamoe.mirai.utils.io.debugPrint
@ -40,10 +40,10 @@ internal object SvcReqRegisterPacket : PacketFactory<SvcReqRegisterPacket.Respon
internal object Response : Packet
const val subAppId = 537062845L
private const val subAppId = 537062845L
init {
_id = PacketId(0, "StatSvc.register")
_commandName = "StatSvc.register"
}
operator fun invoke(
@ -55,8 +55,8 @@ internal object SvcReqRegisterPacket : PacketFactory<SvcReqRegisterPacket.Respon
extraData = client.wLoginSigInfo.d2.data,
key = client.wLoginSigInfo.d2Key
) { sequenceId ->
writeLoginSsoPacket(
client, subAppId = subAppId, packetId = id,
writeSsoPacket(
client, subAppId = subAppId, commandName = commandName,
extraData = client.wLoginSigInfo.tgt.toReadPacket(), sequenceId = sequenceId
) {
writeUniRequestPacket {

View File

@ -10,7 +10,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.*
internal object TransEmpPacket : PacketFactory<TransEmpPacket.Response>() {
init {
_id = PacketId(0x0812, "wtlogin.trans_emp")
_commandName = "wtlogin.trans_emp"
}
private const val appId = 16L
@ -20,7 +20,7 @@ internal object TransEmpPacket : PacketFactory<TransEmpPacket.Response>() {
fun SubCommand1(
client: QQAndroidClient
): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) {
writeOicqRequestPacket(client, EncryptMethodECDH135(client.ecdh), id) {
writeOicqRequestPacket(client, EncryptMethodECDH135(client.ecdh), TODO()) {
// oicq.wlogin_sdk.request.trans_emp_1#packTransEmpBody
}

View File

@ -22,24 +22,24 @@ import kotlin.text.toByteArray
// x2
// OidbSvc.0xcf8 (getShoppingCardInfo)send 20da22db750806141ef4481108004500009450fd400080060000c0a8030a71600dd0fe501f908b8c3b2908ce927e501801fe436900000000006c0000000b0100014e78000000000e31393934373031303231fde67e3ef90dfab4c8706743671f3abf660fc3f77e4efa3fabdeb96e9984107b3f4bf7677b5d34c72e88a6e212af9107e3c52c5f97b7e41c2c3cecfe9301293ab4be504d4d2eca28a816ec514deca805
// OidbSvc.0x59f send 20da22db750806141ef4481108004500008c50fe400080060000c0a8030a71600dd0fe501f908b8c3b9508ce9366501801fe43610000000000640000000b0100014e7a000000000e313939343730313032319798479335a617d6037b4351bf340716d7095f01a83a19090ced9170a5d2e45578915b186770906f21b623304ee25b7ccb52126e3ab84275d2063f4801b3ea88f4b8fd064be98e75
// OidbSvc.0x59f (requestIsFirstLogin) send 20da22db750806141ef4481108004500008c50fe400080060000c0a8030a71600dd0fe501f908b8c3b9508ce9366501801fe43610000000000640000000b0100014e7a000000000e313939343730313032319798479335a617d6037b4351bf340716d7095f01a83a19090ced9170a5d2e45578915b186770906f21b623304ee25b7ccb52126e3ab84275d2063f4801b3ea88f4b8fd064be98e75
// friendlist.GetTroopListReqV2 send 20da22db750806141ef4481108004500011450ff400080060000c0a8030a71600dd0fe501f908b8c3bf908ce963e501801fb43e90000000000ec0000000b0100014e7b000000000e31393934373031303231e92012cde1f02af5088df9ee11e33f90ffc5416dce23cff1193985eb747ea1f453957b000b9f642708e394f590d5c8e7030064ef6f56210330319d4dd4fe21f0463095d74c6d5e21d94fcfb318c58e18d5a83ae548c03827b28c384e9a598f2ec9758ccb313fb825d44b727c10f8929682c5b6d34a8721f06e7ebb6768d39c6e1283b29bbdc15c6f35943fcc26195d1db57ae8de55d96637c7ae4caaa432bcf6768f17a39aa7f49882a86af04876146a2e44c3dcebf3ab106944cf7de19c85111add7b97c8d6bb53f773f11c09525614
// OidbSvc.0x791_0 send 20da22db750806141ef448110800450000bc5101400080060000c0a8030a71600dd0fe501f908b8c3ce508ce96a6501801fa43910000000000940000000b0100014e7d000000000e313939343730313032311ca9030fef4676440544c30ee8455143b3d29bf4b96fcb3923e437c30fd64795a325c777e38cd08f173f5dd6814541ca160a2de1ebdb46dcd73386cbf35ee2faae6cdac5c91aa81cf0beca175d7fdee366bacea06859de8b3e163e95d6765256fc523b7e435dc8f73d1a3f5a5c6c793706c88e103a55efa5
// OidbSvc.0x480_9 send 20da22db750806141ef4481108004500008c5102400080060000c0a8030a71600dd0fe501f908b8c3d7908ce97165018020043610000000000640000000b0100014e7e000000000e3139393437303130323183063dc1abd81bf314960d1a00d2a457ff44cb694c4d17d048b888600262a1a957713055cd6e2a68a55d239e1d70d26f9a39bfc61418a8cfbdd96dac2ae1be32e34f94a0271339d8
// OidbSvc.0x5eb_15 send 20da22db750806141ef4481108004500009c5105400080060000c0a8030a71600dd0fe501f908b8c3ddd08ce9e7e501801fe43710000000000740000000b0100014e7f000000000e31393934373031303231e80e3bc84057f0f3cdbfcde52cf82c5c640f69afd3680638b3bbd86bab49ddb8e29e297815f1f41ddfecfe241f76b57f999b02988fe5bb6f92da0693e27e023baea0504b7ca768c541630e636c31a01bdce3df4c27f88906
// OidbSvc.0x791_0 (getRedPointInfo) send 20da22db750806141ef448110800450000bc5101400080060000c0a8030a71600dd0fe501f908b8c3ce508ce96a6501801fa43910000000000940000000b0100014e7d000000000e313939343730313032311ca9030fef4676440544c30ee8455143b3d29bf4b96fcb3923e437c30fd64795a325c777e38cd08f173f5dd6814541ca160a2de1ebdb46dcd73386cbf35ee2faae6cdac5c91aa81cf0beca175d7fdee366bacea06859de8b3e163e95d6765256fc523b7e435dc8f73d1a3f5a5c6c793706c88e103a55efa5
// OidbSvc.0x480_9 (getDetailCardInfo) send 20da22db750806141ef4481108004500008c5102400080060000c0a8030a71600dd0fe501f908b8c3d7908ce97165018020043610000000000640000000b0100014e7e000000000e3139393437303130323183063dc1abd81bf314960d1a00d2a457ff44cb694c4d17d048b888600262a1a957713055cd6e2a68a55d239e1d70d26f9a39bfc61418a8cfbdd96dac2ae1be32e34f94a0271339d8
// OidbSvc.0x5eb_15 (getHiddenSwitch) send 20da22db750806141ef4481108004500009c5105400080060000c0a8030a71600dd0fe501f908b8c3ddd08ce9e7e501801fe43710000000000740000000b0100014e7f000000000e31393934373031303231e80e3bc84057f0f3cdbfcde52cf82c5c640f69afd3680638b3bbd86bab49ddb8e29e297815f1f41ddfecfe241f76b57f999b02988fe5bb6f92da0693e27e023baea0504b7ca768c541630e636c31a01bdce3df4c27f88906
// CliLogSvc.UploadReq send 20da22db750806141ef448110800450001cc5106400080060000c0a8030a71600dd0fe501f908b8c3e5108ce9eee501801fd44a10000000001a40000000b0100014e80000000000e31393934373031303231393e687d1ca6ee2f38f879c89a930bfbd7a9d0d5d6a84e3e76574b272980e8222c35564db3952d09f452bd954248922527ac9aee51a742b3508d50d3794ce81120245bff0a4e3ac74b026fb5444e9e5a5fad8a5c9865e855ede492fa445cc27e48a27f05d81f39e7f9818890717bffeab38df651f21e884cf5a7292c0f94aa3a849cbfdc84bc7e560e371fbbc4d62c1bd134b41f66915272cee5e4094ef47a5641cdb7e19a070a6babd955a02e722b2a5fbad6adc161f58f295d9a6406dd8bd9ac14bfc520e454eb2f0422ae20beaf6789d25ca367cb22fae28488670f5871e4fa7cd8953eb854a4b53cdd8ef0406f5efbd46870afb095efb7b375f956d4f085b6e03c7f7eada6b35d3cdc6e17c2e0169177f6bc24074f1a5fe90ea54cd8af627a00cb78518e6b7f3daab0811fc0872408581f385d25efeecfa4634998ffa81d43868521467262ff08f7fc338fac60499c3452f530bce46272599401fb4cf363ff74e8813c8e12a51b6bfb992e24d3dcf1dfde34af16e6e892f0a3cf146d2d3e444b62432e5e2932
// CliLogSvc.UploadReq send 20da22db750806141ef448110800450001c45107400080060000c0a8030a71600dd0fe501f908b8c3ff508ce9eee501801fd449900000000019c0000000b0100014e81000000000e3139393437303130323128f6ceffe231f5a913fe9b4c59d24ea84d7dd8a67ef3c802f5eb2705ffeec4e98ddb95ec61e2adb2a52bcf4f744613a956a7af05be228b1dc95d40a0c4e187e79b495946e95bf2ffcabfc550c4f384269f87fea6d550a744a493cc0e11fea05cd7816fcf625b48ee6ed270e13fbacaeaef462a43dd17be5fa587e41e28fa40c083caa7e632cdcdef307404d75c30dce888de061ad715192916ec0b740c5614589b8e06683526042f8b74e896ba1049b71b8deff9354b1b2e83991d7426e2844cc592f511d9d51697361f6ef54370c4043b1bec4d7aa227804dc2b539ef95313b77561faa4d23f7392a2d18f5d796f7768af59d3faa65892169636d9c0e26a7b55be18bcb78719bd0a8ab5fa446f55e515ec5f2d0bfe9e0977ac98fe9af99f0426bc7d65066248d605eefed9b3c42f9d95d578e82515afce2fe239b857619bf64faadee7b10268bd3a079c23a413fffa209fdb9c7d23adab92e4c42fb446add76c24556d2f176f9020183814dfb2fa68861576bfcc41dfdd254d3a63dc8528b95
// OidbSvc.0x787_11 send 20da22db750806141ef448110800450000a45108400080060000c0a8030a71600dd0fe501f908b8c419108ce9eee501801fd437900000000007c0000000b0100014e84000000000e31393934373031303231de7a3d7936e5679df9be661fdb98fa181243fed121a7c37e0a0a035537b27705ed59f5707bf86495d9b4781418f5c8dc36f561d8b659e2936d4549b55ec6c807650b4e5af7c79fe881ee9cb3df4b4b307748103b3b52eef06aeaf81adb25767c
// OidbSvc.0xaf6_0 send 20da22db750806141ef44811080045000094510a400080060000c0a8030a71600dd0fe501f908b8c420d08ce9f86501801fd436900000000006c0000000b0100014e85000000000e313939343730313032311425f3e63a4e0a0454c45b48639abbe10c101b19f0a66f37e774289e87cc3c54def76486925c7291f5d37392120d7e0d30a9caba77f73808b201f49ff2a04a55c5ec502b10a6f861dbffb6eed7324b92
// OidbSvc.0xdc9 send 20da22db750806141ef448110800450000d4510b400080060000c0a8030a71600dd0fe501f908b8c427908cea04e501801fc43a90000000000ac0000000b0100014e86000000000e31393934373031303231abc2f4d9170210b0504e058282363e45527ce2ec6080f48a99d24ca40171ab146ae451517cc60d98585c746d2d00d434d3b44a9e3c9bcbe0a5ee23d406d8ae9c88b9d51beae9d05a3c22fa67f5a03bea60c17017848d32852b7e6abbe290974f74183d7af2b20d6c43c133b52ec2506f9e752676a40518cf73b922505e1e5497fb58146e526627c8fdd2c8ec4424ff96
// OidbSvc.0x787_11 (getTroopMemberListBy0x787) send 20da22db750806141ef448110800450000a45108400080060000c0a8030a71600dd0fe501f908b8c419108ce9eee501801fd437900000000007c0000000b0100014e84000000000e31393934373031303231de7a3d7936e5679df9be661fdb98fa181243fed121a7c37e0a0a035537b27705ed59f5707bf86495d9b4781418f5c8dc36f561d8b659e2936d4549b55ec6c807650b4e5af7c79fe881ee9cb3df4b4b307748103b3b52eef06aeaf81adb25767c
// OidbSvc.0xaf6_0 (getTroopMemberListForHeadBatch) send 20da22db750806141ef44811080045000094510a400080060000c0a8030a71600dd0fe501f908b8c420d08ce9f86501801fd436900000000006c0000000b0100014e85000000000e313939343730313032311425f3e63a4e0a0454c45b48639abbe10c101b19f0a66f37e774289e87cc3c54def76486925c7291f5d37392120d7e0d30a9caba77f73808b201f49ff2a04a55c5ec502b10a6f861dbffb6eed7324b92
// OidbSvc.0xdc9 (getHostTroopHonorList) send 20da22db750806141ef448110800450000d4510b400080060000c0a8030a71600dd0fe501f908b8c427908cea04e501801fc43a90000000000ac0000000b0100014e86000000000e31393934373031303231abc2f4d9170210b0504e058282363e45527ce2ec6080f48a99d24ca40171ab146ae451517cc60d98585c746d2d00d434d3b44a9e3c9bcbe0a5ee23d406d8ae9c88b9d51beae9d05a3c22fa67f5a03bea60c17017848d32852b7e6abbe290974f74183d7af2b20d6c43c133b52ec2506f9e752676a40518cf73b922505e1e5497fb58146e526627c8fdd2c8ec4424ff96
// IncreaseURLSvr.QQHeadUrlReq, IncreaseURLSvr.QQHeadUrlReq send 20da22db750806141ef44811080045000150510c400080060000c0a8030a71600dd0fe501f908b8c432508cea116501801fb44250000000000b40000000b0100014e87000000000e31393934373031303231a3e5c904a29879bfe01d903db3522e51d9d388a6f976387267c78f937ebfb4b800cf847d9af9522bcf8b4e710d905935a904be7e144a8f85db87e784b42bdcc1f19b3dbf307b37d62ba3ee42e6145249161da0a9c608289f139e4f545b9efe40f868a9d7fc06381e59499b04da34e36aac978bb42ad6b93efa55fd63ddc18db1216c68afafc50c954caace2c159cc2ae5cdda25d4bcb5f2b000000740000000b0100014e88000000000e31393934373031303231c571c13b189ca8a129aeecfc734352ff401917c63da218afd73b3f95eaf5121a54331f4ae9534b5c5c5add7307c612fe935cbdfedb775ff1b386adba02b35984aac175015452125c1e93cb333e43c314d53cbb0201ebf0a5
// OidbSvc.0xc42 send 20da22db750806141ef448110800450004ec510d400080060000c0a8030a71600dd0fe501f908b8c444d08cea3ee5018020047c10000000004c40000000b0100014e89000000000e31393934373031303231e59b7a31945585845fec9d893236808c4868e458601b681c89bdefb2b52d4c2b4f3f3d6e6abe0e0e0fc8df28dccc8733c80a4bb9869cfd7203664227c9c485d1e22d02f7fb24944d70542610a73cdb657fb915b1ded3c1a5a52eece81fddbe4df82302b948c88b51bb4fa1bcc9af6302304ffd89ae1fa47f6b732c84c1deb3d4b1bbd6818359f066be51e868d90bd500bb5b3d65ae0cc11a40c3aa03e3aa1e1144dea014d65d1d1ac82cbf6df2415c4b0629bd07323d61f5735bc768d0bbcc7be7fd66ebd9b65232b5491a7c2b33c1079f0af971c0ff178868361cd0fb40b05e3d421145e43a92696ef394f3fbc9e1ac0c037791aa57ad1c6542195c681eb951e7e59532fc9c1eed68c96e79e720d3057f1d6ae4cf4ef253af35fdb2feadec3bac82091d8146a7022b5f2578e3f126a474e9f1cec9d987b055c9217c003931a5cf03530a0062641e6f4549cedf50ea16c75feb7035a849a3229a3663c135cd8905f17176e878fe29942a55107895041595e5b497ca8796d9489d0682e8823589965240ade202ea0efa9f84f1ebc0e25d33e3e81b3a43d7bdc75005fe8b43d09fe914c6af785ba4ad4cb40cb41f5bc622af6dc1cad1460871b8c7fdec63e08a80536ddf340e907b1eddd8fa90d2323d3e2920c7cd80fd379d633e9f8b8c526f47f9e101d6a1edeccaf15d61c893cc55e9c192cd23b7a417c3175461096146a70a08717a8e654086d8db042b674e72dc54a057a80dd7dd291b85af7d4f7ee0b8dabb8a0e58cafb411f1e501b855a2e6ea6b5a089cb8d066d5d9181d0e16d5389123f96a06d630269efe3727ccc2ca84a4b3dbd1f5d786c3a655e2b3e9311bae60acf3855e55b5e96981295193564ab0172ab8fd6fb4a6c05bff477e7800dcfa6d1e6d2face51219e69987a1a03419ce7d6a43b6216f5f3f02d87b8c9e4faf227f4509427f3b26316f3e996a4a9dae90afc693b3eb359ecd2226087305d77bfe3f6fcbb949061f7a4d1076634144fa1b3f2491ca34d75ee4d3c7a4f4ba17233b7e56bcc8c04044ee5c0d0eed5c53814a6efc0347251e47eaf5981bfc5ccc7b3c2c9e6b2d8b5c1b81f2d79d5134420f5909d0526c5d761b94c0afade2dda634f2d44b911b977630dec1c3f7aa0ed1aea422aebb5c6aef49a9873ce5df751bea10926983c43843fa5adc56077f835e84bc07fd434867e4af0d605c64c729baa77e6a22d5b58d4b9378f518b10f57a61a486a815afb0e3591f85b5c5cdb37f5fba5c89b2638b21c27cc369acd6c995932ead6ceb49fdf6122e2c09b385eb43ffbf2e81acb31057beba0700fb388374ce9fb33794b3991e9b3a18123e732b8d14e5aef01391424200dab855c12b47ade4a2c60b760cd9e3c5400d452fa040ead996a21aad6ce6fac722121f35910b39a3cc8e20543fb2539fe3fe538162f086e1de508f0f9b0cc2414b8af6800ece710f944c95031d2536470ca87083a41641392edbf976413844cd7c7d64a6ed61a2f7ce8e09a6948099d62da1f81b28fcb50424f88b1f0a9b271a7172247ff0313e0dff87ef3b2b4d965852d200e0476fb56aba5a71e5e7a2ad500e62e7f15dc165f0a6b315bffde194822420b846fd18ed2f510eb2610d5d23ccaffbded2c495224c0a215859bf03f0cb1ffc7f3373aff418326c2a98c7a44e8bffe93b
// ConfigPushSvc.GetIpDirect send 20da22db750806141ef44811080045000094510e400080060000c0a8030a71600dd0fe501f908b8c491108cea4b6501801ff436900000000006c0000000b0100014e8a000000000e31393934373031303231831dcd7b8023b2e8434f5897e7a34a13b67bcf4def875c650022a4a6b71417d9151938fe206612ae192f55d174e41aa848a02e51441700440260e2fdaf7882cfc60b2a10946dc2e76c172ddefc309389
// * friendlist.getFriendGroupList send 20da22db750806141ef448110800450001245111400080060000c0a8030a71600dd0fe501f908b8c497d08ceae5e501801fd43f90000000000fc0000000b0100014ea4000000000e31393934373031303231899eb2e0bc999ad0799e23cd538fcb600850fda949fd86368e3897c1e1b736ce01509901fc190da6c2c0eb00edd851ebad2efac593997488b51ec58d289d3a050ff1a732a616e3b4fffd40b7aca1da2d04dc0c9e1205bcc63c9473d9ed5b4386cf41d4a786f7382f94266b09db3e3993a27bff4685ffb7d9eda7f66fcf592c8c8d593aa8c00e3fae4274371e5c4b4c3c23bdbc4f6a255d1f5b66f4bf2d56798099afbb34507f516d16ae24b344607bd23c899e241048c18b227a6094cbdcb12d2a8a33b443f7a4f26bc9b3f04fd8001daa46302bdeb22bf32bdc72d06c4a7959
// * StatSvc.GetOnlineStatus send 20da22db750806141ef4481108004500008c5112400080060000c0a8030a71600dd0fe501f908b8c4a7908ceae5e501801fd43610000000000640000000b0100014ea5000000000e31393934373031303231954e34510d4f281e8676c7345c1e8d453c99aeca52c7649053a6230953ac2bca49f6e250394081be6153eceaa531aec179450ec3d671d72251db0c36cff7e1ba3b6de0e6ade53de2
// * account.RequestQueryQQMobileContactsV3 send 20da22db750806141ef448110800450001445115400080060000c0a8030a71600dd0fe501f908b8c4add08ceba36501801ff441900000000011c0000000b0100014ea9000000000e31393934373031303231a78ed17a376177e537dec3ed98b7e47b51e9be299048820b1bf3ae88d8a18324e6773ef89922a7e7cd46f24d18a6f8aa53472bfeb09000bb7c44ef5f646d8a8f9e0d04accb35183b0216bea7dee1ef8a51207f11a0681fbcfcd09364a21b16bd6974fef7d66c7eca43aea623c499f1c81fb995d11d5490e64f7929861b670e2f24dc975684ea3098f0b96aff986b4e0b6b09a45bf7f2e301fa58ba1b462e755685681c112c3d2ac369d785d56c25c12b1c66bf39396030b374400879c922a7c43d6d36cc40aa8482f079ef48355b9a2562669f5bce3d3ace4f014ce0454b158693f2727833d62d29bdc7884b165b93c57e60d443351e9fff7e093494f0c61918
// OidbSvc.0x58a send 20da22db750806141ef448110800450000945116400080060000c0a8030a71600dd0fe501f908b8c4bf908cebb5e501801fe436900000000006c0000000b0100014eaa000000000e3139393437303130323178d1c8e8c5d15a4dca043edc70fa514b19b92706d26a84f2bdb1b3e478d5ef53748b8d6082dea9a74f1c9f0ab519406c1ef36fcc0502cf201f658ecac1cd1682a34bb1ff42ac64da5f35e3af7fabcc8c
// OidbSvc.0x58a (getDiscuss) send 20da22db750806141ef448110800450000945116400080060000c0a8030a71600dd0fe501f908b8c4bf908cebb5e501801fe436900000000006c0000000b0100014eaa000000000e3139393437303130323178d1c8e8c5d15a4dca043edc70fa514b19b92706d26a84f2bdb1b3e478d5ef53748b8d6082dea9a74f1c9f0ab519406c1ef36fcc0502cf201f658ecac1cd1682a34bb1ff42ac64da5f35e3af7fabcc8c
// OidbSvc.0x7c4_0, OidbSvc.0xbe8 send 20da22db750806141ef448110800450001085117400080060000c0a8030a71600dd0fe501f908b8c4c6508cebbe6501801fe43dd00000000006c0000000b0100014eab000000000e31393934373031303231a047827363fff4e4596299c74f6d847be9e8b5c2e4327bdaddffb8dd40e8df0eb76c54a6c7b7a56eddbae7136bb2b076386eb3b51091c46e756d1f9241678b656498da02276578cfb1ebfb6445513f51000000740000000b0100014eac000000000e31393934373031303231bd70b59f03df1144ae0ab45768257763ae622d5517bc20092fffaf4a5a3d55118ef6cd02907467c0eaa4a45309661277166f75e8ec4b75c0ec5fbf313e03b4a667ce26dfb0d148039a4d9ef8be7ad8cdf5e5a810edb60dd4
// OidbSvc.0x58b_0, CertifiedAccountSvc.certified_account_read.GetFollowList send 20da22db750806141ef448110800450002f05118400080060000c0a8030a71600dd0fe501f908b8c4d4508cebcd6501801fd45c500000000009c0000000b0100014ead000000000e313939343730313032311c087c0ad4a44631d3e9eb9a6ebb4456a003db2e7eaa5e27ffd4c3ee592b8de7b89b9f6a56fc8260e57eef4f3b6616a5255ab830548dd50e9a99cf87011584f3811591c35fc95cadfc364bbeb0ed337063a518aca85fd17c30ab57408389f5c071ed2626ec47b1086478164d0ae0bd0f21222eb7d4b7a5601bc160f99a8f70330000022c0000000b0100014eae000000000e313939343730313032312dd572fad1b71384d3fdb16a1c57f3cbadac7e41ae6de9d13cc2827262e4c5a4bb95829233b72b5f9076b4652c1ffd1ebba874003bcf7e3be86cdc1034ac656efde24be90a49484209c954b78dec531b3d194cc92a297efef340d8273de90a63335bf543109e96a5aa958283161e7e78f50b74b49adb176472ac82fdad36adb68b38421deba0d1c1dcf24f8342bb8d39c1181545a675abb92a3e28431e60a02aaca6c2b4f5ea79c3f4431865444932c9af983f07dd39dd6d81e47f0f59e386e5320051472fe9235f3b98b8850a9335074173730103565ddf81fb57fedb200f328d9ba16d2e52ecf1cc590382087529678501b1ab6b5866afb25b70f0d03b0773f84691e6b94e6d03c3c47f1baa4e17552fafce1bcc90e336ae0d7fca76babcb035378ce191aee9315885197a39301f319857c33cd25a017f6a0480e16030b623547216bafe886f41014f65ae2e6cf3b4c58a4ce96b8f0967c4b0e0be6a9e669c25a06e6b412f115522522af613c6b8fee922d4f3f189d3c2696521afd63fdfc4103bd827a3eb4aba949a6e07424510af29c74e3de4faa1706bf128ac7f9f66306852da2390bb6cb8ed34c885b49d577e22b86222e95142b351dec31690804b98d98baa66b405cb6d649069d9e21254f2f81a6963962955c86e6a74be6c159eb9dce9eff7eb7e0c34f864d826ececbc1e577b4498b403140983fd716ca2b04aa5c23b8c18fe28367bc5ba76081c4aafd3
// CertifiedAccountSvc.certified_account_read.GetFollowList send 20da22db750806141ef44811080045000274511c400080060000c0a8030a71600dd0fe501f908b8c500d08ceca66501801ff454900000000024c0000000b0100014eaf000000000e313939343730313032318b6198dc33ae901346ecbe82c9821a5e2e7e68d070b2baa3dc8525246a625cb7461bf329a93acc9d20b0221108cd838505d2c0e2c9b944cf7c57eb17b74e74c99c873febfc6e89395b139c033c68d66b731b0ad4d9d7444471b7638628924c3ebb4c2ed326a87b1761d5d5a72043c5e3e538d5797843333867177b5f52445e0b5fa5805cba497e5f0f7da203da3504d74977180e1b86dcdb0c3b7298c4b10d6e53a145c277033e20445a82d0fcc78a1ce597294bf767e43ca42608e7531577d185cc14f91db8f3b71b614f5299ab75c448dd7462a0ce66b1a0992db05ebbab6667ca79ff39d2e9e5f58f73eb2b47cf1896e5560ebe389289b2222687ea8af254b4518ccc6d3468dd03ebce6247e7aac4278ba99210b4c91c49c6f29fd3ecb2653eae174e7bddaf40ef743f8da7605d09d36bca5ef84ee9b75d126db616fbe2b67cdbbb26809d56e97b2e4f6175da52694f0ee640ea1990dc79e5a0c2b266ddc16d0b7bf19818ad7727add2fd2ab379ba1b41763d953d0e21dd26e2f469e8273059f5130355a0976d5a01ca438f3b698b96a2c5394b6ebe381b3818b032ee5226a1a246935a741d39fb84feb917f9680d6c7b2e950e74def6523c318cbbe592904167f2ff8dbaf10616fb2b39a5af68fa19443e874ad2a6bc0639240903fccf8d2eecaacb9404c15ec387faf459f438c229e4a571234403078d270499a2634b13baf5051979ebe31ec8fedb55854e73d58534e51a924c637ee797389de4a27da494dbe7b50c69e1c4857537d3f369752e
@ -49,29 +49,27 @@ import kotlin.text.toByteArray
// ConfigPushSvc.PushResp, ** StatSvc.register send 20da22db750806141ef448110800450002f85124400080060000c0a8030a71600dd0fe501f908b8c558508cee2605018020045cd0000000000ac0000000b01a4da6eb0000000000e3139393437303130323122465f76192ce454d64e90a36fe651eb96d052893396c002a815851dc04994d16f7a596b06ca02b4743077fb387442f00409806ece8bf2f533a129073db60c8d5a22b9d4224387629e8ce29959a683f505b741aa1a83068239f6df0f97a4e5499c1035092e7466b005307110460211aecd1f11c10cea0cc861007e08882accb0bbaec68cd9c9a83fd19bb5eebda016ff000002240000000a0100000044e0e22a59327abb9ce80cf63be86694210344fab2f2b065d7785a32cacfa4075cd509f49cb37a075ad0685cbd472344bfdef1ede611c0ad81129be9e2d7e476d2000000000e31393934373031303231f4cf6ac405adbbfab64c0905f9f1f4b3236e4b17c34bc8aaefd77b184f012c036978eea06bb7f9e6d443a9d71f6eaf8b08b3c49858269de0405d7acf5076fd3000357cdbced53142200fcd8f87dc2a047ecfdd0d374aa0bb1b5c97b35e59a7cc77f146c930d04be6b70a75be3d71704d1b95794cbc36ef0ffe96533d61521c7b4b676f6b067859c0760ae5689f146b3c1a19668b694a50aa1d561f2feb76b49d507dc530d49007ba08f84297b23290177539d0b2a3ceb0a2ef8a64b65494e574ed78857fc1c93911c7639dce6699d5fde605f432d4ab7dfd6cf8cc5451950b29d79f5e755f90faadf55dfcb3993d9b4fb9479f44e47c1a0702205da298327b0deb180e2976d07be7b6ac0302b128d792200a092e084ca6908fe0c13e142d50f42783009029b3d2da23bd1050a2cc56023f943ce3b164002fa31fdf9624a255455cc77b774223726f36cccb2603240ca528534ee1533eb66872b007ea20bb5e76f87efa35d7dcb4be7e5f410ed7276c09e20f04db63ea4b79fd7d2201ef0ec14b5f9795bd2bd028e58b3ab8d3461a188f113a8b50406e9c3db9f8b2115924faadc9f2707c6715dc2dda73119228079467fbe145cf951cf1948e755aa428f4e478a6ab9708ad39ded4
private val wtSessionTicketKey = "B6 9D E4 EC 65 38 64 FD C8 3A D8 33 54 35 0C 73".hexToBytes()
private val tgtgtKey = "D7 71 03 E3 4C E5 8F 6B 05 D8 C7 8C 96 FB FB 23".hexToBytes()
private val deviceToken = "CE 1E 2E DC 69 24 4F 9B FF 2F 52 D8 8F 69 DD 40".hexToBytes()
private val D2Key = "44 28 6B 35 7A 54 2D 45 45 5D 56 32 44 33 47 49".hexToBytes()
private val userStKey = "35 29 42 54 78 62 47 68 5E 77 68 54 6B 76 57 5F".hexToBytes()
private val userStWebSig =
internal val wtSessionTicketKey = "B6 9D E4 EC 65 38 64 FD C8 3A D8 33 54 35 0C 73".hexToBytes()
internal val tgtgtKey = "D7 71 03 E3 4C E5 8F 6B 05 D8 C7 8C 96 FB FB 23".hexToBytes()
internal val deviceToken = "CE 1E 2E DC 69 24 4F 9B FF 2F 52 D8 8F 69 DD 40".hexToBytes()
internal val D2Key = "44 28 6B 35 7A 54 2D 45 45 5D 56 32 44 33 47 49".hexToBytes()
internal val userStKey = "35 29 42 54 78 62 47 68 5E 77 68 54 6B 76 57 5F".hexToBytes()
internal val userStWebSig =
"63 A2 BD 78 FC 88 58 AC 12 95 6C 15 6A 9B A1 EB B0 E8 66 D0 95 D2 0E B4 BC C3 48 05 C1 D9 54 FB 65 8F 21 29 E5 5D 84 BA A1 63 48 5C 24 F3 84 A3".hexToBytes()
private val tgtKey = "44 24 3F 43 3F 21 37 2B 29 44 6E 47 70 3A 4E 3D".hexToBytes()
internal val tgtKey = "44 24 3F 43 3F 21 37 2B 29 44 6E 47 70 3A 4E 3D".hexToBytes()
private val t108 = "BD 12 96 6C 83 53 EF DD 06 16 52 16 B8 1B 25 69".hexToBytes()
private val t10c = "23 7D 2C 7A 3F 4A 41 35 7D 3B 45 51 6D 3D 2A 56".hexToBytes()
private val t163 = "2C 7A 7B 23 4E 24 3F 24 24 47 62 6B 69 2E 47 50".hexToBytes()
internal val t108 = "BD 12 96 6C 83 53 EF DD 06 16 52 16 B8 1B 25 69".hexToBytes()
internal val t10c = "23 7D 2C 7A 3F 4A 41 35 7D 3B 45 51 6D 3D 2A 56".hexToBytes()
internal val t163 = "2C 7A 7B 23 4E 24 3F 24 24 47 62 6B 69 2E 47 50".hexToBytes()
private val shareKeyCalculatedByConstPubKey = ECDH.calculateShareKey(
internal val shareKeyCalculatedByConstPubKey = ECDH.calculateShareKey(
loadPrivateKey("97a52992cb7a2110413629af94a3c249c68a3b731510caa8"),
initialPublicKey
)
fun main() {
val data = """
20da22db750806141ef448110800450000d4512f400080060000c0a8030a71600dd0fe501f908b8c5c9908cf2416501801ff43a90000000000ac0000000b0100014f0d000000000e3139393437303130323193c94c8ce2871f6d5f6664df9e9231dedce5c7cb914cf5d616cf64af478aea9f210098e7f5efae9a952742b8fff704681885e5cc14a44e40d88910258f4a4a5cfcadd642cc159fdc475478475b18ba225cfad1c8bc2c5c828a9cc3ebaed1aa040d04b94f577fcfdb0861fd19754622733a242c5bcb37ca8597a2935d9910162111e44839b6787bb9be80058ad9c921c2
20da22db750806141ef448110800450002f85124400080060000c0a8030a71600dd0fe501f908b8c558508cee2605018020045cd0000000000ac0000000b01a4da6eb0000000000e3139393437303130323122465f76192ce454d64e90a36fe651eb96d052893396c002a815851dc04994d16f7a596b06ca02b4743077fb387442f00409806ece8bf2f533a129073db60c8d5a22b9d4224387629e8ce29959a683f505b741aa1a83068239f6df0f97a4e5499c1035092e7466b005307110460211aecd1f11c10cea0cc861007e08882accb0bbaec68cd9c9a83fd19bb5eebda016ff000002240000000a0100000044e0e22a59327abb9ce80cf63be86694210344fab2f2b065d7785a32cacfa4075cd509f49cb37a075ad0685cbd472344bfdef1ede611c0ad81129be9e2d7e476d2000000000e31393934373031303231f4cf6ac405adbbfab64c0905f9f1f4b3236e4b17c34bc8aaefd77b184f012c036978eea06bb7f9e6d443a9d71f6eaf8b08b3c49858269de0405d7acf5076fd3000357cdbced53142200fcd8f87dc2a047ecfdd0d374aa0bb1b5c97b35e59a7cc77f146c930d04be6b70a75be3d71704d1b95794cbc36ef0ffe96533d61521c7b4b676f6b067859c0760ae5689f146b3c1a19668b694a50aa1d561f2feb76b49d507dc530d49007ba08f84297b23290177539d0b2a3ceb0a2ef8a64b65494e574ed78857fc1c93911c7639dce6699d5fde605f432d4ab7dfd6cf8cc5451950b29d79f5e755f90faadf55dfcb3993d9b4fb9479f44e47c1a0702205da298327b0deb180e2976d07be7b6ac0302b128d792200a092e084ca6908fe0c13e142d50f42783009029b3d2da23bd1050a2cc56023f943ce3b164002fa31fdf9624a255455cc77b774223726f36cccb2603240ca528534ee1533eb66872b007ea20bb5e76f87efa35d7dcb4be7e5f410ed7276c09e20f04db63ea4b79fd7d2201ef0ec14b5f9795bd2bd028e58b3ab8d3461a188f113a8b50406e9c3db9f8b2115924faadc9f2707c6715dc2dda73119228079467fbe145cf951cf1948e755aa428f4e478a6ab9708ad39ded4
""".trimIndent()
@ -101,12 +99,11 @@ fun ByteReadPacket.analysisOneFullPacket() = debugIfFail("Failed", { buildPacket
val flag1 = readInt()
println("flag1=" + flag1.contentToString())
val flag2 = readByte().toInt()
println("flag2=$flag2")
if (flag1 == 0x0B) {
if (flag2 == 1) {
println("flag2=$flag2")
println("sequenceId = " + readInt().toUHexString())
} else {
println("flag2=$flag2")
println("extra data=" + readBytes(readInt() - 4).toUHexString())
}
} else {
@ -124,9 +121,9 @@ fun ByteReadPacket.analysisOneFullPacket() = debugIfFail("Failed", { buildPacket
println("// 解密 body")
readRemainingBytes().tryDecrypt().toReadPacket().debugPrint("outer body decrypted").apply {
when (flag2) {
2 -> decodeSso()
1 -> decodeUni()
when (flag1) {
0x0A -> decodeSso()
0x0B -> decodeUni()
}
}
}
@ -139,7 +136,7 @@ fun ByteReadPacket.decodeUni() {
// 00 00 00 5B 10 03 2C 3C 4C 56 23 51 51 53 65 72 76 69 63 65 2E 43 6F 6E 66 69 67 50 75 73 68 53 76 63 2E 4D 61 69 6E 53 65 72 76 61 6E 74 66 08 50 75 73 68 52 65 73 70 7D 00 00 1A 08 00 01 06 08 50 75 73 68 52 65 73 70 1D 00 00 09 0A 10 01 22 14 DA 6E B1 0B 8C 98 0C A8 0C
println("// 尝试解 Uni")
println("// head")
readBytes(readInt() - 4).read {
readBytes(readInt() - 4).debugPrint("head").toReadPacket().apply {
val commandName = readString(readInt() - 4).also { println("commandName=$it") }
println(" unknown4Bytes=" + readBytes(readInt() - 4).toUHexString())
// 00 00 00 1A 43 6F 6E 66 69 67 50 75 73 68 53 76 63 2E 50 75 73 68 52 65 73 70

View File

@ -41,8 +41,11 @@ fun ktor(id: String, version: String) = "io.ktor:ktor-$id:$version"
dependencies {
runtimeOnly(files("../mirai-core/build/classes/kotlin/jvm/main")) // IDE bug
runtimeOnly(files("../mirai-core-timpc/build/classes/kotlin/jvm/main")) // IDE bug
implementation(project(":mirai-core-timpc"))
runtimeOnly(files("../mirai-core-qqandroid/build/classes/kotlin/jvm/main")) // IDE bug
implementation(project(":mirai-core-qqandroid"))
// runtimeOnly(files("../mirai-core/build/classes/kotlin/jvm/main")) // classpath is not added correctly by IDE
implementation("org.bouncycastle:bcprov-jdk15on:1.64")
@ -70,4 +73,9 @@ dependencies {
implementation(ktor("client-core", ktorVersion))
implementation(ktor("network", ktorVersion))
testImplementation(kotlin("test-annotations-common"))
testImplementation(kotlin("test"))
testImplementation(kotlin("test-junit"))
testImplementation(kotlin("script-runtime"))
}

View File

@ -0,0 +1,79 @@
package jce.jce;
import java.io.UnsupportedEncodingException;
public class HexUtil {
private static final char[] digits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
public static final byte[] emptybytes = new byte[0];
public static String byte2HexStr(byte var0) {
char var1 = digits[var0 & 15];
var0 = (byte) (var0 >>> 4);
return new String(new char[]{digits[var0 & 15], var1});
}
public static String bytes2HexStr(byte[] var0) {
if (var0 != null && var0.length != 0) {
char[] var3 = new char[var0.length * 2];
for (int var1 = 0; var1 < var0.length; ++var1) {
byte var2 = var0[var1];
var3[var1 * 2 + 1] = digits[var2 & 15];
var2 = (byte) (var2 >>> 4);
var3[var1 * 2 + 0] = digits[var2 & 15];
}
return new String(var3);
} else {
return null;
}
}
public static byte char2Byte(char var0) {
if (var0 >= '0' && var0 <= '9') {
return (byte) (var0 - 48);
} else if (var0 >= 'a' && var0 <= 'f') {
return (byte) (var0 - 97 + 10);
} else {
return var0 >= 'A' && var0 <= 'F' ? (byte) (var0 - 65 + 10) : 0;
}
}
public static byte hexStr2Byte(String var0) {
byte var2 = 0;
byte var1 = var2;
if (var0 != null) {
var1 = var2;
if (var0.length() == 1) {
var1 = char2Byte(var0.charAt(0));
}
}
return var1;
}
public static byte[] hexStr2Bytes(String var0) {
if (var0 != null && !var0.equals("")) {
byte[] var4 = new byte[var0.length() / 2];
for (int var3 = 0; var3 < var4.length; ++var3) {
char var1 = var0.charAt(var3 * 2);
char var2 = var0.charAt(var3 * 2 + 1);
var4[var3] = (byte) (char2Byte(var1) * 16 + char2Byte(var2));
}
return var4;
} else {
return emptybytes;
}
}
public static void main(String[] var0) {
try {
byte[] var2 = "Hello WebSocket World?".getBytes("gbk");
System.out.println(bytes2HexStr(var2));
} catch (UnsupportedEncodingException var1) {
var1.printStackTrace();
}
}
}

View File

@ -0,0 +1,7 @@
package jce.jce;
public class JceDecodeException extends RuntimeException {
public JceDecodeException(String var1) {
super(var1);
}
}

View File

@ -0,0 +1,7 @@
package jce.jce;
public class JceEncodeException extends RuntimeException {
public JceEncodeException(String var1) {
super(var1);
}
}

View File

@ -0,0 +1,11 @@
package jce.jce;
public class JceInputStream$HeadData {
public int tag;
public byte type;
public void clear() {
this.type = 0;
this.tag = 0;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,430 @@
package jce.jce;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class JceOutputStream {
// $FF: renamed from: bs java.nio.ByteBuffer
private ByteBuffer field_80728;
private OnIllegalArgumentException exceptionHandler;
protected String sServerEncoding;
public JceOutputStream() {
this(128);
}
public JceOutputStream(int var1) {
this.sServerEncoding = "GBK";
this.field_80728 = ByteBuffer.allocate(var1);
}
public JceOutputStream(ByteBuffer var1) {
this.sServerEncoding = "GBK";
this.field_80728 = var1;
}
public static void main(String[] var0) {
JceOutputStream var2 = new JceOutputStream();
var2.write(1311768467283714885L, 0);
ByteBuffer var1 = var2.getByteBuffer();
System.out.println(HexUtil.bytes2HexStr(var1.array()));
System.out.println(Arrays.toString(var2.toByteArray()));
}
private void writeArray(Object[] var1, int var2) {
this.reserve(8);
this.writeHead((byte) 9, var2);
this.write(var1.length, 0);
int var3 = var1.length;
for (var2 = 0; var2 < var3; ++var2) {
this.write(var1[var2], 0);
}
}
public ByteBuffer getByteBuffer() {
return this.field_80728;
}
public OnIllegalArgumentException getExceptionHandler() {
return this.exceptionHandler;
}
public void reserve(int var1) {
if (this.field_80728.remaining() < var1) {
int var2 = (this.field_80728.capacity() + var1) * 2;
ByteBuffer var3;
try {
var3 = ByteBuffer.allocate(var2);
var3.put(this.field_80728.array(), 0, this.field_80728.position());
} catch (IllegalArgumentException var4) {
if (this.exceptionHandler != null) {
this.exceptionHandler.onException(var4, this.field_80728, var1, var2);
}
throw var4;
}
this.field_80728 = var3;
}
}
public void setExceptionHandler(OnIllegalArgumentException var1) {
this.exceptionHandler = var1;
}
public int setServerEncoding(String var1) {
this.sServerEncoding = var1;
return 0;
}
public byte[] toByteArray() {
byte[] var1 = new byte[this.field_80728.position()];
System.arraycopy(this.field_80728.array(), 0, var1, 0, this.field_80728.position());
return var1;
}
public void write(byte var1, int var2) {
this.reserve(3);
if (var1 == 0) {
this.writeHead((byte) 12, var2);
} else {
this.writeHead((byte) 0, var2);
this.field_80728.put(var1);
}
}
public void write(double var1, int var3) {
this.reserve(10);
this.writeHead((byte) 5, var3);
this.field_80728.putDouble(var1);
}
public void write(float var1, int var2) {
this.reserve(6);
this.writeHead((byte) 4, var2);
this.field_80728.putFloat(var1);
}
public void write(int var1, int var2) {
this.reserve(6);
if (var1 >= -32768 && var1 <= 32767) {
this.write((short) var1, var2);
} else {
this.writeHead((byte) 2, var2);
this.field_80728.putInt(var1);
}
}
public void write(long var1, int id) {
this.reserve(10);
if (var1 >= -2147483648L && var1 <= 2147483647L) {
this.write((int) var1, id);
} else {
this.writeHead((byte) 3, id);
this.field_80728.putLong(var1);
}
}
public void write(JceStruct var1, int var2) {
this.reserve(2);
this.writeHead((byte) 10, var2);
var1.writeTo(this);
this.reserve(2);
this.writeHead((byte) 11, 0);
}
public void write(Boolean var1, int var2) {
this.write((boolean) var1, var2);
}
public void write(Byte var1, int var2) {
this.write((byte) var1, var2);
}
public void write(Double var1, int var2) {
this.write((double) var1, var2);
}
public void write(Float var1, int var2) {
this.write((float) var1, var2);
}
public void write(Integer var1, int var2) {
this.write((int) var1, var2);
}
public void write(Long var1, int var2) {
this.write((long) var1, var2);
}
public void write(Object var1, int var2) {
if (var1 instanceof Byte) {
this.write((Byte) var1, var2);
} else if (var1 instanceof Boolean) {
this.write((Boolean) var1, var2);
} else if (var1 instanceof Short) {
this.write((Short) var1, var2);
} else if (var1 instanceof Integer) {
this.write((Integer) var1, var2);
} else if (var1 instanceof Long) {
this.write((Long) var1, var2);
} else if (var1 instanceof Float) {
this.write((Float) var1, var2);
} else if (var1 instanceof Double) {
this.write((Double) var1, var2);
} else if (var1 instanceof String) {
this.write((String) var1, var2);
} else if (var1 instanceof Map) {
this.write((Map) var1, var2);
} else if (var1 instanceof List) {
this.write((List) var1, var2);
} else if (var1 instanceof JceStruct) {
this.write((JceStruct) var1, var2);
} else if (var1 instanceof byte[]) {
this.write((byte[]) var1, var2);
} else if (var1 instanceof boolean[]) {
this.write((boolean[]) var1, var2);
} else if (var1 instanceof short[]) {
this.write((short[]) var1, var2);
} else if (var1 instanceof int[]) {
this.write((int[]) var1, var2);
} else if (var1 instanceof long[]) {
this.write((long[]) var1, var2);
} else if (var1 instanceof float[]) {
this.write((float[]) var1, var2);
} else if (var1 instanceof double[]) {
this.write((double[]) var1, var2);
} else if (var1.getClass().isArray()) {
this.writeArray((Object[]) var1, var2);
} else if (var1 instanceof Collection) {
this.write((Collection) var1, var2);
} else {
throw new JceEncodeException("write object error: unsupport type. " + var1.getClass());
}
}
public void write(Short var1, int var2) {
this.write((short) var1, var2);
}
public void write(String var1, int var2) {
byte[] var5;
label16:
{
byte[] var3;
try {
var3 = var1.getBytes(this.sServerEncoding);
} catch (UnsupportedEncodingException var4) {
var5 = var1.getBytes();
break label16;
}
var5 = var3;
}
this.reserve(var5.length + 10);
if (var5.length > 255) {
this.writeHead((byte) 7, var2);
this.field_80728.putInt(var5.length);
} else {
this.writeHead((byte) 6, var2);
this.field_80728.put((byte) var5.length);
}
this.field_80728.put(var5);
}
public <T> void write(Collection<T> var1, int var2) {
this.reserve(8);
this.writeHead((byte) 9, var2);
if (var1 == null) {
var2 = 0;
} else {
var2 = var1.size();
}
this.write(var2, 0);
if (var1 != null) {
for (T t : var1) {
this.write(t, 0);
}
}
}
public <K, V> void write(Map<K, V> var1, int var2) {
this.reserve(8);
this.writeHead((byte) 8, var2);
if (var1 == null) {
var2 = 0;
} else {
var2 = var1.size();
}
this.write(var2, 0);
if (var1 != null) {
for (Entry<K, V> kvEntry : var1.entrySet()) {
this.write(((Entry) kvEntry).getKey(), 0);
this.write(((Entry) kvEntry).getValue(), 1);
}
}
}
public void write(short var1, int var2) {
this.reserve(4);
if (var1 >= -128 && var1 <= 127) {
this.write((byte) var1, var2);
} else {
this.writeHead((byte) 1, var2);
this.field_80728.putShort(var1);
}
}
public void write(boolean var1, int var2) {
byte var3;
if (var1) {
var3 = 1;
} else {
var3 = 0;
}
this.write(var3, var2);
}
public void write(byte[] var1, int var2) {
this.reserve(var1.length + 8);
this.writeHead((byte) 13, var2);
this.writeHead((byte) 0, 0);
this.write(var1.length, 0);
this.field_80728.put(var1);
}
public void write(double[] var1, int var2) {
this.reserve(8);
this.writeHead((byte) 9, var2);
this.write(var1.length, 0);
int var3 = var1.length;
for (var2 = 0; var2 < var3; ++var2) {
this.write(var1[var2], 0);
}
}
public void write(float[] var1, int var2) {
this.reserve(8);
this.writeHead((byte) 9, var2);
this.write(var1.length, 0);
int var3 = var1.length;
for (var2 = 0; var2 < var3; ++var2) {
this.write(var1[var2], 0);
}
}
public void write(int[] var1, int var2) {
this.reserve(8);
this.writeHead((byte) 9, var2);
this.write(var1.length, 0);
int var3 = var1.length;
for (var2 = 0; var2 < var3; ++var2) {
this.write(var1[var2], 0);
}
}
public void write(long[] var1, int var2) {
this.reserve(8);
this.writeHead((byte) 9, var2);
this.write(var1.length, 0);
int var3 = var1.length;
for (var2 = 0; var2 < var3; ++var2) {
this.write(var1[var2], 0);
}
}
public <T> void write(T[] var1, int var2) {
this.writeArray(var1, var2);
}
public void write(short[] var1, int var2) {
this.reserve(8);
this.writeHead((byte) 9, var2);
this.write(var1.length, 0);
int var3 = var1.length;
for (var2 = 0; var2 < var3; ++var2) {
this.write(var1[var2], 0);
}
}
public void write(boolean[] var1, int var2) {
this.reserve(8);
this.writeHead((byte) 9, var2);
this.write(var1.length, 0);
int var3 = var1.length;
for (var2 = 0; var2 < var3; ++var2) {
this.write(var1[var2], 0);
}
}
public void writeByteString(String var1, int var2) {
this.reserve(var1.length() + 10);
byte[] var3 = HexUtil.hexStr2Bytes(var1);
if (var3.length > 255) {
this.writeHead((byte) 7, var2);
this.field_80728.putInt(var3.length);
this.field_80728.put(var3);
} else {
this.writeHead((byte) 6, var2);
this.field_80728.put((byte) var3.length);
this.field_80728.put(var3);
}
}
public void writeHead(byte var1, int var2) {
byte var3;
if (var2 < 15) {
var3 = (byte) (var2 << 4 | var1);
this.field_80728.put(var3);
} else if (var2 < 256) {
var3 = (byte) (var1 | 240);
this.field_80728.put(var3);
this.field_80728.put((byte) var2);
} else {
throw new JceEncodeException("tag is too large: " + var2);
}
}
public void writeStringByte(String var1, int var2) {
byte[] var3 = HexUtil.hexStr2Bytes(var1);
this.reserve(var3.length + 10);
if (var3.length > 255) {
this.writeHead((byte) 7, var2);
this.field_80728.putInt(var3.length);
this.field_80728.put(var3);
} else {
this.writeHead((byte) 6, var2);
this.field_80728.put((byte) var3.length);
this.field_80728.put(var3);
}
}
}

View File

@ -0,0 +1,78 @@
package jce.jce;
import java.io.Serializable;
public abstract class JceStruct implements Serializable {
public static final byte BYTE = 0;
public static final byte DOUBLE = 5;
public static final byte FLOAT = 4;
public static final byte INT = 2;
public static final int JCE_MAX_STRING_LENGTH = 104857600;
public static final byte LIST = 9;
public static final byte LONG = 3;
public static final byte MAP = 8;
public static final byte SHORT = 1;
public static final byte SIMPLE_LIST = 13;
public static final byte STRING1 = 6;
public static final byte STRING4 = 7;
public static final byte STRUCT_BEGIN = 10;
public static final byte STRUCT_END = 11;
public static final byte ZERO_TAG = 12;
public static String toDisplaySimpleString(JceStruct var0) {
if (var0 == null) {
return null;
} else {
StringBuilder var1 = new StringBuilder();
var0.displaySimple(var1, 0);
return var1.toString();
}
}
public boolean containField(String var1) {
return false;
}
public void display(StringBuilder var1, int var2) {
}
public void displaySimple(StringBuilder var1, int var2) {
}
public Object getFieldByName(String var1) {
return null;
}
public JceStruct newInit() {
return null;
}
public abstract void readFrom(JceInputStream var1);
public void recyle() {
}
public void setFieldByName(String var1, Object var2) {
}
public byte[] toByteArray() {
JceOutputStream var1 = new JceOutputStream();
this.writeTo(var1);
return var1.toByteArray();
}
public byte[] toByteArray(String var1) {
JceOutputStream var2 = new JceOutputStream();
var2.setServerEncoding(var1);
this.writeTo(var2);
return var2.toByteArray();
}
public String toString() {
StringBuilder var1 = new StringBuilder();
this.display(var1, 0);
return var1.toString();
}
public abstract void writeTo(JceOutputStream var1);
}

View File

@ -0,0 +1,594 @@
package jce.jce;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.List;
public final class JceUtil {
private static final byte[] highDigits;
private static final int iConstant = 37;
private static final int iTotal = 17;
private static final byte[] lowDigits;
static {
byte[] var1 = new byte[]{48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70};
byte[] var2 = new byte[256];
byte[] var3 = new byte[256];
for (int var0 = 0; var0 < 256; ++var0) {
var2[var0] = var1[var0 >>> 4];
var3[var0] = var1[var0 & 15];
}
highDigits = var2;
lowDigits = var3;
}
public static int compareTo(byte var0, byte var1) {
if (var0 < var1) {
return -1;
} else {
return var0 > var1 ? 1 : 0;
}
}
public static int compareTo(char var0, char var1) {
if (var0 < var1) {
return -1;
} else {
return var0 > var1 ? 1 : 0;
}
}
public static int compareTo(double var0, double var2) {
if (var0 < var2) {
return -1;
} else {
return var0 > var2 ? 1 : 0;
}
}
public static int compareTo(float var0, float var1) {
if (var0 < var1) {
return -1;
} else {
return var0 > var1 ? 1 : 0;
}
}
public static int compareTo(int var0, int var1) {
if (var0 < var1) {
return -1;
} else {
return var0 > var1 ? 1 : 0;
}
}
public static int compareTo(long var0, long var2) {
if (var0 < var2) {
return -1;
} else {
return var0 > var2 ? 1 : 0;
}
}
public static <T extends Comparable<T>> int compareTo(T var0, T var1) {
return var0.compareTo(var1);
}
public static <T extends Comparable<T>> int compareTo(List<T> var0, List<T> var1) {
Iterator var3 = var0.iterator();
Iterator var4 = var1.iterator();
while (var3.hasNext() && var4.hasNext()) {
int var2 = ((Comparable) var3.next()).compareTo(var4.next());
if (var2 != 0) {
return var2;
}
}
return compareTo(var3.hasNext(), var4.hasNext());
}
public static int compareTo(short var0, short var1) {
if (var0 < var1) {
return -1;
} else {
return var0 > var1 ? 1 : 0;
}
}
public static int compareTo(boolean var0, boolean var1) {
byte var3 = 1;
byte var2;
if (var0) {
var2 = 1;
} else {
var2 = 0;
}
if (!var1) {
var3 = 0;
}
return var2 - var3;
}
public static int compareTo(byte[] var0, byte[] var1) {
int var3 = 0;
for (int var2 = 0; var2 < var0.length && var3 < var1.length; ++var2) {
int var4 = compareTo(var0[var2], var1[var3]);
if (var4 != 0) {
return var4;
}
++var3;
}
return compareTo(var0.length, var1.length);
}
public static int compareTo(char[] var0, char[] var1) {
int var3 = 0;
for (int var2 = 0; var2 < var0.length && var3 < var1.length; ++var2) {
int var4 = compareTo(var0[var2], var1[var3]);
if (var4 != 0) {
return var4;
}
++var3;
}
return compareTo(var0.length, var1.length);
}
public static int compareTo(double[] var0, double[] var1) {
int var3 = 0;
for (int var2 = 0; var2 < var0.length && var3 < var1.length; ++var2) {
int var4 = compareTo(var0[var2], var1[var3]);
if (var4 != 0) {
return var4;
}
++var3;
}
return compareTo(var0.length, var1.length);
}
public static int compareTo(float[] var0, float[] var1) {
int var3 = 0;
for (int var2 = 0; var2 < var0.length && var3 < var1.length; ++var2) {
int var4 = compareTo(var0[var2], var1[var3]);
if (var4 != 0) {
return var4;
}
++var3;
}
return compareTo(var0.length, var1.length);
}
public static int compareTo(int[] var0, int[] var1) {
int var3 = 0;
for (int var2 = 0; var2 < var0.length && var3 < var1.length; ++var2) {
int var4 = compareTo(var0[var2], var1[var3]);
if (var4 != 0) {
return var4;
}
++var3;
}
return compareTo(var0.length, var1.length);
}
public static int compareTo(long[] var0, long[] var1) {
int var3 = 0;
for (int var2 = 0; var2 < var0.length && var3 < var1.length; ++var2) {
int var4 = compareTo(var0[var2], var1[var3]);
if (var4 != 0) {
return var4;
}
++var3;
}
return compareTo(var0.length, var1.length);
}
public static <T extends Comparable<T>> int compareTo(T[] var0, T[] var1) {
int var3 = 0;
for (int var2 = 0; var2 < var0.length && var3 < var1.length; ++var2) {
int var4 = var0[var2].compareTo(var1[var3]);
if (var4 != 0) {
return var4;
}
++var3;
}
return compareTo(var0.length, var1.length);
}
public static int compareTo(short[] var0, short[] var1) {
int var3 = 0;
for (int var2 = 0; var2 < var0.length && var3 < var1.length; ++var2) {
int var4 = compareTo(var0[var2], var1[var3]);
if (var4 != 0) {
return var4;
}
++var3;
}
return compareTo(var0.length, var1.length);
}
public static int compareTo(boolean[] var0, boolean[] var1) {
int var3 = 0;
for (int var2 = 0; var2 < var0.length && var3 < var1.length; ++var2) {
int var4 = compareTo(var0[var2], var1[var3]);
if (var4 != 0) {
return var4;
}
++var3;
}
return compareTo(var0.length, var1.length);
}
public static boolean equals(byte var0, byte var1) {
return var0 == var1;
}
public static boolean equals(char var0, char var1) {
return var0 == var1;
}
public static boolean equals(double var0, double var2) {
return var0 == var2;
}
public static boolean equals(float var0, float var1) {
return var0 == var1;
}
public static boolean equals(int var0, int var1) {
return var0 == var1;
}
public static boolean equals(long var0, long var2) {
return var0 == var2;
}
public static boolean equals(Object var0, Object var1) {
return var0.equals(var1);
}
public static boolean equals(short var0, short var1) {
return var0 == var1;
}
public static boolean equals(boolean var0, boolean var1) {
return var0 == var1;
}
public static String getHexdump(ByteBuffer var0) {
int var1 = var0.remaining();
if (var1 == 0) {
return "empty";
} else {
StringBuffer var4 = new StringBuffer(var0.remaining() * 3 - 1);
int var2 = var0.position();
int var3 = var0.get() & 255;
var4.append((char) highDigits[var3]);
var4.append((char) lowDigits[var3]);
--var1;
while (var1 > 0) {
var4.append(' ');
var3 = var0.get() & 255;
var4.append((char) highDigits[var3]);
var4.append((char) lowDigits[var3]);
--var1;
}
var0.position(var2);
return var4.toString();
}
}
public static String getHexdump(byte[] var0) {
return getHexdump(ByteBuffer.wrap(var0));
}
public static byte[] getJceBufArray(ByteBuffer var0) {
byte[] var1 = new byte[var0.position()];
System.arraycopy(var0.array(), 0, var1, 0, var1.length);
return var1;
}
public static int hashCode(byte var0) {
return var0 + 629;
}
public static int hashCode(char var0) {
return var0 + 629;
}
public static int hashCode(double var0) {
return hashCode(Double.doubleToLongBits(var0));
}
public static int hashCode(float var0) {
return Float.floatToIntBits(var0) + 629;
}
public static int hashCode(int var0) {
return var0 + 629;
}
public static int hashCode(long var0) {
return (int) (var0 >> 32 ^ var0) + 629;
}
public static int hashCode(Object var0) {
if (var0 == null) {
return 629;
} else if (var0.getClass().isArray()) {
if (var0 instanceof long[]) {
return hashCode((long[]) ((long[]) var0));
} else if (var0 instanceof int[]) {
return hashCode((int[]) ((int[]) var0));
} else if (var0 instanceof short[]) {
return hashCode((short[]) ((short[]) var0));
} else if (var0 instanceof char[]) {
return hashCode((char[]) ((char[]) var0));
} else if (var0 instanceof byte[]) {
return hashCode((byte[]) ((byte[]) var0));
} else if (var0 instanceof double[]) {
return hashCode((double[]) ((double[]) var0));
} else if (var0 instanceof float[]) {
return hashCode((float[]) ((float[]) var0));
} else if (var0 instanceof boolean[]) {
return hashCode((boolean[]) ((boolean[]) var0));
} else {
return var0 instanceof JceStruct[] ? hashCode((JceStruct[]) ((JceStruct[]) var0)) : hashCode((Object) ((Object[]) ((Object[]) var0)));
}
} else {
return var0 instanceof JceStruct ? var0.hashCode() : var0.hashCode() + 629;
}
}
public static int hashCode(short var0) {
return var0 + 629;
}
public static int hashCode(boolean var0) {
byte var1;
if (var0) {
var1 = 0;
} else {
var1 = 1;
}
return var1 + 629;
}
public static int hashCode(byte[] var0) {
int var3;
if (var0 == null) {
var3 = 629;
} else {
int var1 = 17;
int var2 = 0;
while (true) {
var3 = var1;
if (var2 >= var0.length) {
break;
}
var1 = var1 * 37 + var0[var2];
++var2;
}
}
return var3;
}
public static int hashCode(char[] var0) {
int var3;
if (var0 == null) {
var3 = 629;
} else {
int var1 = 17;
int var2 = 0;
while (true) {
var3 = var1;
if (var2 >= var0.length) {
break;
}
var1 = var1 * 37 + var0[var2];
++var2;
}
}
return var3;
}
public static int hashCode(double[] var0) {
int var3;
if (var0 == null) {
var3 = 629;
} else {
int var1 = 17;
int var2 = 0;
while (true) {
var3 = var1;
if (var2 >= var0.length) {
break;
}
var1 = var1 * 37 + (int) (Double.doubleToLongBits(var0[var2]) ^ Double.doubleToLongBits(var0[var2]) >> 32);
++var2;
}
}
return var3;
}
public static int hashCode(float[] var0) {
int var3;
if (var0 == null) {
var3 = 629;
} else {
int var1 = 17;
int var2 = 0;
while (true) {
var3 = var1;
if (var2 >= var0.length) {
break;
}
var1 = var1 * 37 + Float.floatToIntBits(var0[var2]);
++var2;
}
}
return var3;
}
public static int hashCode(int[] var0) {
int var3;
if (var0 == null) {
var3 = 629;
} else {
int var1 = 17;
int var2 = 0;
while (true) {
var3 = var1;
if (var2 >= var0.length) {
break;
}
var1 = var1 * 37 + var0[var2];
++var2;
}
}
return var3;
}
public static int hashCode(long[] var0) {
int var3;
if (var0 == null) {
var3 = 629;
} else {
int var1 = 17;
int var2 = 0;
while (true) {
var3 = var1;
if (var2 >= var0.length) {
break;
}
var1 = var1 * 37 + (int) (var0[var2] ^ var0[var2] >> 32);
++var2;
}
}
return var3;
}
public static int hashCode(JceStruct[] var0) {
int var3;
if (var0 == null) {
var3 = 629;
} else {
int var1 = 17;
int var2 = 0;
while (true) {
var3 = var1;
if (var2 >= var0.length) {
break;
}
var1 = var1 * 37 + var0[var2].hashCode();
++var2;
}
}
return var3;
}
public static int hashCode(short[] var0) {
int var3;
if (var0 == null) {
var3 = 629;
} else {
int var1 = 17;
int var2 = 0;
while (true) {
var3 = var1;
if (var2 >= var0.length) {
break;
}
var1 = var1 * 37 + var0[var2];
++var2;
}
}
return var3;
}
public static int hashCode(boolean[] var0) {
int var3;
if (var0 == null) {
var3 = 629;
} else {
int var1 = 17;
int var2 = 0;
while (true) {
var3 = var1;
if (var2 >= var0.length) {
break;
}
byte var4;
if (var0[var2]) {
var4 = 0;
} else {
var4 = 1;
}
var1 = var4 + var1 * 37;
++var2;
}
}
return var3;
}
}

View File

@ -0,0 +1,7 @@
package jce.jce;
import java.nio.ByteBuffer;
public interface OnIllegalArgumentException {
void onException(IllegalArgumentException var1, ByteBuffer var2, int var3, int var4);
}

View File

@ -0,0 +1,293 @@
package jceTest
import io.ktor.util.InternalAPI
import jce.jce.JceInputStream
import jce.jce.JceOutputStream
import jce.jce.JceStruct
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.readBytes
import net.mamoe.mirai.qqandroid.network.io.JceInput
import net.mamoe.mirai.qqandroid.network.io.JceOutput
import net.mamoe.mirai.qqandroid.network.io.buildJcePacket
import net.mamoe.mirai.utils.io.toUHexString
import org.junit.Test
private infix fun ByteReadPacket.shouldEqualTo(another: ByteArray) {
this.readBytes().let {
check(it.contentEquals(another)) {
"""actual: ${it.toUHexString()}
|required: ${another.toUHexString()}
""".trimMargin()
}
}
}
@UseExperimental(InternalAPI::class)
private fun qqJce(block: JceOutputStream.() -> Unit): ByteArray {
return JceOutputStream().apply(block).toByteArray()
}
internal class JceOutputTest {
@Test
fun writeByte() {
buildJcePacket {
writeByte(1, 1)
writeByte(-128, 2)
} shouldEqualTo qqJce {
write(1.toByte(), 1)
write((-128).toByte(), 2)
}
}
@Test
fun writeDouble() {
buildJcePacket {
writeDouble(1.0, 1)
writeDouble(-128.0, 2)
} shouldEqualTo qqJce {
write(1.toDouble(), 1)
write((-128).toDouble(), 2)
}
}
@Test
fun writeFloat() {
buildJcePacket {
writeFloat(1.0f, 1)
writeFloat(-128.0f, 2)
} shouldEqualTo qqJce {
write(1.toFloat(), 1)
write((-128).toFloat(), 2)
}
}
@Test
fun writeFully() {
buildJcePacket {
writeFully(byteArrayOf(1, 2), 1)
writeFully(byteArrayOf(1, 2), 2)
} shouldEqualTo qqJce {
write(byteArrayOf(1, 2), 1)
write(byteArrayOf(1, 2), 2)
}
}
@Test
fun testWriteFully() {
buildJcePacket {
writeFully(intArrayOf(1, 2), 1)
writeFully(intArrayOf(1, 2), 2)
} shouldEqualTo qqJce {
write(intArrayOf(1, 2), 1)
write(intArrayOf(1, 2), 2)
}
}
@Test
fun testWriteFully1() {
buildJcePacket {
writeFully(shortArrayOf(1, 2), 1)
writeFully(shortArrayOf(1, 2), 2)
} shouldEqualTo qqJce {
write(shortArrayOf(1, 2), 1)
write(shortArrayOf(1, 2), 2)
}
}
@Test
fun testWriteFully2() {
buildJcePacket {
writeFully(booleanArrayOf(true, false), 1)
writeFully(booleanArrayOf(true, false), 2)
} shouldEqualTo qqJce {
write(booleanArrayOf(true, false), 1)
write(booleanArrayOf(true, false), 2)
}
}
@Test
fun testWriteFully3() {
buildJcePacket {
writeFully(longArrayOf(1, 2), 1)
writeFully(longArrayOf(1, 2), 2)
} shouldEqualTo qqJce {
write(longArrayOf(1, 2), 1)
write(longArrayOf(1, 2), 2)
}
}
@Test
fun testWriteFully4() {
buildJcePacket {
writeFully(floatArrayOf(1f, 2f), 1)
writeFully(floatArrayOf(1f, 2f), 2)
} shouldEqualTo qqJce {
write(floatArrayOf(1f, 2f), 1)
write(floatArrayOf(1f, 2f), 2)
}
}
@Test
fun testWriteFully5() {
buildJcePacket {
writeFully(doubleArrayOf(1.0, 2.0), 1)
writeFully(doubleArrayOf(1.0, 2.0), 2)
} shouldEqualTo qqJce {
write(doubleArrayOf(1.0, 2.0), 1)
write(doubleArrayOf(1.0, 2.0), 2)
}
}
@Test
fun testWriteFully6() {
buildJcePacket {
writeFully(arrayOf("123", "哈哈"), 1)
writeFully(arrayOf("123", "哈哈"), 2)
} shouldEqualTo qqJce {
write(arrayOf("123", "哈哈"), 1)
write(arrayOf("123", "哈哈"), 2)
}
}
@Test
fun writeInt() {
buildJcePacket {
writeInt(1, 1)
writeInt(-128, 2)
} shouldEqualTo qqJce {
write(1, 1)
write(-128, 2)
}
}
@Test
fun writeLong() {
buildJcePacket {
writeLong(1, 1)
writeLong(-128, 2)
} shouldEqualTo qqJce {
write(1L, 1)
write(-128L, 2)
}
}
@Test
fun writeShort() {
buildJcePacket {
writeShort(1, 1)
writeShort(-128, 2)
} shouldEqualTo qqJce {
write(1.toShort(), 1)
write((-128).toShort(), 2)
}
}
@Test
fun writeBoolean() {
buildJcePacket {
writeBoolean(true, 1)
writeBoolean(false, 2)
} shouldEqualTo qqJce {
write(true, 1)
write(false, 2)
}
}
@Test
fun writeString() {
buildJcePacket {
writeString("1", 1)
writeString("哈啊", 2)
} shouldEqualTo qqJce {
write("1", 1)
write("哈啊", 2)
}
}
@Test
fun writeMap() {
buildJcePacket {
writeMap(mapOf("" to ""), 1)
writeMap(mapOf("" to 123), 2)
writeMap(mapOf(123.0 to "Hello"), 3)
} shouldEqualTo qqJce {
write(mapOf("" to ""), 1)
write(mapOf("" to 123), 2)
write(mapOf(123.0 to "Hello"), 3)
}
}
@Test
fun writeCollection() {
buildJcePacket {
writeMap(mapOf("" to ""), 1)
writeMap(mapOf("" to 123), 2)
writeMap(mapOf(123.0 to "Hello"), 3)
} shouldEqualTo qqJce {
write(mapOf("" to ""), 1)
write(mapOf("" to 123), 2)
write(mapOf(123.0 to "Hello"), 3)
}
}
data class TestMiraiStruct(
val message: String
) : net.mamoe.mirai.qqandroid.network.io.JceStruct() {
override fun writeTo(builder: JceOutput) {
builder.writeString(message, 0)
}
companion object : Factory<TestMiraiStruct> {
override fun newInstanceFrom(input: JceInput): TestMiraiStruct {
return TestMiraiStruct(input.readString(0))
}
}
}
class TestQQStruct(
private var message: String
) : JceStruct() {
override fun readFrom(var1: JceInputStream) {
message = var1.read("", 0, true)
}
override fun writeTo(var1: JceOutputStream) {
var1.write(message, 0)
}
}
@Test
fun writeJceStruct() {
buildJcePacket {
writeJceStruct(TestMiraiStruct("Hello"), 0)
writeJceStruct(TestMiraiStruct(""), 1)
} shouldEqualTo qqJce {
write(TestQQStruct("Hello"), 0)
write(TestQQStruct(""), 1)
}
}
@Test
fun writeObject() {
buildJcePacket {
writeObject(0.toByte(), 1)
writeObject(0.toShort(), 2)
writeObject(0, 3)
writeObject(0L, 4)
writeObject(0f, 5)
writeObject(0.0, 6)
writeObject("hello", 7)
writeObject(TestMiraiStruct("Hello"), 8)
} shouldEqualTo qqJce {
write(0.toByte(), 1)
write(0.toShort(), 2)
write(0, 3)
write(0L, 4)
write(0f, 5)
write(0.0, 6)
write("hello", 7)
write(TestQQStruct("Hello"), 8)
}
}
}