Update syncCookie

This commit is contained in:
Him188 2020-02-01 23:17:53 +08:00
parent 424c9bb2af
commit d5ff8f3933
12 changed files with 99 additions and 70 deletions

View File

@ -212,7 +212,7 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
}
override fun encodeTaggedEnum(tag: Int, enumDescription: SerialDescriptor, ordinal: Int) {
TODO()
encodeTaggedInt(tag, ordinal)
}
override fun encodeTaggedNull(tag: Int) {
@ -332,9 +332,9 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
override fun decodeTaggedString(tag: Int): String = input.readString(tag)
override fun decodeTaggedBoolean(tag: Int): Boolean = input.readBoolean(tag)
override fun decodeTaggedEnum(tag: Int, enumDescription: SerialDescriptor): Int =
TODO()
override fun decodeTaggedEnum(tag: Int, enumDescription: SerialDescriptor): Int {
return input.readInt(tag)
}
/**
* [KSerializer.serialize]

View File

@ -17,16 +17,15 @@ import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.QQImpl
import net.mamoe.mirai.qqandroid.event.ForceOfflineEvent
import net.mamoe.mirai.qqandroid.event.PacketReceivedEvent
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
import net.mamoe.mirai.qqandroid.network.protocol.packet.*
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc
import net.mamoe.mirai.utils.LockFreeLinkedList
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.cryptor.contentToString
import net.mamoe.mirai.utils.getValue
import net.mamoe.mirai.utils.io.*
import net.mamoe.mirai.utils.unsafeWeakRef
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
@ -112,6 +111,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
}
}
val msg = MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<MessageSvc.PbGetMsg.Response>()
println(msg.contentToString())
try {
bot.logger.info("开始加载组信息")
val troopData = FriendList.GetTroopListSimplify(
@ -363,19 +365,17 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
channel.send(delegate)
}
bot.logger.info("Send: ${this.commandName}")
try {
return withTimeoutOrNull(timeoutMillis) {
@Suppress("UNCHECKED_CAST")
handler.await() as E
// 不要 `withTimeout`. timeout 的异常会不知道去哪了.
} ?: net.mamoe.mirai.qqandroid.utils.inline {
error("timeout when receiving response of $commandName")
}
} finally {
packetListeners.remove(handler)
return withTimeoutOrNull(timeoutMillis) {
@Suppress("UNCHECKED_CAST")
handler.await() as E
// 不要 `withTimeout`. timeout 的异常会不知道去哪了.
} ?: net.mamoe.mirai.qqandroid.utils.inline {
error("timeout when receiving response of $commandName")
}
} catch (e: Exception) {
lastException = e
} finally {
packetListeners.remove(handler)
}
}
throw lastException!!

View File

@ -96,7 +96,10 @@ internal open class QQAndroidClient(
val apkVersionName: ByteArray = "8.2.0".toByteArray()
private val messageSequenceId: AtomicInt = atomic(0)
internal fun atomicNextMessageSequenceId(): Int = messageSequenceId.getAndIncrement()
internal fun atomicNextMessageSequenceId(): Int = messageSequenceId.getAndAdd(2)
private val requestPacketRequestId: AtomicInt = atomic(1921334513)
internal fun nextRequestPacketRequestId(): Int = requestPacketRequestId.getAndAdd(2)
val appClientVersion: Int = 0
@ -112,7 +115,6 @@ internal open class QQAndroidClient(
class C2cMessageSyncData {
var syncCookie: ByteArray? = null
var pubAccountCookie = EMPTY_BYTE_ARRAY
var syncFlag: Int = 0
var msgCtrlBuf: ByteArray = EMPTY_BYTE_ARRAY
}

View File

@ -1,7 +1,5 @@
package net.mamoe.mirai.qqandroid.network.protocol.data.jce
import kotlinx.atomicfu.AtomicInt
import kotlinx.atomicfu.atomic
import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable
import net.mamoe.mirai.qqandroid.io.JceStruct
@ -14,20 +12,14 @@ internal class RequestPacket(
@SerialId(1) val iVersion: Short = 3,
@SerialId(2) val cPacketType: Byte = 0,
@SerialId(3) val iMessageType: Int = 0,
@SerialId(4) val iRequestId: Int = nextRequestPacketRequestId(),
@SerialId(4) val iRequestId: Int,
@SerialId(5) val sServantName: String = "",
@SerialId(6) val sFuncName: String = "",
@SerialId(7) val sBuffer: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(8) val iTimeout: Int = 0,
@SerialId(9) val context: Map<String, String> = EMPTY_MAP,
@SerialId(10) val status: Map<String, String> = EMPTY_MAP
) : JceStruct {
}
private val requestPacketRequestId: AtomicInt = atomic(1921334513)
internal fun nextRequestPacketRequestId(): Int = requestPacketRequestId.getAndAdd(2)
) : JceStruct
@Serializable
internal class RequestDataVersion3(

View File

@ -18,7 +18,7 @@ internal class MsgSvc : ProtoBuf {
@SerialId(1) val result: Int = 0,
@SerialId(2) val errmsg: String = "",
@SerialId(3) val syncCookie: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(4) val syncFlag: Int /* enum */ = 0,
@SerialId(4) val syncFlag: SyncFlag,
@SerialId(5) val uinPairMsgs: List<MsgComm.UinPairMsg>? = null,
@SerialId(6) val bindUin: Long = 0L,
@SerialId(7) val msgRspType: Int = 0,
@ -147,9 +147,15 @@ internal class MsgSvc : ProtoBuf {
@SerialId(2) val groupWithDraw: List<PbGroupMsgWithDrawReq>? = null
) : ProtoBuf
internal enum class SyncFlag {
START,
CONTINUE,
STOP
}
@Serializable
internal class PbGetMsgReq(
@SerialId(1) val syncFlag: Int /* enum */ = 0,
@SerialId(1) val syncFlag: SyncFlag,
@SerialId(2) val syncCookie: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(3) val rambleFlag: Int = 1,
@SerialId(4) val latestRambleNumber: Int = 20,

View File

@ -6,11 +6,13 @@ import net.mamoe.mirai.qqandroid.io.ProtoBuf
@Serializable
class SyncCookie(
@SerialId(2) val time: Long,
@SerialId(3) val unknown1: Long = 2994099792,
@SerialId(4) val unknown2: Long = 3497826378,
@SerialId(5) val const1: Long = 1680172298,
@SerialId(6) val const2: Long = 2424173273,
@SerialId(7) val unknown3: Long = 0,
@SerialId(8) val unknown4: Long = 0
@SerialId(1) val time1: Long? = null, // 1580277992
@SerialId(2) val time: Long, // 1580277992
@SerialId(3) val unknown1: Long = 678328038,// 678328038
@SerialId(4) val unknown2: Long = 1687142153, // 1687142153
@SerialId(5) val const1: Long = 1458467940, // 1458467940
@SerialId(11) val const2: Long = 2683038258, // 2683038258
@SerialId(12) val unknown3: Long = 0x1d,
@SerialId(13) val lastSyncTime: Long? = null,
@SerialId(14) val unknown4: Long = 0
) : ProtoBuf

View File

@ -24,9 +24,11 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
import net.mamoe.mirai.qqandroid.utils.toMessageChain
import net.mamoe.mirai.qqandroid.utils.toRichTextElems
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.cryptor.contentToString
import net.mamoe.mirai.utils.currentTimeSeconds
import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.toUHexString
import kotlin.math.absoluteValue
import kotlin.random.Random
@ -43,7 +45,7 @@ internal class MessageSvc {
override suspend fun QQAndroidBot.handle(packet: RequestPushNotify) {
network.run {
PbGetMsg(client, packet.stMsgInfo?.uMsgTime ?: 0).sendAndExpect<MultiPacket<FriendMessage>>()
PbGetMsg(client, MsgSvc.SyncFlag.START, packet.stMsgInfo?.uMsgTime ?: 0).sendAndExpect<MultiPacket<FriendMessage>>()
}
}
@ -53,17 +55,20 @@ internal class MessageSvc {
/**
* 获取好友消息和消息记录
*/
internal object PbGetMsg : PacketFactory<MultiPacket<FriendMessage>>("MessageSvc.PbGetMsg") {
@UseExperimental(MiraiInternalAPI::class)
internal object PbGetMsg : PacketFactory<PbGetMsg.Response>("MessageSvc.PbGetMsg") {
val EXTRA_DATA =
"08 00 12 33 6D 6F 64 65 6C 3A 78 69 61 6F 6D 69 20 36 3B 6F 73 3A 32 32 3B 76 65 72 73 69 6F 6E 3A 76 32 6D 61 6E 3A 78 69 61 6F 6D 69 73 79 73 3A 4C 4D 59 34 38 5A 18 E4 E1 A4 FF FE 2D 20 E9 E1 A4 FF FE 2D 28 A8 E1 A4 FF FE 2D 30 99 E1 A4 FF FE 2D".hexToBytes()
operator fun invoke(
client: QQAndroidClient,
syncFlag: MsgSvc.SyncFlag = MsgSvc.SyncFlag.START,
msgTime: Long //PbPushMsg.msg.msgHead.msgTime
): OutgoingPacket = buildOutgoingUniPacket(
client//,
// extraData = EXTRA_DATA.toReadPacket()
) {
println("syncCookie=${client.c2cMessageSync.syncCookie?.toUHexString()}")
writeProtoBuf(
MsgSvc.PbGetMsgReq.serializer(),
MsgSvc.PbGetMsgReq(
@ -74,10 +79,10 @@ internal class MessageSvc {
otherRambleNumber = 3,
onlineSyncFlag = 1,
whisperSessionId = 0,
syncFlag = syncFlag,
// serverBuf = from.serverBuf ?: EMPTY_BYTE_ARRAY,
syncCookie = client.c2cMessageSync.syncCookie
?: SyncCookie(msgTime).toByteArray(SyncCookie.serializer()).also { client.c2cMessageSync.syncCookie = it },
syncFlag = 1
?: SyncCookie(time = msgTime).toByteArray(SyncCookie.serializer())//.also { client.c2cMessageSync.syncCookie = it },
// syncFlag = client.c2cMessageSync.syncFlag,
//msgCtrlBuf = client.c2cMessageSync.msgCtrlBuf,
//pubaccountCookie = client.c2cMessageSync.pubAccountCookie
@ -85,25 +90,40 @@ internal class MessageSvc {
)
}
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): MultiPacket<FriendMessage> {
@UseExperimental(MiraiInternalAPI::class)
internal class GetMsgSuccess(delegate: MutableList<FriendMessage>) : Response(MsgSvc.SyncFlag.STOP, delegate)
/**
* 不要直接 expect 这个 class. 它可能
*/
@MiraiInternalAPI
open class Response(internal val syncFlagFromServer: MsgSvc.SyncFlag, delegate: MutableList<FriendMessage>) : MultiPacket<FriendMessage>(delegate) {
override fun toString(): String {
return "MessageSvc.PbGetMsg.Response($syncFlagFromServer=$syncFlagFromServer, messages=List(size=${this.size}))"
}
}
@UseExperimental(MiraiInternalAPI::class)
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
// 00 00 01 0F 08 00 12 00 1A 34 08 FF C1 C4 F1 05 10 FF C1 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 8A CA 91 D1 0C 48 9B A5 BD 9B 0A 58 DE 9D 99 F8 08 60 1D 68 FF C1 C4 F1 05 70 00 20 02 2A 9D 01 08 F3 C1 C4 F1 05 10 A2 FF 8C F0 03 18 01 22 8A 01 0A 2A 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 A6 01 20 0B 28 AE F9 01 30 F4 C1 C4 F1 05 38 A7 E3 D8 D4 84 80 80 80 01 B8 01 CD B5 01 12 08 08 01 10 00 18 00 20 00 1A 52 0A 50 0A 27 08 00 10 F4 C1 C4 F1 05 18 A7 E3 D8 D4 04 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 08 0A 06 0A 04 4E 4D 53 4C 12 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 12 04 4A 02 08 00 30 01 2A 15 08 97 A2 C1 F1 05 10 95 A6 F5 E5 0C 18 01 30 01 40 01 48 81 01 2A 10 08 D3 F7 B5 F1 05 10 DD F1 92 B7 07 18 01 30 01 38 00 42 00 48 00
discardExact(4)
val resp = readProtoBuf(MsgSvc.PbGetMsgResp.serializer())
if (resp.result != 0) {
return MultiPacket(emptyList())
println("!!! Result=${resp.result} !!!: " + resp.contentToString())
return GetMsgSuccess(mutableListOf())
}
bot.client.c2cMessageSync.syncCookie = resp.syncCookie
bot.client.c2cMessageSync.pubAccountCookie = resp.pubAccountCookie
bot.client.c2cMessageSync.syncFlag = resp.syncFlag
bot.client.c2cMessageSync.msgCtrlBuf = resp.msgCtrlBuf
println(resp.contentToString())
if (resp.uinPairMsgs == null) {
return MultiPacket(emptyList())
return GetMsgSuccess(mutableListOf())
}
return MultiPacket(resp.uinPairMsgs.asSequence().flatMap { it.msg.asSequence() }.mapNotNull {
val messages = resp.uinPairMsgs.asSequence().flatMap { it.msg.asSequence() }.mapNotNull {
when (it.msgHead.msgType) {
166 -> {
FriendMessage(
@ -115,10 +135,29 @@ internal class MessageSvc {
}
else -> null
}
}.toList())
}.toMutableList()
if (resp.syncFlag == MsgSvc.SyncFlag.STOP) {
return GetMsgSuccess(messages)
}
return Response(resp.syncFlag, messages)
}
override suspend fun QQAndroidBot.handle(packet: Response) {
when (packet.syncFlagFromServer) {
MsgSvc.SyncFlag.STOP,
MsgSvc.SyncFlag.START -> return
MsgSvc.SyncFlag.CONTINUE -> {
network.run {
PbGetMsg(client, MsgSvc.SyncFlag.CONTINUE, currentTimeSeconds)
}
return
}
}
}
}
/**
* 被挤下线
*/
@ -165,7 +204,7 @@ internal class MessageSvc {
msgSeq = client.atomicNextMessageSequenceId(),
msgRand = Random.nextInt().absoluteValue,
syncCookie = client.c2cMessageSync.syncCookie?.takeIf { it.isNotEmpty() }
?: SyncCookie(currentTimeSeconds).toByteArray(SyncCookie.serializer())
?: SyncCookie(time = currentTimeSeconds).toByteArray(SyncCookie.serializer())
// msgVia = 1
)
)
@ -192,9 +231,10 @@ internal class MessageSvc {
elems = message.toRichTextElems()
)
),
msgSeq = client.atomicNextMessageSequenceId(),
msgRand = 123,
syncCookie = client.c2cMessageSync.syncCookie?.takeIf { it.isNotEmpty() } ?: byteArrayOf()
msgSeq = client.atomicNextMessageSequenceId()
// msgRand = 123
//syncCookie = client.c2cMessageSync.syncCookie?.takeIf { it.isNotEmpty() } ?:
//SyncCookie(currentTimeSeconds, Random.nextLong().absoluteValue, Random.nextLong().absoluteValue).toByteArray(SyncCookie.serializer())
// msgVia = 1
)
)

View File

@ -11,21 +11,12 @@ import net.mamoe.mirai.qqandroid.io.serialization.toByteArray
import net.mamoe.mirai.qqandroid.io.serialization.writeJceStruct
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.*
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.FriendInfo
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.GetFriendListReq
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.GetFriendListResp
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.GetTroopListReqV2Simplify
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Vec0xd50
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
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.buildOutgoingUniPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList.GetFriendGroupList.decode
import net.mamoe.mirai.utils.cryptor.contentToString
import net.mamoe.mirai.utils.io.discardExact
import net.mamoe.mirai.utils.io.readRemainingBytes
import net.mamoe.mirai.utils.io.toUHexString
internal class FriendList {
@ -48,6 +39,7 @@ internal class FriendList {
sFuncName = "GetTroopMemberListReq",
sServantName = "mqq.IMService.FriendListServiceServantObj",
iVersion = 3,
iRequestId = client.nextRequestPacketRequestId(),
sBuffer = jceRequestSBuffer(
"GTML",
GetTroopMemberListReq.serializer(),

View File

@ -59,6 +59,7 @@ internal class StatSvc {
RequestPacket(
sServantName = "PushService",
sFuncName = "SvcReqRegister",
iRequestId = 0,
sBuffer = jceRequestSBuffer(
"SvcReqRegister",
SvcReqRegister.serializer(),

View File

@ -276,9 +276,6 @@ fun ByteReadPacket.decodeUni() {
//return
readBytes(readInt() - 4).debugPrint("head").toReadPacket().apply {
val commandName = readString(readInt() - 4).also { PacketLogger.warning("commandName=$it") }
if(commandName.contains("GetTroopList")){
println("!\n".repeat(100))
}
println(commandName)
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

@ -219,9 +219,6 @@ private fun parseSsoFrame(flag3: Int, input: ByteReadPacket): KnownPacketFactori
commandName = readString(readInt() - 4)
DebugLogger.warning("commandName=$commandName")
if(commandName.contains("GetTroopList")){
println("!\n".repeat(100))
}
val unknown = readBytes(readInt() - 4)
//if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: ${unknown.toUHexString()}")

View File

@ -8,7 +8,7 @@ interface Packet
/**
* PacketFactory 可以一次解析多个包出来. 它们将会被分别广播.
*/
class MultiPacket<P : Packet>(delegate: List<P>) : List<P> by delegate, Packet {
open class MultiPacket<P : Packet>(internal val delegate: MutableList<P>) : List<P> by delegate, Packet {
override fun toString(): String {
return "MultiPacket<${this.firstOrNull()?.let { it::class.simpleName }?: "?"}>"
}