Commit 5e56144c authored by Him188's avatar Him188

Support for approving friend add request

parent 6cd7fb24
...@@ -245,7 +245,7 @@ suspend fun ContactSystem.addFriend(id: UInt, lazyMessage: () -> String = { "" } ...@@ -245,7 +245,7 @@ suspend fun ContactSystem.addFriend(id: UInt, lazyMessage: () -> String = { "" }
is CanAddFriendResponse.ReadyToAdd, is CanAddFriendResponse.ReadyToAdd,
is CanAddFriendResponse.RequireVerification -> { is CanAddFriendResponse.RequireVerification -> {
val key = RequestFriendAdditionKeyPacket(bot.qqAccount, id, sessionKey).sendAndExpect<RequestFriendAdditionKeyPacket.Response>().key val key = RequestFriendAdditionKeyPacket(bot.qqAccount, id, sessionKey).sendAndExpect<RequestFriendAdditionKeyPacket.Response>().key
AddFriendPacket(bot.qqAccount, id, sessionKey, lazyMessage(), lazyRemark(), key).sendAndExpect<AddFriendPacket.Response>() AddFriendPacket.RequestAdd(bot.qqAccount, id, sessionKey, lazyMessage(), lazyRemark(), key).sendAndExpect<AddFriendPacket.Response>()
return AddFriendResult.WAITING_FOR_APPROVE return AddFriendResult.WAITING_FOR_APPROVE
} }
//这个做的是需要验证消息的情况, 不确定 ReadyToAdd 的是啥 //这个做的是需要验证消息的情况, 不确定 ReadyToAdd 的是啥
......
...@@ -11,6 +11,7 @@ internal fun IoBuffer.parseMessageFace(): Face { ...@@ -11,6 +11,7 @@ internal fun IoBuffer.parseMessageFace(): Face {
//00 01 0C 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 4D //00 01 0C 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 4D
discardExact(1) discardExact(1)
// FIXME: 2019/11/20 EMOJI 表情会解析失败
val id1 = FaceId(readLVNumber().toInt().toUByte())//可能这个是id, 也可能下面那个 val id1 = FaceId(readLVNumber().toInt().toUByte())//可能这个是id, 也可能下面那个
discardExact(readByte().toLong()) // -1 discardExact(readByte().toLong()) // -1
readLVNumber()//某id? readLVNumber()//某id?
......
...@@ -7,7 +7,6 @@ import kotlinx.serialization.SerializationStrategy ...@@ -7,7 +7,6 @@ import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.protobuf.ProtoBuf import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.TIMProtocol import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.utils.io.debugPrint
import net.mamoe.mirai.utils.io.encryptAndWrite import net.mamoe.mirai.utils.io.encryptAndWrite
import net.mamoe.mirai.utils.io.hexToBytes import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.writeQQ import net.mamoe.mirai.utils.io.writeQQ
...@@ -141,7 +140,7 @@ fun <T> PacketFactory<*, *>.buildSessionProtoPacket( ...@@ -141,7 +140,7 @@ fun <T> PacketFactory<*, *>.buildSessionProtoPacket(
writeInt(head.size) writeInt(head.size)
writeInt(proto.size) writeInt(proto.size)
writeFully(head) writeFully(head)
writeFully(proto.debugPrint("proto data")) writeFully(proto)
} }
is String -> buildSessionProtoPacket(bot, sessionKey, name, id, sequenceId, headerSizeHint, version, head.hexToBytes(), serializer, protoObj) is String -> buildSessionProtoPacket(bot, sessionKey, name, id, sequenceId, headerSizeHint, version, head.hexToBytes(), serializer, protoObj)
} }
......
...@@ -4,10 +4,17 @@ package net.mamoe.mirai.network.protocol.tim.packet ...@@ -4,10 +4,17 @@ package net.mamoe.mirai.network.protocol.tim.packet
import kotlinx.atomicfu.atomic import kotlinx.atomicfu.atomic
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import kotlinx.io.core.readBytes
import kotlinx.io.pool.useInstance import kotlinx.io.pool.useInstance
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.utils.io.ByteArrayPool import net.mamoe.mirai.utils.io.ByteArrayPool
import net.mamoe.mirai.utils.io.debugPrint
import net.mamoe.mirai.utils.io.read
import net.mamoe.mirai.utils.io.toUHexString import net.mamoe.mirai.utils.io.toUHexString
import net.mamoe.mirai.utils.readProtoMap
object PacketFactoryList : MutableList<PacketFactory<*, *>> by mutableListOf() object PacketFactoryList : MutableList<PacketFactory<*, *>> by mutableListOf()
...@@ -43,6 +50,25 @@ abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(val d ...@@ -43,6 +50,25 @@ abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(val d
*/ */
abstract suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): TPacket abstract suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): TPacket
@Suppress("DEPRECATION")
fun <T> ByteReadPacket.decodeProtoPacket(deserializer: DeserializationStrategy<T>, debuggingTag: String? = null): T {
val headLength = readInt()
val protoLength = readInt()
if (debuggingTag != null) {
readBytes(headLength).debugPrint("$debuggingTag head")
} else {
discardExact(headLength)
}
val bytes = readBytes(protoLength)
// println(ByteReadPacket(bytes).readProtoMap())
if (debuggingTag != null) {
bytes.read { readProtoMap() }.toString().debugPrint("$debuggingTag proto")
}
return ProtoBuf.load(deserializer, bytes)
}
companion object { companion object {
private val sequenceIdInternal = atomic(1) private val sequenceIdInternal = atomic(1)
......
...@@ -81,6 +81,10 @@ enum class KnownPacketId(override inline val value: UShort, override inline val ...@@ -81,6 +81,10 @@ enum class KnownPacketId(override inline val value: UShort, override inline val
inline REQUEST_PROFILE_DETAILS(0x003Cu, RequestProfileDetailsPacket), inline REQUEST_PROFILE_DETAILS(0x003Cu, RequestProfileDetailsPacket),
inline QUERY_PREVIOUS_NAME(0x01BCu, QueryPreviousNamePacket), inline QUERY_PREVIOUS_NAME(0x01BCu, QueryPreviousNamePacket),
// 031F 查询 "新朋友" 记录
// @Suppress("DEPRECATION") // @Suppress("DEPRECATION")
// inline SUBMIT_IMAGE_FILE_NAME(0x01BDu, SubmitImageFilenamePacket), // inline SUBMIT_IMAGE_FILE_NAME(0x01BDu, SubmitImageFilenamePacket),
......
...@@ -5,6 +5,7 @@ package net.mamoe.mirai.network.protocol.tim.packet.action ...@@ -5,6 +5,7 @@ package net.mamoe.mirai.network.protocol.tim.packet.action
import kotlinx.io.core.* import kotlinx.io.core.*
import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.* import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.network.protocol.tim.packet.event.EventPacket import net.mamoe.mirai.network.protocol.tim.packet.event.EventPacket
import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.*
...@@ -40,13 +41,17 @@ object QueryPreviousNamePacket : SessionPacketFactory<PreviousNameList>() { ...@@ -40,13 +41,17 @@ object QueryPreviousNamePacket : SessionPacketFactory<PreviousNameList>() {
// [00 00 00 10] 68 69 6D 31 38 38 E7 9A 84 E5 B0 8F 64 69 63 6B // [00 00 00 10] 68 69 6D 31 38 38 E7 9A 84 E5 B0 8F 64 69 63 6B
// [00 00 00 0F] E4 B8 B6 E6 9A 97 E8 A3 94 E5 89 91 E9 AD 94 // [00 00 00 0F] E4 B8 B6 E6 9A 97 E8 A3 94 E5 89 91 E9 AD 94
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): PreviousNameList = override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): PreviousNameList {
PreviousNameList(ArrayList<String>(readUInt().toInt()).apply { // 00 00 00 01 00 00 00 0F E8 87 AA E5 8A A8 E9 A9 BE E9 A9 B6 31 2E 33
repeat(size) {
val count = readUInt().toInt()
return PreviousNameList(ArrayList<String>(count).apply {
repeat(count) {
discardExact(2) discardExact(2)
add(readUShortLVString()) add(readUShortLVString())
} }
}) })
}
} }
class PreviousNameList( class PreviousNameList(
...@@ -192,9 +197,9 @@ object RequestFriendAdditionKeyPacket : SessionPacketFactory<RequestFriendAdditi ...@@ -192,9 +197,9 @@ object RequestFriendAdditionKeyPacket : SessionPacketFactory<RequestFriendAdditi
* 请求添加好友 * 请求添加好友
*/ */
@AnnotatedId(KnownPacketId.ADD_FRIEND) @AnnotatedId(KnownPacketId.ADD_FRIEND)
@PacketVersion(date = "2019.11.11", timVersion = "2.3.2 (21173)")
object AddFriendPacket : SessionPacketFactory<AddFriendPacket.Response>() { object AddFriendPacket : SessionPacketFactory<AddFriendPacket.Response>() {
operator fun invoke( @PacketVersion(date = "2019.11.11", timVersion = "2.3.2 (21173)")
fun RequestAdd(
bot: UInt, bot: UInt,
qq: UInt, qq: UInt,
sessionKey: SessionKey, sessionKey: SessionKey,
...@@ -243,6 +248,53 @@ object AddFriendPacket : SessionPacketFactory<AddFriendPacket.Response>() { ...@@ -243,6 +248,53 @@ object AddFriendPacket : SessionPacketFactory<AddFriendPacket.Response>() {
// write // write
} }
// 03 76 E4 B8 DD
// 00 00 09 //分组
// 00 29 //有备注
// 00 09 00 02 00 00 00 00
// [00 18] E8 87 AA E5 8A A8 E9 A9 BE E9 A9 B6 31 2E 33 E5 93 88 E5 93 88 E5 93 88
// [00 05] 00 00 00 00 01
// 03 76 E4 B8 DD
// 00 00 09 00 11 00 09 00 02 00 00 00 00 //没有备注, 选择分组和上面那个一样
// 00 00 00 05 00 00 00 00 01
// 03 76 E4 B8 DD
// 00 00 00
// 00 11 //没有备注
// 00 09 00 02 00 00 00 00
// 00 00 00 05 00 00 00 00 01
@PacketVersion(date = "2019.11.20", timVersion = "2.3.2 (21173)")
fun Approve(
bot: UInt,
sessionKey: SessionKey,
/**
* 好友列表分组的组的 ID. "我的好友" 为 0
*/
friendListId: Short,
qq: UInt,
/**
* 备注. 不设置则需要为 `null` TODO 需要确认是否还需发送一个设置备注包. 因为测试时若有备注则会多发一个包并且包里面有所设置的备注
*/
remark: String?
) = buildSessionPacket(bot, sessionKey, version = TIMProtocol.version0x02) {
writeByte(0x03)
writeQQ(qq)
writeZero(1)
writeUShort(friendListId.toUShort())
writeZero(1)
when (remark) {
null -> writeUByte(0x11u)
else -> writeUByte(0x29u)
}
writeHex("00 09 00 02 00 00 00 00")
when (remark) {
null -> writeZero(2)
else -> writeShortLVString(remark)
}
writeHex("00 05 00 00 00 00 01")
}
object Response : Packet { object Response : Packet {
override fun toString(): String = "AddFriendPacket.Response" override fun toString(): String = "AddFriendPacket.Response"
} }
......
...@@ -33,9 +33,7 @@ object RequestAccountInfoPacket : SessionPacketFactory<RequestAccountInfoPacket. ...@@ -33,9 +33,7 @@ object RequestAccountInfoPacket : SessionPacketFactory<RequestAccountInfoPacket.
@NoLog @NoLog
object Response : Packet { object Response : Packet {
//等级 override fun toString(): String = "RequestAccountInfoPacket.Response"
//升级剩余活跃天数
//ignored
} }
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): Response = Response override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): Response = Response
......
...@@ -4,11 +4,8 @@ package net.mamoe.mirai.network.protocol.tim.packet.action ...@@ -4,11 +4,8 @@ package net.mamoe.mirai.network.protocol.tim.packet.action
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import kotlinx.io.core.readBytes
import kotlinx.serialization.SerialId import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.GroupId import net.mamoe.mirai.contact.GroupId
import net.mamoe.mirai.contact.GroupInternalId import net.mamoe.mirai.contact.GroupInternalId
...@@ -23,7 +20,6 @@ import net.mamoe.mirai.qqAccount ...@@ -23,7 +20,6 @@ import net.mamoe.mirai.qqAccount
import net.mamoe.mirai.utils.ExternalImage import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.Http import net.mamoe.mirai.utils.Http
import net.mamoe.mirai.utils.assertUnreachable import net.mamoe.mirai.utils.assertUnreachable
import net.mamoe.mirai.utils.io.debugPrintln
import net.mamoe.mirai.utils.io.toUHexString import net.mamoe.mirai.utils.io.toUHexString
import kotlin.coroutines.coroutineContext import kotlin.coroutines.coroutineContext
...@@ -85,7 +81,7 @@ class ImageDownloadInfo( ...@@ -85,7 +81,7 @@ class ImageDownloadInfo(
val thumbnail: String get() = host + ":" + port.first() + _thumbnail!! val thumbnail: String get() = host + ":" + port.first() + _thumbnail!!
override val original: String get() = host + ":" + port.first() + _original!! override val original: String get() = host + ":" + port.first() + _original!!
val compressed: String get() = host + ":" + port.first() + _compressed!! val compressed: String get() = host + ":" + port.first() + _compressed!!
override fun toString(): String = "ImageDownloadInfo(${_original?.let { original } ?: errorMessage ?: "unknown"}" override fun toString(): String = "ImageDownloadInfo(${_original?.let { original } ?: errorMessage ?: "unknown"})"
} }
fun ImageDownloadInfo.requireSuccess(): ImageDownloadInfo { fun ImageDownloadInfo.requireSuccess(): ImageDownloadInfo {
...@@ -224,11 +220,6 @@ object GroupImagePacket : SessionPacketFactory<GroupImageResponse>() { ...@@ -224,11 +220,6 @@ object GroupImagePacket : SessionPacketFactory<GroupImageResponse>() {
} }
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): GroupImageResponse { override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): GroupImageResponse {
val headLength = readInt()
val protoLength = readInt()
discardExact(headLength)
val bytes = readBytes(protoLength)
// println(ByteReadPacket(bytes).readProtoMap())
@Serializable @Serializable
data class GroupImageResponseProto( data class GroupImageResponseProto(
...@@ -236,8 +227,7 @@ object GroupImagePacket : SessionPacketFactory<GroupImageResponse>() { ...@@ -236,8 +227,7 @@ object GroupImagePacket : SessionPacketFactory<GroupImageResponse>() {
@SerialId(4) val imageDownloadInfo: ImageDownloadInfo? = null @SerialId(4) val imageDownloadInfo: ImageDownloadInfo? = null
) )
debugPrintln("收到返回=" + bytes.toUHexString()) val proto = decodeProtoPacket(GroupImageResponseProto.serializer())
val proto = ProtoBuf.load(GroupImageResponseProto.serializer(), bytes)
return when { return when {
proto.imageUploadInfoPacket != null -> proto.imageUploadInfoPacket proto.imageUploadInfoPacket != null -> proto.imageUploadInfoPacket
proto.imageDownloadInfo != null -> proto.imageDownloadInfo proto.imageDownloadInfo != null -> proto.imageDownloadInfo
......
...@@ -94,6 +94,7 @@ abstract class KnownEventParserAndHandler<TPacket : Packet>(override val id: USh ...@@ -94,6 +94,7 @@ abstract class KnownEventParserAndHandler<TPacket : Packet>(override val id: USh
GroupFileUploadEventFactory, GroupFileUploadEventFactory,
GroupMemberPermissionChangedEventFactory, GroupMemberPermissionChangedEventFactory,
GroupMessageEventParserAndHandler, GroupMessageEventParserAndHandler,
FriendMessageEventParserAndHandler FriendMessageEventParserAndHandler,
FriendAddRequestEventPacket
) )
} }
\ No newline at end of file
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import kotlinx.io.core.readUInt
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.network.protocol.tim.packet.PacketVersion
import net.mamoe.mirai.network.protocol.tim.packet.action.AddFriendPacket
import net.mamoe.mirai.network.qqAccount
import net.mamoe.mirai.utils.io.readUShortLVString
import net.mamoe.mirai.withSession
import kotlin.jvm.JvmOverloads
/**
* 陌生人请求添加机器人账号为好友
*/
data class ReceiveFriendAddRequestEvent(
val qq: QQ,
/**
* 验证消息
*/
val message: String
) : EventPacket {
/**
* 同意这个请求
*
* @param remark 备注名, 不设置则需为 `null`
*/
@JvmOverloads
suspend fun approve(remark: String? = null): Unit = qq.bot.withSession {
AddFriendPacket.Approve(qqAccount, sessionKey, 0, qq.id, remark).sendAndExpect<AddFriendPacket.Response>()
}
}
@PacketVersion(date = "2019.11.20", timVersion = "2.3.2 (21173)")
object FriendAddRequestEventPacket : KnownEventParserAndHandler<ReceiveFriendAddRequestEvent>(0x02DFu) {
override suspend fun ByteReadPacket.parse(bot: Bot, identity: EventPacketIdentity): ReceiveFriendAddRequestEvent = bot.withSession {
// 00 00 00 08 00 0A 00 04 01 00
// 00 00 00 01
// 76 E4 B8 DD
// 00 00 00 01
// 2D 5C 53 A6
// 76 E4 B8 DD
// 02 00 00
// 00 0B BC 00 0B 5D D5 2E A3 04 7C 00 02 00 0C E6 88 91 E6 98 AF E6 A2 A8 E5 A4 B4 00 00
// 有验证消息
// 00 00 00 08 00 0A 00 04 01 00
// 00 00 00 01
// 76 E4 B8 DD
// 00 00 00 01
// 2D 5C 53 A6
// 76 E4 B8 DD
// 02 00 00
// 09 0B BD 00 02 5D D5 32 50 04 7C 00 02 00 00 00 00
// 无验证消息
// 00 00 00 08 00 0A 00 04 01 00
// 00 00 00 01
// 76 E4 B8 DD
// 00 00 00 01
// 2D 5C 53 A6
// 76 E4 B8 DD
// 02 00 00
// 09 0B BD 00 02 5D D5 33 0C 04 7C 00 02 00 0C E6 88 91 E6 98 AF E6 A2 A8 E5 A4 B4 00 00
// 有验证消息
/*
Mirai 20:35:23 : Packet received: UnknownEventPacket(id=02 10, identity=(761025446->1994701021))
= 00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 06 00 00 00 4C 08 02 1A 02 08 23 0A 4A 08 DD F1 92 B7 07 10 A6 A7 F1 EA 02 18 02 20 00 28 01 30 09 38 BD 17 40 02 48 8C E6 D4 EE 05 52 0C E6 88 91 E6 98 AF E6 A2 A8 E5 A4 B4 5A 0F E6 9D A5 E8 87 AA E8 AE A8 E8 AE BA E7 BB 84 62 00 6A 06 08 A5 CE 85 8A 06 72 00
Mirai 20:35:23 : Packet received: UnknownEventPacket(id=02 DF, identity=(761025446->1994701021))
= 00 00 00 08 00 0A 00 04 01 00 00 00 00 01 76 E4 B8 DD 00 00 00 01 2D 5C 53 A6 76 E4 B8 DD 02 00 00 09 0B BD 00 02 5D D5 33 0C 04 7C 00 02 00 0C E6 88 91 E6 98 AF E6 A2 A8 E5 A4 B4 00 00
Mirai 20:35:23 : Packet received: UnknownEventPacket(id=00 BB, identity=(761025446->1994701021))
= 00 00 00 08 00 0A 00 04 01 00 00 00 01 0C E6 88 91 E6 98 AF E6 A2 A8 E5 A4 B4 01 0B BD 00 02 00 00 00 5E 00 00 00 00 00 00 00 00 01 04 03 EF 00 06 08 A5 CE 85 8A 06 03 F0 00 02 08 01 03 F2 00 14 00 00 00 82 00 00 00 6D 2F AF 0B ED 20 02 EB 94 00 00 00 00 03 ED 00 28 08 01 12 18 68 69 6D 31 38 38 E7 9A 84 E8 80 81 E5 85 AC E7 9A 84 E6 9B BF E8 BA AB 18 00 22 06 E6 A2 A8 E5 A4 B4 28 01
*/
//Mirai 20:32:15 : Packet received: UnknownEventPacket(id=02 DF, identity=(761025446->1994701021))
// = 00 00 00 08 00 0A 00 04 01 00 00 00 00 01 76 E4 B8 DD 00 00 00 01 2D 5C 53 A6 76 E4 B8 DD 02 00 00 09 0B BD 00 02 5D D5 32 50 04 7C 00 02 00 00 00 00
//Mirai 20:32:15 : Packet received: UnknownEventPacket(id=02 10, identity=(761025446->1994701021))
// = 00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 06 00 00 00 40 08 02 1A 02 08 23 0A 3E 08 DD F1 92 B7 07 10 A6 A7 F1 EA 02 18 02 20 00 28 01 30 09 38 BD 17 40 02 48 D0 E4 D4 EE 05 52 00 5A 0F E6 9D A5 E8 87 AA E8 AE A8 E8 AE BA E7 BB 84 62 00 6A 06 08 A5 CE 85 8A 06 72 00
//Mirai 20:32:15 : Packet received: UnknownEventPacket(id=00 BB, identity=(761025446->1994701021))
// = 00 00 00 08 00 0A 00 04 01 00 00 00 01 00 01 0B BD 00 02 00 00 00 5E 00 00 00 00 00 00 00 00 01 04 03 EF 00 06 08 A5 CE 85 8A 06 03 F0 00 02 08 01 03 F2 00 14 00 00 00 82 00 00 00 6D 2F AF 0B ED 20 02 EB 94 00 00 00 00 03 ED 00 28 08 01 12 18 68 69 6D 31 38 38 E7 9A 84 E8 80 81 E5 85 AC E7 9A 84 E6 9B BF E8 BA AB 18 00 22 06 E6 A2 A8 E5 A4 B4 28 01
discardExact(10 + 4) // 00 00 00 08 00 0A 00 04 01 00 00 00 00 01
discardExact(4) // bot account uint
discardExact(4) // 00 00 00 01
val qq = readUInt().qq()
discardExact(4) // bot account uint
discardExact(3) // 02 00 00 恒定
discardExact(11) // 不确定. 以下为可能的值
// 00 00 01 00 01 5D D5 3C 57 00 A8 , 1994701021 添加 761025446
// 09 0B BD 00 02 5D D5 33 0C 04 7C 有验证, 761025446 添加 1994701021
// 09 0B BD 00 02 5D D5 32 50 04 7C 无验证, 761025446 添加 1994701021
// 00 0B BC 00 0B 5D D5 2E A3 04 7C 有验证
val message = readUShortLVString()
discardExact(2) // 00 01
return ReceiveFriendAddRequestEvent(qq, message)
}
}
/*
1994701021 向 761025446 发出好友请求, 761025446 收到 0x02DF 事件, body=
00 00 00 08 00 0A 00 04 01 00
00 00 00 01
2D 5C 53 A6
00 00 00 01
76 E4 B8 DD
2D 5C 53 A6
02 00 00
00 00 01 00 01 5D D5 3C 57 00 A8 00 02 00 00 00 00
*/
...@@ -72,7 +72,7 @@ enum class ProtoType(val value: Byte, private val typeName: String) { ...@@ -72,7 +72,7 @@ enum class ProtoType(val value: Byte, private val typeName: String) {
override fun toString(): String = this.typeName override fun toString(): String = this.typeName
companion object { companion object {
fun valueOf(value: Byte): ProtoType = values().firstOrNull { it.value == value } ?: error("Unknown ProtoId $value") fun valueOf(value: Byte): ProtoType = values().firstOrNull { it.value == value } ?: error("Unknown ProtoType $value")
} }
} }
...@@ -144,7 +144,8 @@ fun ByteReadPacket.readProtoMap(length: Long = this.remaining): ProtoMap { ...@@ -144,7 +144,8 @@ fun ByteReadPacket.readProtoMap(length: Long = this.remaining): ProtoMap {
require(this.remaining > expectingRemaining) { "Expecting to read $length bytes, but read ${expectingRemaining + length - this.remaining}" } require(this.remaining > expectingRemaining) { "Expecting to read $length bytes, but read ${expectingRemaining + length - this.remaining}" }
val id = ProtoFieldId(readUVarInt()) val id = ProtoFieldId(readUVarInt())
map[id] = when (id.type) {
fun readValue(): Any = when (id.type) {
ProtoType.VAR_INT -> UVarInt(readUVarInt()) ProtoType.VAR_INT -> UVarInt(readUVarInt())
ProtoType.BIT_32 -> readUInt() ProtoType.BIT_32 -> readUInt()
ProtoType.BIT_64 -> readULong() ProtoType.BIT_64 -> readULong()
...@@ -153,6 +154,19 @@ fun ByteReadPacket.readProtoMap(length: Long = this.remaining): ProtoMap { ...@@ -153,6 +154,19 @@ fun ByteReadPacket.readProtoMap(length: Long = this.remaining): ProtoMap {
ProtoType.START_GROUP -> Unit ProtoType.START_GROUP -> Unit
ProtoType.END_GROUP -> Unit ProtoType.END_GROUP -> Unit
} }
if (map.containsKey(id)) {
if (map[id] is MutableList<*>) {
@Suppress("UNCHECKED_CAST")
(map[id] as MutableList<Any>) += readValue()
} else {
map[id] = mutableListOf(map[id]!!)
@Suppress("UNCHECKED_CAST")
(map[id] as MutableList<Any>) += readValue()
}
} else {
map[id] = readValue()
}
} }
return map return map
} }
......
...@@ -12,6 +12,13 @@ internal object DebugLogger : MiraiLogger by DefaultLogger("Packet Debug") ...@@ -12,6 +12,13 @@ internal object DebugLogger : MiraiLogger by DefaultLogger("Packet Debug")
internal fun debugPrintln(any: Any?) = DebugLogger.debug(any) internal fun debugPrintln(any: Any?) = DebugLogger.debug(any)
@Deprecated("Low efficiency, only for debug purpose", ReplaceWith("this"))
internal fun String.debugPrint(name: String): String {
DebugLogger.debug("$name=$this")
return this
}
@Deprecated("Low efficiency, only for debug purpose", ReplaceWith("this"))
internal fun ByteArray.debugPrint(name: String): ByteArray { internal fun ByteArray.debugPrint(name: String): ByteArray {
DebugLogger.debug(name + "=" + this.toUHexString()) DebugLogger.debug(name + "=" + this.toUHexString())
return this return this
...@@ -67,7 +74,6 @@ internal fun BytePacketBuilder.debugColorizedPrintThis(name: String = "", compar ...@@ -67,7 +74,6 @@ internal fun BytePacketBuilder.debugColorizedPrintThis(name: String = "", compar
@Deprecated("Low efficiency, only for debug purpose", ReplaceWith(" ")) @Deprecated("Low efficiency, only for debug purpose", ReplaceWith(" "))
internal fun BytePacketBuilder.debugPrintThis(name: String = "") { internal fun BytePacketBuilder.debugPrintThis(name: String = "") {
val data = this.build().readBytes() val data = this.build().readBytes()
data.debugPrint(name)
this.writeFully(data) this.writeFully(data)
} }
......
...@@ -118,8 +118,8 @@ object PacketDebugger { ...@@ -118,8 +118,8 @@ object PacketDebugger {
* 7. 运行完 `mov eax,dword ptr ss:[ebp+10]` * 7. 运行完 `mov eax,dword ptr ss:[ebp+10]`
* 8. 查看内存, `eax` 到 `eax+10` 的 16 字节就是 `sessionKey` * 8. 查看内存, `eax` 到 `eax+10` 的 16 字节就是 `sessionKey`
*/ */
val sessionKey: SessionKey = SessionKey("FF 75 0E 37 92 1C F3 A2 44 77 8A 61 44 29 EA D8".hexToBytes()) val sessionKey: SessionKey = SessionKey("15 95 8D 22 F7 3B C6 6E FE 91 1B 1B 8F A2 9E 1C".hexToBytes())
const val qq: UInt = 1040400290u const val qq: UInt = 761025446u
val IgnoredPacketIdList: List<PacketId> = listOf( val IgnoredPacketIdList: List<PacketId> = listOf(
KnownPacketId.FRIEND_ONLINE_STATUS_CHANGE, KnownPacketId.FRIEND_ONLINE_STATUS_CHANGE,
......
...@@ -9,10 +9,12 @@ import kotlinx.serialization.protobuf.ProtoBuf ...@@ -9,10 +9,12 @@ import kotlinx.serialization.protobuf.ProtoBuf
import kotlinx.serialization.protobuf.ProtoNumberType import kotlinx.serialization.protobuf.ProtoNumberType
import kotlinx.serialization.protobuf.ProtoType import kotlinx.serialization.protobuf.ProtoType
import kotlinx.serialization.serializer import kotlinx.serialization.serializer
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.ProtoFieldId
import net.mamoe.mirai.utils.io.hexToBytes import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.read import net.mamoe.mirai.utils.io.read
import net.mamoe.mirai.utils.io.toUHexString import net.mamoe.mirai.utils.io.toUHexString
import net.mamoe.mirai.utils.readProtoMap
import kotlin.reflect.KClass import kotlin.reflect.KClass
@Serializable @Serializable
...@@ -58,17 +60,15 @@ suspend fun main() { ...@@ -58,17 +60,15 @@ suspend fun main() {
} }
suspend fun deserializeTest() { suspend fun deserializeTest() {
println(Http.getURL("http://gchat.qpic.cn/gchatpic_new/1994701021/1994701021-2868483628-39F76532E1AB5CA786D7A51389225385/0?vuin=1994701021&term=255&srvver=26933").remaining) //println(Http.getURL("http://gchat.qpic.cn/gchatpic_new/1994701021/1994701021-2868483628-39F76532E1AB5CA786D7A51389225385/0?vuin=1994701021&term=255&srvver=26933").remaining)
val bytes = val bytes =
""" """
08 01 10 00 1A 89 02 10 01 18 03 3A 4D 08 A6 A7 F1 EA 02 10 DD F1 92 B7 07 18 01 20 D3 81 D5 EE 05 2A 00 32 11 E6 9D A5 E8 87 AA 51 51 E5 8F B7 E6 9F A5 E6 89 BE 38 01 40 01 48 00 50 00 58 00 60 01 6A 00 70 00 78 00 80 01 03 A0 01 00 A8 01 00 B0 01 00 C0 01 01 E8 01 00 3A 4A 08 A6 A7 F1 EA 02 10 DD F1 92 B7 07 18 03 20 DC 80 D5 EE 05 2A 00 32 11 E6 9D A5 E8 87 AA 51 51 E5 8F B7 E6 9F A5 E6 89 BE 38 01 40 01 48 00 50 00 58 00 60 01 6A 00 70 00 78 00 80 01 00 A0 01 00 A8 01 00 B0 01 00 C0 01 00 3A 4A 08 A6 A7 F1 EA 02 10 DD F1 92 B7 07 18 03 20 D7 F8 D4 EE 05 2A 00 32 11 E6 9D A5 E8 87 AA 51 51 E5 8F B7 E6 9F A5 E6 89 BE 38 01 40 01 48 00 50 00 58 00 60 01 6A 00 70 00 78 00 80 01 00 A0 01 00 A8 01 00 B0 01 00 C0 01 00 40 D3 81 D5 EE 05 48 01 50 01 58 01 60 DD F1 92 B7 07 72 08 0A 06 08 DD F1 92 B7 07 78 00
10 02 22 4E 08 A0 89 F7 B6 03 10 A2 FF 8C F0 03 18 BB 92 94 BF 08 22 10 63 B1 86 6F 41 3E D9 78 CB CF 53 3E 92 28 5C 58 28 04 30 02 38 20 40 FF 01 48 00 50 01 5A 05 32 36 39 33 33 60 00 68 00 70 00 78 00 80 01 97 04 88 01 ED 03 90 01 04 A0 01 01
""".trimIndent().replace("\n", " ").replace("[", "").replace("]", "")
""".trimIndent().replace("\n", " ").replace("[", "").replace("]", "")
.hexToBytes() .hexToBytes()
/* /*
......
...@@ -17,6 +17,7 @@ import net.mamoe.mirai.message.getValue ...@@ -17,6 +17,7 @@ import net.mamoe.mirai.message.getValue
import net.mamoe.mirai.message.sendAsImageTo import net.mamoe.mirai.message.sendAsImageTo
import net.mamoe.mirai.network.protocol.tim.packet.event.FriendMessage import net.mamoe.mirai.network.protocol.tim.packet.event.FriendMessage
import net.mamoe.mirai.network.protocol.tim.packet.event.GroupMessage import net.mamoe.mirai.network.protocol.tim.packet.event.GroupMessage
import net.mamoe.mirai.network.protocol.tim.packet.event.ReceiveFriendAddRequestEvent
import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess
import java.io.File import java.io.File
import java.util.* import java.util.*
...@@ -54,6 +55,10 @@ suspend fun main() { ...@@ -54,6 +55,10 @@ suspend fun main() {
//bot.logger.verbose("收到了一个事件: ${it::class.simpleName}") //bot.logger.verbose("收到了一个事件: ${it::class.simpleName}")
} }
subscribeAlways<ReceiveFriendAddRequestEvent> {
it.approve()
}
bot.subscribeMessages { bot.subscribeMessages {
"你好" reply "你好!" "你好" reply "你好!"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment