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:
parent
cc171a87b4
commit
04c54f2a83
mirai-core-qqandroid/src
androidMain/kotlin/net/mamoe/mirai/qqandroid/utils
commonMain/kotlin/net/mamoe/mirai/qqandroid
jvmMain/kotlin/net/mamoe/mirai/qqandroid/utils
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io
@ -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
|
||||
}
|
||||
}
|
@ -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")) {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
@ -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
|
||||
|
@ -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) =
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
@ -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
|
@ -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
|
||||
)
|
||||
}
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
)
|
||||
*/
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user