1
0
mirror of https://github.com/mamoe/mirai.git synced 2025-03-25 06:50:09 +08:00

Daily QQA Update

This commit is contained in:
Him188 2020-01-17 22:35:24 +08:00
parent cc171a87b4
commit 04c54f2a83
21 changed files with 530 additions and 34 deletions
mirai-core-qqandroid/src
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io

View File

@ -84,5 +84,6 @@ actual class SystemDeviceInfo actual constructor(context: Context) : DeviceInfo(
override val incremental: ByteArray get() = Build.VERSION.INCREMENTAL.toByteArray()
override val release: ByteArray get() = Build.VERSION.RELEASE.toByteArray()
override val codename: ByteArray get() = Build.VERSION.CODENAME.toByteArray()
override val sdk: Int get() = Build.VERSION.SDK_INT
}
}

View File

@ -12,8 +12,11 @@ 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.LockFreeLinkedList
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.getValue
import net.mamoe.mirai.utils.io.*
import net.mamoe.mirai.utils.unsafeWeakRef
import kotlin.coroutines.CoroutineContext
@ -33,7 +36,10 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
println("Sending login")
LoginPacket.SubCommand9(bot.client).sendAndExpect<LoginPacket.LoginPacketResponse>()
println("SessionTicket=${bot.client.wLoginSigInfo.wtSessionTicket.data.toUHexString()}")
println("SessionTicketKey=${bot.client.wLoginSigInfo.d2Key.toUHexString()}")
println("SessionTicketKey=${bot.client.wLoginSigInfo.wtSessionTicketKey.toUHexString()}")
delay(2000)
SvcReqRegisterPacket(bot.client, RegPushReason.setOnlineStatus).sendAndExpect<SvcReqRegisterPacket.Response>()
}
internal fun launchPacketProcessor(rawInput: ByteReadPacket): Job = launch(CoroutineName("Incoming Packet handler")) {

View File

@ -5,6 +5,7 @@ import kotlinx.atomicfu.atomic
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.toByteArray
import net.mamoe.mirai.BotAccount
import net.mamoe.mirai.data.OnlineStatus
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.protocol.packet.Tlv
import net.mamoe.mirai.qqandroid.utils.Context
@ -15,6 +16,7 @@ import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.cryptor.ECDH
import net.mamoe.mirai.utils.cryptor.contentToString
import net.mamoe.mirai.utils.getValue
import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.read
import net.mamoe.mirai.utils.io.readUShortLVByteArray
@ -50,7 +52,9 @@ internal open class QQAndroidClient(
return "QQAndroidClient(account=$account, ecdh=$ecdh, device=$device, tgtgtKey=${tgtgtKey.contentToString()}, randomKey=${randomKey.contentToString()}, miscBitMap=$miscBitMap, mainSigMap=$mainSigMap, subSigMap=$subSigMap, openAppId=$openAppId, apkVersionName=${apkVersionName.contentToString()}, loginState=$loginState, appClientVersion=$appClientVersion, networkType=$networkType, apkSignatureMd5=${apkSignatureMd5.contentToString()}, protocolVersion=$protocolVersion, apkId=${apkId.contentToString()}, t150=${t150?.contentToString()}, rollbackSig=${rollbackSig?.contentToString()}, ipFromT149=${ipFromT149?.contentToString()}, timeDifference=$timeDifference, uin=$uin, t530=${t530?.contentToString()}, t528=${t528?.contentToString()}, ksid='$ksid', pwdFlag=$pwdFlag, loginExtraData=$loginExtraData, wFastLoginInfo=$wFastLoginInfo, reserveUinInfo=$reserveUinInfo, wLoginSigInfo=$wLoginSigInfo, tlv113=${tlv113?.contentToString()}, qrPushSig=${qrPushSig.contentToString()}, mainDisplayName='$mainDisplayName')"
}
val context by context.unsafeWeakRef()
var onlineStatus: OnlineStatus = OnlineStatus.ONLINE
val context: Context by context.unsafeWeakRef()
val bot: QQAndroidBot by bot.unsafeWeakRef()
var tgtgtKey: ByteArray = ByteArray(16) // generateTgtgtKey(device.guid)

View File

@ -2,10 +2,21 @@ package net.mamoe.mirai.qqandroid.network.io
import kotlinx.io.charsets.Charset
import kotlinx.io.core.*
import kotlinx.io.pool.useInstance
import net.mamoe.mirai.utils.io.ByteArrayPool
import net.mamoe.mirai.utils.io.readRemainingBytes
import kotlin.reflect.KClass
private val CharsetGBK = Charset.forName("GBK")
fun buildJcePacket(stringCharset: Charset = CharsetGBK, block: JceOutput.() -> Unit): ByteReadPacket {
return JceOutput(stringCharset).apply(block).build()
}
fun BytePacketBuilder.writeJcePacket(stringCharset: Charset = CharsetGBK, block: JceOutput.() -> Unit) {
return this.writePacket(buildJcePacket(stringCharset, block))
}
/**
*
* From: com.qq.taf.jce.JceOutputStream
@ -13,9 +24,11 @@ private val CharsetGBK = Charset.forName("GBK")
@Suppress("unused", "MemberVisibilityCanBePrivate")
@UseExperimental(ExperimentalIoApi::class)
class JceOutput(
private val stringCharset: Charset = CharsetGBK,
private val output: Output = BytePacketBuilder()
private val stringCharset: Charset = CharsetGBK
) {
private val output: BytePacketBuilder = BytePacketBuilder()
fun build(): ByteReadPacket = output.build()
fun close() = output.close()
fun flush() = output.flush()
@ -197,10 +210,36 @@ class JceOutput(
is FloatArray -> writeFully(v, tag)
is DoubleArray -> writeFully(v, tag)
is Array<*> -> writeFully(v, tag)
is String -> writeString(v, tag)
//
// is ByteReadPacket -> ByteArrayPool.useInstance {
// v.readAvailable(it)
// writeFully(it, tag)
// }
else -> error("unsupported type: ${v.getClassName()}")
}
}
fun write(v: Int, tag: Int) = writeInt(v, tag)
fun write(v: Byte, tag: Int) = writeByte(v, tag)
fun write(v: Short, tag: Int) = writeShort(v, tag)
fun write(v: Long, tag: Int) = writeLong(v, tag)
fun write(v: Float, tag: Int) = writeFloat(v, tag)
fun write(v: Double, tag: Int) = writeDouble(v, tag)
fun write(v: String, tag: Int) = writeString(v, tag)
fun write(v: Boolean, tag: Int) = writeBoolean(v, tag)
fun write(v: Collection<*>, tag: Int) = writeCollection(v, tag)
fun write(v: Map<*, *>, tag: Int) = writeMap(v, tag)
fun write(v: ByteArray, tag: Int) = writeFully(v, tag)
fun write(v: IntArray, tag: Int) = writeFully(v, tag)
fun write(v: BooleanArray, tag: Int) = writeFully(v, tag)
fun write(v: LongArray, tag: Int) = writeFully(v, tag)
fun write(v: ShortArray, tag: Int) = writeFully(v, tag)
fun write(v: Array<*>, tag: Int) = writeFully(v, tag)
fun write(v: FloatArray, tag: Int) = writeFully(v, tag)
fun write(v: DoubleArray, tag: Int) = writeFully(v, tag)
@PublishedApi
internal companion object {
const val BYTE: Int = 0

View File

@ -1,5 +1,7 @@
package net.mamoe.mirai.qqandroid.network.io
import kotlinx.io.core.BytePacketBuilder
abstract class JceStruct {
abstract fun writeTo(p0: JceOutput)
abstract fun writeTo(builder: JceOutput)
}

View File

@ -0,0 +1,32 @@
package net.mamoe.mirai.qqandroid.network.protocol.jce
import net.mamoe.mirai.qqandroid.network.io.JceOutput
import net.mamoe.mirai.qqandroid.network.io.JceStruct
private val EMPTY_MAP = mapOf<String, String>()
class RequestPacket(
val sBuffer: ByteArray,
val cPacketType: Byte = 0,
val iMessageType: Int = 0,
val iRequestId: Int = 0,
val iTimeout: Int = 3000,
val iVersion: Short = 3,
val context: Map<String, String> = EMPTY_MAP,
val sFuncName: String = "",
val sServantName: String = "",
val status: Map<String, String> = EMPTY_MAP
) : JceStruct() {
override fun writeTo(builder: JceOutput) {
builder.write(this.iVersion, 1)
builder.write(this.cPacketType, 2)
builder.write(this.iMessageType, 3)
builder.write(this.iRequestId, 4)
builder.write(this.sServantName, 5)
builder.write(this.sFuncName, 6)
builder.write(this.sBuffer, 7)
builder.write(this.iTimeout, 8)
builder.write(this.context, 9)
builder.write(this.status, 10)
}
}

View File

@ -0,0 +1,123 @@
package net.mamoe.mirai.qqandroid.network.protocol.jce
import net.mamoe.mirai.qqandroid.network.io.JceOutput
import net.mamoe.mirai.qqandroid.network.io.JceStruct
class SvcReqRegister(
val bIsOnline: Byte = 0,
val bIsSetStatus: Byte = 0,
val bIsShowOnline: Byte = 0,
val bKikPC: Byte = 0,
val bKikWeak: Byte = 0,
val bOnlinePush: Byte = 0,
val bOpenPush: Byte = 1,
val bRegType: Byte = 0,
val bSetMute: Byte = 0,
val bSlientPush: Byte = 0,
val bytes_0x769_reqbody: ByteArray? = null,
val cConnType: Byte = 0,
val cNetType: Byte = 0,
val iLargeSeq: Long = 0L,
val iLastWatchStartTime: Long = 0L,
val iLocaleID: Int = 2052,
val iOSVersion: Long = 0L,
val iStatus: Int = 11,
val lBid: Long = 0L,
val lCpId: Long = 0L,
val lUin: Long = 0L,
val sBuildVer: String? = "",
val sChannelNo: String? = "",
val sOther: String = "",
val strDevName: String? = "",
val strDevType: String? = "",
val strIOSIdfa: String? = "",
val strOSVer: String? = "",
val strVendorName: String? = "",
val strVendorOSName: String? = "",
val timeStamp: Long = 0L,
val uNewSSOIp: Long = 0L,
val uOldSSOIp: Long = 0L,
val vecDevParam: ByteArray? = null,
val vecGuid: ByteArray? = null,
val vecServerBuf: ByteArray? = null
) : JceStruct() {
override fun writeTo(builder: JceOutput) {
builder.write(lUin, 0)
builder.write(lBid, 1)
builder.write(cConnType, 2)
builder.write(sOther, 3)
builder.write(iStatus, 4)
builder.write(bOnlinePush, 5)
builder.write(bIsOnline, 6)
builder.write(bIsShowOnline, 7)
builder.write(bKikPC, 8)
builder.write(bKikWeak, 9)
builder.write(timeStamp, 10)
builder.write(iOSVersion, 11)
builder.write(cNetType, 12)
if (sBuildVer != null) {
builder.write(sBuildVer, 13)
}
builder.write(bRegType, 14)
if (vecDevParam != null) {
builder.write(vecDevParam, 15)
}
if (vecGuid != null) {
builder.write(vecGuid, 16)
}
builder.write(iLocaleID, 17)
builder.write(bSlientPush, 18)
if (strDevName != null) {
builder.write(strDevName, 19)
}
if (strDevType != null) {
builder.write(strDevType, 20)
}
if (strOSVer != null) {
builder.write(strOSVer, 21)
}
builder.write(bOpenPush, 22)
builder.write(iLargeSeq, 23)
builder.write(iLastWatchStartTime, 24)
// if (this.vecBindUin != null) {
// builder.write(this.vecBindUin, 25)
// }
builder.write(uOldSSOIp, 26)
builder.write(uNewSSOIp, 27)
if (sChannelNo != null) {
builder.write(sChannelNo, 28)
}
builder.write(lCpId, 29)
if (strVendorName != null) {
builder.write(strVendorName, 30)
}
if (strVendorOSName != null) {
builder.write(strVendorOSName, 31)
}
if (strIOSIdfa != null) {
builder.write(strIOSIdfa, 32)
}
if (bytes_0x769_reqbody != null) {
builder.write(bytes_0x769_reqbody, 33)
}
builder.write(bIsSetStatus, 34)
if (vecServerBuf != null) {
builder.write(vecServerBuf, 35)
}
builder.write(bSetMute, 36)
}
}

View File

@ -0,0 +1,12 @@
package net.mamoe.mirai.qqandroid.network.protocol.jce
import kotlinx.io.core.BytePacketBuilder
import net.mamoe.mirai.qqandroid.network.io.JceOutput
import net.mamoe.mirai.qqandroid.network.io.buildJcePacket
import net.mamoe.mirai.qqandroid.network.io.writeJcePacket
fun BytePacketBuilder.writeUniRequestPacket(requestPacket: RequestPacket) {
writeJcePacket {
requestPacket.writeTo(this)
}
}

View File

@ -0,0 +1,9 @@
package net.mamoe.mirai.qqandroid.network.protocol.packet
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.protobuf.ProtoBuf
interface MessageMicro
fun <T : MessageMicro> T.toByteArray(serializer: SerializationStrategy<T>): ByteArray = ProtoBuf.dump(serializer, this)

View File

@ -31,8 +31,8 @@ internal class OutgoingPacket constructor(
}
}
private val KEY_16_ZEROS = ByteArray(16)
private val EMPTY_BYTE_ARRAY = ByteArray(0)
internal val KEY_16_ZEROS = ByteArray(16)
internal val EMPTY_BYTE_ARRAY = ByteArray(0)
/**
* 最外层的包. 结构适用于登录之后的过程.
@ -61,16 +61,31 @@ private val EMPTY_BYTE_ARRAY = ByteArray(0)
* 31 39 39 34 37 30 31 30 32 31
* 18 5D 8F 17 7D 67 71 61 FE DB 30 A4 4D 16 DD 0E 8D 84 0A F2 44 BE FB BB 11 BB B4 AC 79 50 50 9F 4C 99 CC 77 0B AA B6 E0 06 0C F7 91 79 99 57 31 3D EF 38 92 2C C8 81 33 79 83 FF C6 2F BA 18 2A 33 F8 D9 4E CD 62 07 D8 08 B7 1A 1E C7 EB AC AB B4 1E C9 9D A9 15 9C 29 29 2A 99 F6 BB D0 43 65 D6 5E 9C 93 A8 8D 17 08 5B 6A 29 92 58 6A 75 C9 B5 45 B3 0E A5 D3 52 8F 9A A4 88 36 A0 14 3A 21 F2 46 C3 91 66 A3 73 67 6A 3E F7 9D 8E 44 52 87 7B 8A C7 1B E2 D3 98 62 E8 25 30 2A 43 5C 5A B2 C6 45 F5 39 EC 85 81 BF 7D 22 4C E8 01 87 92 48 38 06 6B A0 83 70 0B 51 ED CF 7A FF E2 F2 06 3E A7 95 4E E5 29 23 32 1C FE 79 C6 08 C5 7A 39 B9 AF CD 4F 80 3E 5D 74 4D 0B E1 10 33 8D F0 54 8E 0E 22 96 B4 06 7F 29 01 1E CA 30 35 FD 8A 2E 51 04 20 79 7B 08 DC DF F6 64 21 6B C5 95 34 B3 40 D2 E8 CE BB DC 69 89 75 62 A6 0B 4A 49 9D 90 BA 68 2B BD 8A 50 2D 68 6B 56 40 0C 39 F2 08 20 1B EB A4 A5 20 1D 1F 7E FA 4B B8 2E 58 79 2A 16 54 26 6C C8 44 6C 4F 64 2D 5C 0C 47 2E 90 13 A9 D7 33 4A 51 17 6E 3F 3E 48 AE 39 D8 45 05 2C 0C 3C 9F 92 39 DB 62 B3 BB 64 EE 7E 91 C5 84 92 10 96 D9 F1 13 02 94 00 EA DA 87 7C 85 7B 68 BA 8D A1 AB F5 CD 9C EB 4C CD A0 38 78 43 80 DD E5 1D 28 25 1F F0 25 EF 0D 95 91 0F 21 5D 41 06 00 03 48 77 E0 98 09 3E 04 5A B0 93 63 3B AE 8E 49 0C C2 12 BA DD C3 5A ED FF 68 98 22 C4 5E F6 1E 85 57 15 E8 7E 26 22 E3 70 C2 57 F4 CE 2F CB C4 DC 39 4A 9C FE DE 27 18 D3 36 66 88 92 D7 69 D0 04 8E 93 9B AD E9 2E 5A 2C 91 CD 28 DF BE 62 CF 2C 72 8E FD A9 1F 0E 8E 00 9E 54 28 50 25 0C E7 DC 98 85 C9 B3 59 A8 97 F5 2E 7F 44 4C 43 3C C4 65 E5 AB DB 5B 3C 50 2D 53 B3 EA 74 3C 39 F4 0A 52 31 34 30 F5 E6 82 CD 36 D9
*/
internal inline fun PacketFactory<*, *>.buildOutgingPacket(
@UseExperimental(MiraiInternalAPI::class)
internal inline fun PacketFactory<*>.buildOutgingPacket(
client: QQAndroidClient,
subAppId: Long,
extraData: ByteArray = EMPTY_BYTE_ARRAY,
name: String? = null,
id: PacketId = this.id,
ssoExtraData: ByteReadPacket = BRP_STUB,
key: ByteArray,
body: BytePacketBuilder.(sequenceId: Int) -> Unit
){
): OutgoingPacket {
val sequenceId: Int = client.nextSsoSequenceId()
return OutgoingPacket(name, id, sequenceId, buildPacket {
writeIntLVPacket(lengthOffset = { it + 4 }) {
writeInt(0x0B)
writeByte(1)
writeInt(sequenceId)
writeByte(0)
client.uin.toString().let {
writeInt(it.length + 4)
writeStringUtf8(it)
}
encryptAndWrite(key) {
body(sequenceId)
}
}
})
}
/**
@ -92,7 +107,7 @@ internal inline fun PacketFactory<*, *>.buildOutgingPacket(
* byte[] body encrypted by 16 zero
*/
@UseExperimental(MiraiInternalAPI::class)
internal inline fun PacketFactory<*, *>.buildLoginOutgoingPacket(
internal inline fun PacketFactory<*>.buildLoginOutgoingPacket(
client: QQAndroidClient,
subAppId: Long,
extraData: ByteArray = EMPTY_BYTE_ARRAY,
@ -214,7 +229,7 @@ private inline fun BytePacketBuilder.writeLoginSsoPacket(
*
* byte[] body encrypted by [sessionKey]
*/
internal inline fun PacketFactory<*, *>.buildSessionOutgoingPacket(
internal inline fun PacketFactory<*>.buildSessionOutgoingPacket(
uinAccount: String,
sessionKey: DecrypterByteArray,
body: BytePacketBuilder.() -> Unit

View File

@ -25,9 +25,7 @@ import kotlin.jvm.JvmName
* @param TDecrypter 服务器回复包解密器
*/
@UseExperimental(ExperimentalUnsignedTypes::class)
internal abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(val decrypterType: DecrypterType<TDecrypter>) {
// TODO: 2020/1/12 Decrypter 多余. 需要删除
internal abstract class PacketFactory<out TPacket : Packet> {
@Suppress("PropertyName")
internal var _id: PacketId = NullPacketId
@ -44,20 +42,20 @@ internal abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypt
}
@JvmName("decode0")
private suspend inline fun <P : Packet> PacketFactory<P, *>.decode(bot: QQAndroidBot, packet: ByteReadPacket): P = packet.decode(bot)
private suspend inline fun <P : Packet> PacketFactory<P>.decode(bot: QQAndroidBot, packet: ByteReadPacket): P = packet.decode(bot)
private val DECRYPTER_16_ZERO = ByteArray(16)
internal typealias PacketConsumer = suspend (packet: Packet, packetId: PacketId, ssoSequenceId: Int) -> Unit
@UseExperimental(ExperimentalUnsignedTypes::class)
internal object KnownPacketFactories : List<PacketFactory<*, *>> by mutableListOf(
internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
LoginPacket
) {
fun findPacketFactory(commandName: String): PacketFactory<*, *> = this.first { it.id.commandName == commandName }
fun findPacketFactory(commandName: String): PacketFactory<*> = this.first { it.id.commandName == commandName }
fun findPacketFactory(commandId: Int): PacketFactory<*, *> = this.first { it.id.commandName == commandName }
fun findPacketFactory(commandId: Int): PacketFactory<*> = this.first { it.id.commandName == commandName }
// do not inline. Exceptions thrown will not be reported correctly
suspend fun parseIncomingPacket(bot: QQAndroidBot, rawInput: ByteReadPacket, consumer: PacketConsumer) =

View File

@ -11,8 +11,6 @@ import net.mamoe.mirai.qqandroid.utils.GuidSource
import net.mamoe.mirai.qqandroid.utils.MacOrAndroidIdChangeFlag
import net.mamoe.mirai.qqandroid.utils.guidFlag
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.cryptor.DecrypterByteArray
import net.mamoe.mirai.utils.cryptor.DecrypterType
import net.mamoe.mirai.utils.cryptor.contentToString
import net.mamoe.mirai.utils.cryptor.decryptBy
import net.mamoe.mirai.utils.currentTimeMillis
@ -20,16 +18,19 @@ import net.mamoe.mirai.utils.currentTimeSeconds
import net.mamoe.mirai.utils.io.*
import net.mamoe.mirai.utils.io.discardExact
class LoginPacketDecrypter(override val value: ByteArray) : DecrypterByteArray {
companion object : DecrypterType<LoginPacketDecrypter>
}
/**
* OicqRequest
*/
@UseExperimental(ExperimentalUnsignedTypes::class)
internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, LoginPacketDecrypter>(LoginPacketDecrypter) {
internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>() {
init {
this._id = PacketId(commandId = 0x0810, commandName = "wtlogin.login")
}
fun hahahaha() {
}
object SubCommand9 {
private const val appId = 16L
private const val subAppId = 537062845L
@ -60,6 +61,8 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log
LoginType.PASSWORD
)
hahahaha()
/* // from GetStWithPasswd
int mMiscBitmap = this.mMiscBitmap;
if (t.uinDeviceToken) {

View File

@ -0,0 +1,113 @@
package net.mamoe.mirai.qqandroid.network.protocol.packet.login
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.readBytes
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.io.buildJcePacket
import net.mamoe.mirai.qqandroid.network.protocol.jce.RequestPacket
import net.mamoe.mirai.qqandroid.network.protocol.jce.SvcReqRegister
import net.mamoe.mirai.qqandroid.network.protocol.jce.writeUniRequestPacket
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.buildOutgingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.oidb0x769.Oidb0x769
import net.mamoe.mirai.qqandroid.utils.NetworkType
import net.mamoe.mirai.utils.currentTimeSeconds
import net.mamoe.mirai.utils.io.encodeToString
@Suppress("EnumEntryName")
enum class RegPushReason {
appRegister,
createDefaultRegInfo,
fillRegProxy,
msfBoot,
msfByNetChange,
msfHeartTimeTooLong,
serverPush,
setOnlineStatus,
unknown
}
internal object SvcReqRegisterPacket : PacketFactory<SvcReqRegisterPacket.Response>() {
internal object Response : Packet
operator fun invoke(
client: QQAndroidClient,
regPushReason: RegPushReason = RegPushReason.setOnlineStatus
): OutgoingPacket = buildOutgingPacket(client, key = client.wLoginSigInfo.wtSessionTicketKey) {
writeUniRequestPacket(
RequestPacket(
sServantName = "PushService",
sFuncName = "SvcReqRegister",
sBuffer = buildJcePacket {
writeMap(
mapOf(
"SvcReqRegister" to buildJcePacket {
writeJceStruct(
SvcReqRegister(
cConnType = 0,
lBid = 1 or 2 or 4,
lUin = client.uin,
iStatus = client.onlineStatus.id,
bKikPC = 0, // 是否把 PC 踢下线
bKikWeak = 0,
timeStamp = currentTimeSeconds, // millis or seconds??
iLargeSeq = 0,
bRegType =
if (regPushReason == RegPushReason.appRegister ||
regPushReason == RegPushReason.fillRegProxy ||
regPushReason == RegPushReason.createDefaultRegInfo ||
regPushReason == RegPushReason.setOnlineStatus
) {
0
} else {
1
}.toByte(),
bIsSetStatus = if (regPushReason == RegPushReason.setOnlineStatus) 1 else 0,
iOSVersion = client.device.version.sdk.toLong(),
cNetType = if (client.networkType == NetworkType.WIFI) 1 else 0,
vecGuid = client.device.guid,
strDevName = client.device.model.encodeToString(),
strDevType = client.device.model.encodeToString(),
strOSVer = client.device.version.release.encodeToString(),
// register 时还需要
/*
var44.uNewSSOIp = field_127445;
var44.uOldSSOIp = field_127444;
var44.strVendorName = ROMUtil.getRomName();
var44.strVendorOSName = ROMUtil.getRomVersion(20);
*/
bytes_0x769_reqbody = ProtoBuf.dump(
Oidb0x769.RequestBody.serializer(), Oidb0x769.RequestBody(
rpt_config_list = listOf(
Oidb0x769.ConfigSeq(
type = 46,
version = 4
),
Oidb0x769.ConfigSeq(
type = 283,
version = 0
)
)
)
),
bSetMute = 0
), 0
)
}.readBytes()
), 0
)
}.readBytes()
)
)
}
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
return Response
}
}

View File

@ -8,7 +8,7 @@ import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.packet.*
import net.mamoe.mirai.utils.io.toReadPacket
internal object TransEmpPacket : PacketFactory<TransEmpPacket.Response, LoginPacketDecrypter>(LoginPacketDecrypter) {
internal object TransEmpPacket : PacketFactory<TransEmpPacket.Response>() {
init {
_id = PacketId(0x0812, "wtlogin.trans_emp")

View File

@ -0,0 +1,19 @@
package net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.command
import kotlinx.serialization.Serializable
import net.mamoe.mirai.qqandroid.network.protocol.packet.MessageMicro
/**
* oidb_cmd0xcf8$GetPublicAccountDetailInfoRequest
*/
@Serializable
class GetPublicAccountDetailInfoRequest(
val seqno: Int, // uint
val uinLong: Long,
val version: Int, // uint
val versionInfo: String
) : MessageMicro
class GetPublicAccountDetailInfoResponse(
) : MessageMicro

View File

@ -0,0 +1,85 @@
package net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.oidb0x769
import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable
class Oidb0x769 {
@Serializable
class RequestBody(
@SerialId(1) val rpt_config_list: List<ConfigSeq>
// @SerialId(2) val msg_device_info: DeviceInfo,
// @SerialId(3) val str_info: String = "",
// @SerialId(4) val province: String,
// @SerialId(5) val city: String,
// @SerialId(6) val req_debug_msg: Int = 0,
// @SerialId(101) val query_uin_package_usage_req: QueryUinPackageUsageReq
)
@Serializable
class QueryUinPackageUsageReq(
@SerialId(1) val type: Int,
@SerialId(2) val uinFileSize: Long = 0
)
@Serializable
class ConfigSeq(
@SerialId(1) val type: Int, // uint
@SerialId(2) val version: Int // uint
)
@Serializable
class DeviceInfo(
@SerialId(1) val brand: String,
@SerialId(2) val model: String
//@SerialId(3) val os: OS,
//@SerialId(4) val cpu: CPU,
//@SerialId(5) val memory: Memory,
//@SerialId(6) val storage: Storage,
//@SerialId(7) val screen: Screen,
//@SerialId(8) val camera: Camera
)
@Serializable
class OS(
@SerialId(1) val type: Int = 1,
@SerialId(2) val version: String,
@SerialId(3) val sdk: String,
@SerialId(4) val kernel: String,
@SerialId(5) val rom: String
)
@Serializable
class Camera(
@SerialId(1) val primary: Long,
@SerialId(2) val secondary: Long,
@SerialId(3) val flag: Boolean
)
@Serializable
class CPU(
@SerialId(1) val model: String,
@SerialId(2) val frequency: Int,
@SerialId(3) val cores: Int
)
@Serializable
class Memory(
@SerialId(1) val total: Int,
@SerialId(2) val process: Int
)
@Serializable
class Screen(
@SerialId(1) val model: String,
@SerialId(2) val width: Int,
@SerialId(3) val height: Int,
@SerialId(4) val dpi: Int,
@SerialId(5) val multiTouch: Boolean
)
@Serializable
class Storage(
@SerialId(1) val builtin: Int,
@SerialId(2) val external: Int
)
}

View File

@ -0,0 +1,22 @@
package net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.sso
import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable
import net.mamoe.mirai.qqandroid.network.protocol.packet.MessageMicro
/**
* oidb_sso$OIDBSSOPkg
*/
@Serializable
class OidbSsoPackage(
@SerialId(1) val command: Int, // uint
@SerialId(2) val serviceType: Int, // uint
@SerialId(3) val result: Int, // uint
@SerialId(4) val bodyBuffer: ByteArray,
@SerialId(5) val errorMessage: String,
@SerialId(6) val clientVersion: String
) : MessageMicro

View File

@ -3,7 +3,10 @@ package net.mamoe.mirai.qqandroid.utils
import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.oidb0x769.Oidb0x769
import net.mamoe.mirai.utils.cryptor.contentToString
import net.mamoe.mirai.utils.getValue
import net.mamoe.mirai.utils.io.encodeToString
import net.mamoe.mirai.utils.unsafeWeakRef
abstract class DeviceInfo(
@ -84,7 +87,18 @@ abstract class DeviceInfo(
val incremental: ByteArray
val release: ByteArray
val codename: ByteArray
val sdk: Int
}
}
}
/*
fun DeviceInfo.toOidb0x769DeviceInfo() : Oidb0x769.DeviceInfo = Oidb0x769.DeviceInfo(
brand = brand.encodeToString(),
model = model.encodeToString(),
os = Oidb0x769.OS(
version = version.release.encodeToString(),
sdk = version.sdk.toString(),
kernel = version.kernel
)
)
*/

View File

@ -35,6 +35,7 @@ actual class SystemDeviceInfo actual constructor(context: Context) : DeviceInfo(
override val incremental: ByteArray get() = "5891938".toByteArray()
override val release: ByteArray get() = "10".toByteArray()
override val codename: ByteArray get() = "REL".toByteArray()
override val sdk: Int get() = 29
}
}

View File

@ -4,7 +4,7 @@ import kotlinx.io.pool.DefaultPool
import kotlinx.io.pool.ObjectPool
internal const val DEFAULT_BYTE_ARRAY_POOL_SIZE = 256
internal const val DEFAULT_BYTE_ARRAY_SIZE = 4096
internal const val DEFAULT_BYTE_ARRAY_SIZE = 8192
val ByteArrayPool: ObjectPool<ByteArray> = ByteArrayPoolImpl

View File

@ -2,8 +2,6 @@
package net.mamoe.mirai.utils.io
import kotlinx.io.charsets.Charset
import kotlinx.io.charsets.Charsets
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.String
import kotlinx.io.core.use
@ -47,7 +45,7 @@ fun UByteArray.toUHexString(separator: String = " ", offset: Int = 0, length: In
}
}
fun ByteArray.encodeToString(charset: Charset = Charsets.UTF_8): String = String(this, charset = charset)
fun ByteArray.encodeToString(): String = String(this)
fun ByteArray.toReadPacket(offset: Int = 0, length: Int = this.size) = ByteReadPacket(this, offset = offset, length = length)