mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 02:20:14 +08:00
Simplify packet structure
This commit is contained in:
parent
0f1328ef00
commit
b02a5a7922
@ -94,10 +94,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun awaitDisconnection() {
|
override suspend fun awaitDisconnection() {
|
||||||
while (true) {
|
supervisor.join()
|
||||||
delay(100)
|
|
||||||
// TODO: 2019/12/31
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose(cause: Throwable?) {
|
override fun dispose(cause: Throwable?) {
|
||||||
|
@ -22,11 +22,6 @@ internal class OutgoingPacket constructor(
|
|||||||
name: String?,
|
name: String?,
|
||||||
val packetId: PacketId,
|
val packetId: PacketId,
|
||||||
val sequenceId: Int,
|
val sequenceId: Int,
|
||||||
// TODO: 2020/1/6 这个 sequenceId 设计有问题.
|
|
||||||
// 02 03 包里面的那个应该并不是 sequenceId.
|
|
||||||
// 它应该是固定的 0x001.
|
|
||||||
// 应该在这里填入 SSO 的 sequenceId.
|
|
||||||
// 同时考虑修改名称. 这可能不应该叫做 SSO. 它在全程都有
|
|
||||||
val delegate: ByteReadPacket
|
val delegate: ByteReadPacket
|
||||||
) {
|
) {
|
||||||
val name: String by lazy {
|
val name: String by lazy {
|
||||||
@ -47,30 +42,40 @@ private val EMPTY_BYTE_ARRAY = ByteArray(0)
|
|||||||
* int extra data size + 4
|
* int extra data size + 4
|
||||||
* byte[] extra data
|
* byte[] extra data
|
||||||
* byte 0
|
* byte 0
|
||||||
* int [uinAccount].length + 4
|
* int uinAccount.length + 4
|
||||||
* byte[] uinAccount
|
* byte[] uinAccount
|
||||||
*
|
*
|
||||||
* byte[] body encrypted by 16 zero
|
* byte[] body encrypted by 16 zero
|
||||||
*/
|
*/
|
||||||
internal inline fun PacketFactory<*, *>.buildLoginOutgoingPacket(
|
internal inline fun PacketFactory<*, *>.buildLoginOutgoingPacket(
|
||||||
uinAccount: String,
|
client: QQAndroidClient,
|
||||||
|
subAppId: Long,
|
||||||
extraData: ByteArray = EMPTY_BYTE_ARRAY,
|
extraData: ByteArray = EMPTY_BYTE_ARRAY,
|
||||||
name: String? = null,
|
name: String? = null,
|
||||||
id: PacketId = this.id,
|
id: PacketId = this.id,
|
||||||
|
ssoExtraData: ByteReadPacket = BRP_STUB,
|
||||||
sequenceId: Int = PacketFactory.atomicNextSequenceId(),
|
sequenceId: Int = PacketFactory.atomicNextSequenceId(),
|
||||||
body: BytePacketBuilder.() -> Unit
|
body: BytePacketBuilder.(sequenceId: Int) -> Unit
|
||||||
): OutgoingPacket = OutgoingPacket(name, id, sequenceId, buildPacket {
|
): OutgoingPacket = OutgoingPacket(name, id, sequenceId, buildPacket {
|
||||||
writeIntLVPacket(lengthOffset = { it + 4 }) {
|
writeIntLVPacket(lengthOffset = { it + 4 }) {
|
||||||
writeInt(0x00_00_00_0A)
|
writeInt(0x00_00_00_0A)
|
||||||
writeByte(0x02)
|
writeByte(0x02)
|
||||||
writeInt(extraData.size + 4)
|
extraData.let {
|
||||||
writeFully(extraData)
|
writeInt(it.size + 4)
|
||||||
|
writeFully(it)
|
||||||
|
}
|
||||||
writeByte(0x00)
|
writeByte(0x00)
|
||||||
|
|
||||||
writeInt(uinAccount.length + 4)
|
client.account.id.toString().let {
|
||||||
writeStringUtf8(uinAccount)
|
writeInt(it.length + 4)
|
||||||
|
writeStringUtf8(it)
|
||||||
|
}
|
||||||
|
|
||||||
encryptAndWrite(KEY_16_ZEROS, body)
|
encryptAndWrite(KEY_16_ZEROS) {
|
||||||
|
writeLoginSsoPacket(client, subAppId, id, ssoExtraData, sequenceId) {
|
||||||
|
body(sequenceId)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -79,20 +84,38 @@ private val BRP_STUB = ByteReadPacket(EMPTY_BYTE_ARRAY)
|
|||||||
/**
|
/**
|
||||||
* The second outermost packet for login
|
* The second outermost packet for login
|
||||||
*
|
*
|
||||||
|
* int headRemaining.size+4
|
||||||
|
* int sequenceId
|
||||||
|
* int subAppId
|
||||||
|
* int subAppId
|
||||||
|
* hex "01 00 00 00 00 00 00 00 00 00 01 00" // unknown values
|
||||||
|
* int extraData.size+4
|
||||||
|
* byte[] extraData
|
||||||
|
* int commandName.length+4
|
||||||
|
* byte[] commandName
|
||||||
|
* int 4+4
|
||||||
|
* int 0x02B05B8B
|
||||||
|
* int imei.length+4
|
||||||
|
* byte[] imei
|
||||||
|
* int 0+4
|
||||||
|
* int ksid.length+4
|
||||||
|
* byte[] ksid
|
||||||
|
* int 0+4
|
||||||
*
|
*
|
||||||
|
* int bodyRemaining.size+4
|
||||||
|
* byte[] body()
|
||||||
*/
|
*/
|
||||||
@UseExperimental(MiraiInternalAPI::class)
|
@UseExperimental(MiraiInternalAPI::class)
|
||||||
internal inline fun BytePacketBuilder.writeLoginSsoPacket(
|
private inline fun BytePacketBuilder.writeLoginSsoPacket(
|
||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
subAppId: Long,
|
subAppId: Long,
|
||||||
packetId: PacketId,
|
packetId: PacketId,
|
||||||
extraData: ByteReadPacket = BRP_STUB,
|
extraData: ByteReadPacket = BRP_STUB,
|
||||||
body: BytePacketBuilder.(ssoSequenceId: Int) -> Unit
|
sequenceId: Int,
|
||||||
|
body: BytePacketBuilder.() -> Unit
|
||||||
) {
|
) {
|
||||||
val ssoSequenceId = client.nextSsoSequenceId()
|
|
||||||
// head
|
|
||||||
writeIntLVPacket(lengthOffset = { it + 4 }) {
|
writeIntLVPacket(lengthOffset = { it + 4 }) {
|
||||||
writeInt(ssoSequenceId)
|
writeInt(sequenceId)
|
||||||
writeInt(subAppId.toInt())
|
writeInt(subAppId.toInt())
|
||||||
writeInt(subAppId.toInt())
|
writeInt(subAppId.toInt())
|
||||||
writeHex("01 00 00 00 00 00 00 00 00 00 01 00")
|
writeHex("01 00 00 00 00 00 00 00 00 00 01 00")
|
||||||
@ -126,9 +149,7 @@ internal inline fun BytePacketBuilder.writeLoginSsoPacket(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// body
|
// body
|
||||||
writeIntLVPacket(lengthOffset = { it + 4 }) {
|
writeIntLVPacket(lengthOffset = { it + 4 }, builder = body)
|
||||||
body(ssoSequenceId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -245,7 +266,7 @@ internal interface EncryptMethodECDH : EncryptMethod {
|
|||||||
* byte 2 // head flag
|
* byte 2 // head flag
|
||||||
* short 27 + 2 + remaining.length
|
* short 27 + 2 + remaining.length
|
||||||
* ushort client.protocolVersion // const 8001
|
* ushort client.protocolVersion // const 8001
|
||||||
* ushort sequenceId
|
* ushort 0x0001
|
||||||
* uint client.account.id
|
* uint client.account.id
|
||||||
* byte 3 // const
|
* byte 3 // const
|
||||||
* ubyte encryptMethod.value // [EncryptMethod]
|
* ubyte encryptMethod.value // [EncryptMethod]
|
||||||
@ -257,7 +278,7 @@ internal interface EncryptMethodECDH : EncryptMethod {
|
|||||||
* byte 3 // tail
|
* byte 3 // tail
|
||||||
*/
|
*/
|
||||||
@UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
|
@UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
|
||||||
internal inline fun BytePacketBuilder.writeRequestPacket(
|
internal inline fun BytePacketBuilder.writeOicqRequestPacket(
|
||||||
client: QQAndroidClient,
|
client: QQAndroidClient,
|
||||||
encryptMethod: EncryptMethod,
|
encryptMethod: EncryptMethod,
|
||||||
packetId: PacketId,
|
packetId: PacketId,
|
||||||
@ -271,7 +292,7 @@ internal inline fun BytePacketBuilder.writeRequestPacket(
|
|||||||
writeByte(0x02) // head
|
writeByte(0x02) // head
|
||||||
writeShort((27 + 2 + body.remaining).toShort()) // orthodox algorithm
|
writeShort((27 + 2 + body.remaining).toShort()) // orthodox algorithm
|
||||||
writeShort(client.protocolVersion)
|
writeShort(client.protocolVersion)
|
||||||
writeShort(1)
|
writeShort(1) // const??
|
||||||
writeShort(packetId.commandId.toShort())
|
writeShort(packetId.commandId.toShort())
|
||||||
writeQQ(client.account.id)
|
writeQQ(client.account.id)
|
||||||
writeByte(3) // originally const
|
writeByte(3) // originally const
|
||||||
|
@ -21,17 +21,17 @@ class LoginPacketDecrypter(override val value: ByteArray) : DecrypterByteArray {
|
|||||||
|
|
||||||
internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, LoginPacketDecrypter>(LoginPacketDecrypter) {
|
internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, LoginPacketDecrypter>(LoginPacketDecrypter) {
|
||||||
init {
|
init {
|
||||||
this._id = PacketId(commandId = 0x0810, commandName = "wtlogin.login", subCommandId = 9)
|
this._id = PacketId(commandId = 0x0810, commandName = "wtlogin.login")
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun invoke(
|
object SubCommand9 {
|
||||||
client: QQAndroidClient
|
|
||||||
): OutgoingPacket = buildLoginOutgoingPacket(client.account.id.toString()) {
|
|
||||||
val appId = 16L
|
val appId = 16L
|
||||||
val subAppId = 537062845L
|
val subAppId = 537062845L
|
||||||
|
|
||||||
writeLoginSsoPacket(client, subAppId, id) { ssoSequenceId ->
|
operator fun invoke(
|
||||||
writeRequestPacket(client, EncryptMethodECDH135(client.ecdh), id) {
|
client: QQAndroidClient
|
||||||
|
): OutgoingPacket = buildLoginOutgoingPacket(client, 537062845L) { sequenceId ->
|
||||||
|
writeOicqRequestPacket(client, EncryptMethodECDH135(client.ecdh), id) {
|
||||||
writeShort(9) // subCommand
|
writeShort(9) // subCommand
|
||||||
writeShort(LoginType.PASSWORD.value.toShort())
|
writeShort(LoginType.PASSWORD.value.toShort())
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log
|
|||||||
|
|
||||||
// ignored t16a because array5 is null
|
// ignored t16a because array5 is null
|
||||||
|
|
||||||
t154(ssoSequenceId)
|
t154(sequenceId)
|
||||||
t141(client.device.simInfo, client.networkType, client.device.apn)
|
t141(client.device.simInfo, client.networkType, client.device.apn)
|
||||||
t8(2052)
|
t8(2052)
|
||||||
|
|
||||||
@ -129,8 +129,10 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log
|
|||||||
|
|
||||||
t187(client.device.macAddress)
|
t187(client.device.macAddress)
|
||||||
t188(client.device.androidId)
|
t188(client.device.androidId)
|
||||||
if (client.device.imsiMd5.isNotEmpty()) {
|
|
||||||
t194(client.device.imsiMd5)
|
val imsi = client.device.imsiMd5
|
||||||
|
if (imsi.isNotEmpty()) {
|
||||||
|
t194(imsi)
|
||||||
}
|
}
|
||||||
t191()
|
t191()
|
||||||
|
|
||||||
@ -158,32 +160,36 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log
|
|||||||
// ignored t318 because not logging in by QR
|
// ignored t318 because not logging in by QR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun ByteReadPacket.decode(bot: QQAndroidBot): LoginPacketResponse {
|
||||||
|
TODO("not implemented")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class LoginPacketResponse : Packet
|
class LoginPacketResponse : Packet
|
||||||
|
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): LoginPacketResponse {
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): LoginPacketResponse {
|
||||||
TODO("not implemented")
|
return when (val subCommand = readShort().toInt()) {
|
||||||
|
9 -> SubCommand9.run { decode(bot) }
|
||||||
|
else -> error("Unknown subCommand: $subCommand")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
internal fun PacketId(commandId: Int, commandName: String, subCommandId: Int) = object : PacketId {
|
internal fun PacketId(commandId: Int, commandName: String) = object : PacketId {
|
||||||
override val commandId: Int get() = commandId
|
override val commandId: Int get() = commandId
|
||||||
override val commandName: String get() = commandName
|
override val commandName: String get() = commandName
|
||||||
override val subCommandId: Int get() = subCommandId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface PacketId {
|
internal interface PacketId {
|
||||||
val commandId: Int // ushort actually
|
val commandId: Int // ushort actually
|
||||||
val commandName: String
|
val commandName: String
|
||||||
val subCommandId: Int // ushort actually
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal object NullPacketId : PacketId {
|
internal object NullPacketId : PacketId {
|
||||||
override val commandId: Int get() = error("uninitialized")
|
override val commandId: Int get() = error("uninitialized")
|
||||||
override val commandName: String get() = error("uninitialized")
|
override val commandName: String get() = error("uninitialized")
|
||||||
override val subCommandId: Int get() = error("uninitialized")
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user