From f3d3130f2d436cc25818e4a06111ad9be068a05f Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 10 Apr 2021 18:43:47 +0800 Subject: [PATCH] Support login cache and login without password. close #1158 --- ...binary-compatibility-validator-android.api | 2 + .../api/binary-compatibility-validator.api | 2 + .../kotlin/utils/BotConfiguration.kt | 14 +++ mirai-core-utils/src/commonMain/kotlin/IO.kt | 5 +- .../src/commonMain/kotlin/Serialization.kt | 11 +++ mirai-core/src/commonMain/kotlin/MiraiImpl.kt | 6 +- .../src/commonMain/kotlin/QQAndroidBot.kt | 70 +++++++++++++- .../kotlin/network/AccountSecrets.kt | 83 +++++++++++++++++ .../kotlin/network/QQAndroidClient.kt | 69 ++++---------- .../kotlin/network/highway/Highway.kt | 1 + .../src/commonMain/kotlin/network/keys.kt | 93 ++++++------------- .../protocol/packet/OutgoingPacketAndroid.kt | 4 +- .../network/protocol/packet/PacketFactory.kt | 1 - .../kotlin/network/protocol/packet/Tlv.kt | 1 + .../protocol/packet/chat/MusicSharePacket.kt | 1 + .../protocol/packet/chat/TroopManagement.kt | 1 + .../protocol/packet/login/Heartbeat.kt | 3 +- .../network/protocol/packet/login/StatSvc.kt | 5 +- .../network/protocol/packet/login/WtLogin.kt | 88 +++++++++++------- .../packet/login/wtlogin/WtLogin10.kt | 2 +- .../packet/login/wtlogin/WtLogin15.kt | 2 +- .../protocol/packet/login/wtlogin/WtLogin2.kt | 2 + .../packet/login/wtlogin/WtLogin20.kt | 2 + .../protocol/packet/login/wtlogin/WtLogin9.kt | 2 +- .../packet/login/wtlogin/WtLoginExt.kt | 8 +- .../commonMain/kotlin/utils/RemoteFileImpl.kt | 1 + 26 files changed, 311 insertions(+), 168 deletions(-) create mode 100644 mirai-core/src/commonMain/kotlin/network/AccountSecrets.kt diff --git a/binary-compatibility-validator/android/api/binary-compatibility-validator-android.api b/binary-compatibility-validator/android/api/binary-compatibility-validator-android.api index c4051ae98..eb412b6fc 100644 --- a/binary-compatibility-validator/android/api/binary-compatibility-validator-android.api +++ b/binary-compatibility-validator/android/api/binary-compatibility-validator-android.api @@ -5578,6 +5578,7 @@ public class net/mamoe/mirai/utils/BotConfiguration { public final fun getHeartbeatTimeoutMillis ()J public final fun getHighwayUploadCoroutineCount ()I public final fun getJson ()Lkotlinx/serialization/json/Json; + public final fun getLoginCacheEnabled ()Z public final fun getLoginSolver ()Lnet/mamoe/mirai/utils/LoginSolver; public final fun getNetworkLoggerSupplier ()Lkotlin/jvm/functions/Function1; public final fun getParentCoroutineContext ()Lkotlin/coroutines/CoroutineContext; @@ -5621,6 +5622,7 @@ public class net/mamoe/mirai/utils/BotConfiguration { public final fun setHeartbeatTimeoutMillis (J)V public final fun setHighwayUploadCoroutineCount (I)V public final fun setJson (Lkotlinx/serialization/json/Json;)V + public final fun setLoginCacheEnabled (Z)V public final fun setLoginSolver (Lnet/mamoe/mirai/utils/LoginSolver;)V public final fun setNetworkLoggerSupplier (Lkotlin/jvm/functions/Function1;)V public final fun setParentCoroutineContext (Lkotlin/coroutines/CoroutineContext;)V diff --git a/binary-compatibility-validator/api/binary-compatibility-validator.api b/binary-compatibility-validator/api/binary-compatibility-validator.api index 232af1eaf..e145bd15f 100644 --- a/binary-compatibility-validator/api/binary-compatibility-validator.api +++ b/binary-compatibility-validator/api/binary-compatibility-validator.api @@ -5578,6 +5578,7 @@ public class net/mamoe/mirai/utils/BotConfiguration { public final fun getHeartbeatTimeoutMillis ()J public final fun getHighwayUploadCoroutineCount ()I public final fun getJson ()Lkotlinx/serialization/json/Json; + public final fun getLoginCacheEnabled ()Z public final fun getLoginSolver ()Lnet/mamoe/mirai/utils/LoginSolver; public final fun getNetworkLoggerSupplier ()Lkotlin/jvm/functions/Function1; public final fun getParentCoroutineContext ()Lkotlin/coroutines/CoroutineContext; @@ -5621,6 +5622,7 @@ public class net/mamoe/mirai/utils/BotConfiguration { public final fun setHeartbeatTimeoutMillis (J)V public final fun setHighwayUploadCoroutineCount (I)V public final fun setJson (Lkotlinx/serialization/json/Json;)V + public final fun setLoginCacheEnabled (Z)V public final fun setLoginSolver (Lnet/mamoe/mirai/utils/LoginSolver;)V public final fun setNetworkLoggerSupplier (Lkotlin/jvm/functions/Function1;)V public final fun setParentCoroutineContext (Lkotlin/coroutines/CoroutineContext;)V diff --git a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt index a0b1becb7..ec1661df4 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt @@ -485,6 +485,20 @@ public open class BotConfiguration { // open for Java contactListCache.groupMemberListCacheEnabled = true } + /** + * 登录缓存. + * + * 开始后在密码登录成功时会保存秘钥等信息, 在下次启动时通过这些信息登录, 而不提交密码. + * 可以减少验证码出现的频率. + * + * 秘钥信息会由密码加密保存. 如果秘钥过期, 则会进行普通密码登录. + * + * 默认 `true` (开启). + * + * @since 2.6 + */ + public var loginCacheEnabled: Boolean = true + /////////////////////////////////////////////////////////////////////////// // Misc /////////////////////////////////////////////////////////////////////////// diff --git a/mirai-core-utils/src/commonMain/kotlin/IO.kt b/mirai-core-utils/src/commonMain/kotlin/IO.kt index 445ebcc06..6e47d69a1 100644 --- a/mirai-core-utils/src/commonMain/kotlin/IO.kt +++ b/mirai-core-utils/src/commonMain/kotlin/IO.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 Mamoe Technologies and contributors. + * Copyright 2019-2021 Mamoe Technologies and contributors. * * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. @@ -126,6 +126,9 @@ public inline fun Input.readString(length: UShort, charset: Charset = Charsets.U public inline fun Input.readString(length: Byte, charset: Charset = Charsets.UTF_8): String = String(this.readBytes(length.toInt()), charset = charset) +public fun Input.readUShortLVString(): String = String(this.readUShortLVByteArray()) +public fun Input.readUShortLVByteArray(): ByteArray = this.readBytes(this.readUShort().toInt()) + public fun File.createFileIfNotExists() { if (!this.exists()) { this.parentFile.mkdirs() diff --git a/mirai-core-utils/src/commonMain/kotlin/Serialization.kt b/mirai-core-utils/src/commonMain/kotlin/Serialization.kt index 85e5e9724..fb4f91234 100644 --- a/mirai-core-utils/src/commonMain/kotlin/Serialization.kt +++ b/mirai-core-utils/src/commonMain/kotlin/Serialization.kt @@ -13,6 +13,7 @@ package net.mamoe.mirai.utils +import kotlinx.serialization.BinaryFormat import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.StringFormat import kotlinx.serialization.descriptors.ClassSerialDescriptorBuilder @@ -30,6 +31,16 @@ public fun File.loadNotBlankAs( return stringFormat.decodeFromString(serializer, this.readText()) } +public fun File.loadNotBlankAs( + serializer: DeserializationStrategy, + binaryFormat: BinaryFormat, +): T? { + if (!this.exists() || this.length() == 0L) { + return null + } + return binaryFormat.decodeFromByteArray(serializer, this.readBytes()) +} + public fun SerialDescriptor.copy(newName: String): SerialDescriptor = buildClassSerialDescriptor(newName) { takeElementsFrom(this@copy) } diff --git a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt index f072492cd..cc3f34045 100644 --- a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt +++ b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt @@ -22,13 +22,17 @@ import kotlinx.serialization.json.* import net.mamoe.mirai.* import net.mamoe.mirai.contact.* import net.mamoe.mirai.data.* -import net.mamoe.mirai.event.events.* +import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent +import net.mamoe.mirai.event.events.FriendAddEvent +import net.mamoe.mirai.event.events.MemberJoinRequestEvent +import net.mamoe.mirai.event.events.NewFriendRequestEvent import net.mamoe.mirai.internal.contact.* import net.mamoe.mirai.internal.contact.info.FriendInfoImpl import net.mamoe.mirai.internal.contact.info.MemberInfoImpl import net.mamoe.mirai.internal.message.* import net.mamoe.mirai.internal.message.DeepMessageRefiner.refineDeep import net.mamoe.mirai.internal.network.highway.* +import net.mamoe.mirai.internal.network.protocol import net.mamoe.mirai.internal.network.protocol.data.jce.SvcDevLoginInfo import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.internal.network.protocol.data.proto.LongMsg diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt index 0dfdd5711..14fe61833 100644 --- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt +++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt @@ -28,12 +28,17 @@ import net.mamoe.mirai.internal.network.handler.QQAndroidBotNetworkHandler import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketWithRespType import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc +import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin import net.mamoe.mirai.internal.utils.ScheduledJob +import net.mamoe.mirai.internal.utils.crypto.TEA import net.mamoe.mirai.internal.utils.friendCacheFile +import net.mamoe.mirai.internal.utils.io.serialization.loadAs +import net.mamoe.mirai.internal.utils.io.serialization.toByteArray import net.mamoe.mirai.message.data.ForwardMessage import net.mamoe.mirai.message.data.RichMessage import net.mamoe.mirai.network.LoginFailedException import net.mamoe.mirai.utils.* +import java.io.File import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext import kotlin.time.milliseconds @@ -59,18 +64,79 @@ internal class QQAndroidBot constructor( ) : AbstractBot(configuration, account.id) { val bdhSyncer: BdhSessionSyncer = BdhSessionSyncer(this) + /////////////////////////////////////////////////////////////////////////// + // Account secrets cache + /////////////////////////////////////////////////////////////////////////// + + // We cannot extract these logics until we rewrite the network framework. + + private val cacheDir: File by lazy { + configuration.workingDir.resolve(bot.configuration.cacheDir).apply { mkdirs() } + } + private val accountSecretsFile: File by lazy { + cacheDir.resolve("account.secrets") + } + + private fun saveSecrets(secrets: AccountSecretsImpl) { + if (secrets.wLoginSigInfoField == null) return + + accountSecretsFile.writeBytes( + TEA.encrypt( + secrets.toByteArray(AccountSecretsImpl.serializer()), + account.passwordMd5 + ) + ) + + network.logger.info { "Saved account secrets to local cache for fast login." } + } + + init { + if (configuration.loginCacheEnabled) { + eventChannel.parentScope(this).subscribeAlways { event -> + if (event is WtLogin.Login.LoginPacketResponse.Success) { + if (client.wLoginSigInfoInitialized) { + saveSecrets(AccountSecretsImpl(client)) + } + } + } + } + } + + private fun loadSecretsFromCacheOrCreate(deviceInfo: DeviceInfo): AccountSecrets { + val loaded = if (configuration.loginCacheEnabled && accountSecretsFile.exists()) { + kotlin.runCatching { + TEA.decrypt(accountSecretsFile.readBytes(), account.passwordMd5).loadAs(AccountSecretsImpl.serializer()) + }.getOrElse { e -> + logger.error("Failed to load account secrets from local cache. Invalidating cache...", e) + accountSecretsFile.delete() + null + } + } else null + if (loaded != null) { + logger.info { "Loaded account secrets from local cache." } + return loaded + } + + return AccountSecretsImpl(deviceInfo, account) // wLoginSigInfoField is null, no need to save. + } + + /////////////////////////// accounts secrets end + var client: QQAndroidClient = initClient() private set fun initClient(): QQAndroidClient { + val device = configuration.deviceInfo?.invoke(this) ?: DeviceInfo.random() client = QQAndroidClient( account, - bot = this, - device = configuration.deviceInfo?.invoke(this) ?: DeviceInfo.random() + device = device, + accountSecrets = loadSecretsFromCacheOrCreate(device) ) + client._bot = this return client } + override val bot: QQAndroidBot get() = this internal var firstLoginSucceed: Boolean = false diff --git a/mirai-core/src/commonMain/kotlin/network/AccountSecrets.kt b/mirai-core/src/commonMain/kotlin/network/AccountSecrets.kt new file mode 100644 index 000000000..9efcc02a2 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/network/AccountSecrets.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2019-2021 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +package net.mamoe.mirai.internal.network + +import kotlinx.io.core.toByteArray +import kotlinx.serialization.Serializable +import net.mamoe.mirai.internal.BotAccount +import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY +import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.get_mpasswd +import net.mamoe.mirai.internal.utils.io.ProtoBuf +import net.mamoe.mirai.utils.DeviceInfo +import net.mamoe.mirai.utils.md5 +import net.mamoe.mirai.utils.toByteArray +import java.util.concurrent.CopyOnWriteArraySet + + +internal interface AccountSecrets { + var wLoginSigInfoField: WLoginSigInfo? + + val wLoginSigInfoInitialized get() = wLoginSigInfoField != null + var wLoginSigInfo + get() = wLoginSigInfoField ?: error("wLoginSigInfoField is not yet initialized") + set(value) { + wLoginSigInfoField = value + } + + /** + * t537 + */ + var loginExtraData: MutableSet + + var G: ByteArray // sigInfo[2] + var dpwd: ByteArray + var randSeed: ByteArray // t403 + + /** + * t108 时更新 + */ + var ksid: ByteArray + + var tgtgtKey: ByteArray + val randomKey: ByteArray +} + +@Serializable +internal class AccountSecretsImpl( + override var loginExtraData: MutableSet, + override var wLoginSigInfoField: WLoginSigInfo?, + override var G: ByteArray, + override var dpwd: ByteArray, + override var randSeed: ByteArray, + override var ksid: ByteArray, + override var tgtgtKey: ByteArray, + override val randomKey: ByteArray, +) : AccountSecrets, ProtoBuf + +internal fun AccountSecretsImpl( + other: AccountSecrets, +): AccountSecretsImpl = other.run { + AccountSecretsImpl(loginExtraData, wLoginSigInfoField, G, dpwd, randSeed, ksid, tgtgtKey, randomKey) +} + +internal fun AccountSecretsImpl( + device: DeviceInfo, account: BotAccount +): AccountSecretsImpl { + return AccountSecretsImpl( + loginExtraData = CopyOnWriteArraySet(), + wLoginSigInfoField = null, + G = device.guid, + dpwd = get_mpasswd().toByteArray(), + randSeed = EMPTY_BYTE_ARRAY, + ksid = EMPTY_BYTE_ARRAY, + tgtgtKey = (account.passwordMd5 + ByteArray(4) + account.id.toInt().toByteArray()).md5(), + randomKey = getRandomByteArray(16), + ) +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/QQAndroidClient.kt b/mirai-core/src/commonMain/kotlin/network/QQAndroidClient.kt index c5743cab7..041f7e6d4 100644 --- a/mirai-core/src/commonMain/kotlin/network/QQAndroidClient.kt +++ b/mirai-core/src/commonMain/kotlin/network/QQAndroidClient.kt @@ -26,7 +26,6 @@ import net.mamoe.mirai.internal.network.protocol.SyncingCacheList import net.mamoe.mirai.internal.network.protocol.data.jce.FileStoragePushFSSvcList import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.internal.network.protocol.packet.Tlv -import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.get_mpasswd import net.mamoe.mirai.internal.utils.MiraiProtocolInternal import net.mamoe.mirai.internal.utils.NetworkType import net.mamoe.mirai.internal.utils.crypto.ECDH @@ -71,12 +70,11 @@ internal open class QQAndroidClient( val account: BotAccount, val ecdh: ECDH = ECDH(), val device: DeviceInfo, - bot: QQAndroidBot -) { - val protocol = MiraiProtocolInternal[bot.configuration.protocol] + accountSecrets: AccountSecrets +) : AccountSecrets by accountSecrets { + lateinit var _bot: QQAndroidBot + val bot: QQAndroidBot get() = _bot - val subAppId: Long - get() = protocol.id internal var strangerSeq: Int = 0 @@ -84,15 +82,9 @@ internal open class QQAndroidClient( var onlineStatus: OnlineStatus = OnlineStatus.ONLINE - val bot: QQAndroidBot by bot.unsafeWeakRef() - internal var tgtgtKey: ByteArray = (account.passwordMd5 + ByteArray(4) + uin.toInt().toByteArray()).md5() - internal val randomKey: ByteArray = getRandomByteArray(16) - - - internal val miscBitMap: Int = protocol.miscBitMap // 184024956 // 也可能是 150470524 ? - internal val mainSigMap: Int = protocol.mainSigMap - internal var subSigMap: Int = protocol.subSigMap // 0x10400 //=66,560 + internal val miscBitMap: Int get() = protocol.miscBitMap // 184024956 // 也可能是 150470524 ? + internal val mainSigMap: Int get() = protocol.mainSigMap private val _ssoSequenceId: AtomicInt = atomic(85600) @@ -101,14 +93,10 @@ internal open class QQAndroidClient( @MiraiInternalApi("Do not use directly. Get from the lambda param of buildSsoPacket") internal fun nextSsoSequenceId() = _ssoSequenceId.addAndGet(2) - var openAppId: Long = 715019303L val apkVersionName: ByteArray get() = protocol.ver.toByteArray() //"8.4.18".toByteArray() val buildVer: String get() = "8.4.18.4810" // 8.2.0.1296 // 8.4.8.4810 // 8.2.7.4410 - val clientVersion: String = "android ${protocol.ver}" // android 8.5.0 - val buildTime: Long get() = protocol.buildTime - val sdkVersion: String get() = protocol.sdkVer private val messageSequenceId: AtomicInt = atomic(22911) internal fun atomicNextMessageSequenceId(): Int = messageSequenceId.getAndAdd(2) @@ -127,6 +115,7 @@ internal open class QQAndroidClient( return friendSeq.compareAndSet(compare, id % 65535) } + private val requestPacketRequestId: AtomicInt = atomic(1921334513) internal fun nextRequestPacketRequestId(): Int = requestPacketRequestId.getAndAdd(2) @@ -139,17 +128,15 @@ internal open class QQAndroidClient( private val highwayDataTransSequenceIdForApplyUp: AtomicInt = atomic(77918) internal fun nextHighwayDataTransSequenceIdForApplyUp(): Int = highwayDataTransSequenceIdForApplyUp.getAndAdd(2) + val appClientVersion: Int = 0 + + val ssoVersion: Int = 15 + var networkType: NetworkType = NetworkType.WIFI - val apkSignatureMd5: ByteArray get() = protocol.sign.hexToBytes() // "A6 B7 45 BF 24 A2 C2 77 52 77 16 F6 F3 6E B6 8D".hexToBytes() - - /** - * 协议版本?, 8.2.7 的为 8001 - */ - val protocolVersion: Short = 8001 internal val groupConfig: GroupConfig = GroupConfig() @@ -214,6 +201,7 @@ internal open class QQAndroidClient( val pendingGroupMessageReceiptCacheList = SyncingCacheList(50) } + val syncingController = MessageSvcSyncData() /* @@ -248,44 +236,27 @@ internal open class QQAndroidClient( var t530: ByteArray? = null var t528: ByteArray? = null - /** - * t108 时更新 - */ - var ksid: ByteArray = EMPTY_BYTE_ARRAY - /** * t186 */ var pwdFlag: Boolean = false - /** - * t537 - */ - var loginExtraData: MutableSet = CopyOnWriteArraySet() lateinit var wFastLoginInfo: WFastLoginInfo var reserveUinInfo: ReserveUinInfo? = null - lateinit var wLoginSigInfo: WLoginSigInfo - val wLoginSigInfoInitialized get() = ::wLoginSigInfo.isInitialized - - var G: ByteArray = device.guid // sigInfo[2] - var dpwd: ByteArray = get_mpasswd().toByteArray() - var randSeed: ByteArray = EMPTY_BYTE_ARRAY // t403 - - var tlv113: ByteArray? = null - var t402: ByteArray? = null lateinit var qrPushSig: ByteArray - lateinit var mainDisplayName: ByteArray - - var transportSequenceId = 1 - - var lastT106Full: ByteArray? = null - lateinit var t104: ByteArray - } +internal val QQAndroidClient.clientVersion: String get() = "android ${protocol.ver}" // android 8.5.0 +internal val QQAndroidClient.protocol get() = MiraiProtocolInternal[bot.configuration.protocol] +internal val QQAndroidClient.sdkVersion: String get() = protocol.sdkVer +internal val QQAndroidClient.buildTime: Long get() = protocol.buildTime +internal val QQAndroidClient.subAppId: Long get() = protocol.id +internal val QQAndroidClient.apkSignatureMd5: ByteArray get() = protocol.sign.hexToBytes() // "A6 B7 45 BF 24 A2 C2 77 52 77 16 F6 F3 6E B6 8D".hexToBytes() +internal val QQAndroidClient.subSigMap: Int get() = protocol.subSigMap // 0x10400 //=66,560 + internal fun BytePacketBuilder.writeLoginExtraData(loginExtraData: LoginExtraData) { loginExtraData.run { writeLong(uin) diff --git a/mirai-core/src/commonMain/kotlin/network/highway/Highway.kt b/mirai-core/src/commonMain/kotlin/network/highway/Highway.kt index 7ae154342..ad54c691a 100644 --- a/mirai-core/src/commonMain/kotlin/network/highway/Highway.kt +++ b/mirai-core/src/commonMain/kotlin/network/highway/Highway.kt @@ -25,6 +25,7 @@ import net.mamoe.mirai.internal.network.BdhSession import net.mamoe.mirai.internal.network.QQAndroidClient import net.mamoe.mirai.internal.network.protocol.data.proto.CSDataHighwayHead import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY +import net.mamoe.mirai.internal.network.subAppId import net.mamoe.mirai.internal.utils.PlatformSocket import net.mamoe.mirai.internal.utils.crypto.TEA import net.mamoe.mirai.internal.utils.io.serialization.readProtoBuf diff --git a/mirai-core/src/commonMain/kotlin/network/keys.kt b/mirai-core/src/commonMain/kotlin/network/keys.kt index 2d3928734..e46826c9e 100644 --- a/mirai-core/src/commonMain/kotlin/network/keys.kt +++ b/mirai-core/src/commonMain/kotlin/network/keys.kt @@ -10,9 +10,7 @@ package net.mamoe.mirai.internal.network import kotlinx.io.core.ByteReadPacket -import kotlinx.io.core.Input -import kotlinx.io.core.readBytes -import kotlinx.io.core.readUShort +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import net.mamoe.mirai.internal.network.getRandomByteArray import net.mamoe.mirai.internal.network.protocol.packet.PacketLogger @@ -44,6 +42,7 @@ internal class WFastLoginInfo( } } +@Serializable internal class WLoginSimpleInfo( val uin: Long, // uin val imgType: ByteArray, @@ -56,6 +55,7 @@ internal class WLoginSimpleInfo( } } +@Serializable internal class LoginExtraData( val uin: Long, val ip: ByteArray, @@ -67,6 +67,7 @@ internal class LoginExtraData( } } +@Serializable internal class WLoginSigInfo( val uin: Long, var encryptA1: ByteArray?, // sigInfo[0] @@ -83,34 +84,34 @@ internal class WLoginSigInfo( var tgt: ByteArray, var a2CreationTime: Long, var tgtKey: ByteArray, - var userStSig: UserStSig, + var userStSig: KeyWithCreationTime, /** * TransEmpPacket 加密使用 */ var userStKey: ByteArray, - var userStWebSig: UserStWebSig, - var userA5: UserA5, - var userA8: UserA8, - var lsKey: LSKey, - var sKey: SKey, - var userSig64: UserSig64, + var userStWebSig: KeyWithExpiry, + var userA5: KeyWithCreationTime, + var userA8: KeyWithExpiry, + var lsKey: KeyWithExpiry, + var sKey: KeyWithExpiry, + var userSig64: KeyWithCreationTime, var openId: ByteArray, - var openKey: OpenKey, - var vKey: VKey, - var accessToken: AccessToken, - var d2: D2, + var openKey: KeyWithCreationTime, + var vKey: KeyWithExpiry, + var accessToken: KeyWithCreationTime, + var d2: KeyWithExpiry, var d2Key: ByteArray, - var sid: Sid, - var aqSig: AqSig, + var sid: KeyWithExpiry, + var aqSig: KeyWithCreationTime, var psKeyMap: PSKeyMap, - var pt4TokenMap: Pt4TokenMap, + var pt4TokenMap: MutableMap = mutableMapOf(), // = Pt4TokenMap maybe compiler bug var superKey: ByteArray, var payToken: ByteArray, var pf: ByteArray, var pfKey: ByteArray, var da2: ByteArray, // val pt4Token: ByteArray, - var wtSessionTicket: WtSessionTicket, + var wtSessionTicket: KeyWithCreationTime, var wtSessionTicketKey: ByteArray, var deviceToken: ByteArray, var encryptedDownloadSession: EncryptedDownloadSession? = null @@ -130,41 +131,8 @@ internal class WLoginSigInfo( } } -internal class UserStSig(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) -internal class LSKey(data: ByteArray, creationTime: Long, expireTime: Long) : - KeyWithExpiry(data, creationTime, expireTime) - -internal class UserStWebSig(data: ByteArray, creationTime: Long, expireTime: Long) : - KeyWithExpiry(data, creationTime, expireTime) - -internal class UserA8(data: ByteArray, creationTime: Long, expireTime: Long) : - KeyWithExpiry(data, creationTime, expireTime) - -internal class UserA5(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) -internal class SKey(data: ByteArray, creationTime: Long, expireTime: Long) : - KeyWithExpiry(data, creationTime, expireTime) - -internal class UserSig64(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) -internal class OpenKey(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) -internal class VKey(data: ByteArray, creationTime: Long, expireTime: Long) : - KeyWithExpiry(data, creationTime, expireTime) - -internal class AccessToken(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) -internal class D2(data: ByteArray, creationTime: Long, expireTime: Long) : KeyWithExpiry(data, creationTime, expireTime) -internal class Sid(data: ByteArray, creationTime: Long, expireTime: Long) : - KeyWithExpiry(data, creationTime, expireTime) - -internal class AqSig(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) - -internal class Pt4Token(data: ByteArray, creationTime: Long, expireTime: Long) : - KeyWithExpiry(data, creationTime, expireTime) - -internal typealias PSKeyMap = MutableMap -internal typealias Pt4TokenMap = MutableMap - -internal fun Input.readUShortLVString(): String = kotlinx.io.core.String(this.readUShortLVByteArray()) - -internal fun Input.readUShortLVByteArray(): ByteArray = this.readBytes(this.readUShort().toInt()) +internal typealias PSKeyMap = MutableMap +internal typealias Pt4TokenMap = MutableMap internal fun parsePSKeyMapAndPt4TokenMap( data: ByteArray, @@ -180,20 +148,16 @@ internal fun parsePSKeyMapAndPt4TokenMap( val pt4token = readUShortLVByteArray() when { - psKey.isNotEmpty() -> outPSKeyMap[domain] = PSKey(psKey, creationTime, expireTime) - pt4token.isNotEmpty() -> outPt4TokenMap[domain] = Pt4Token(pt4token, creationTime, expireTime) + psKey.isNotEmpty() -> outPSKeyMap[domain] = KeyWithExpiry(psKey, creationTime, expireTime) + pt4token.isNotEmpty() -> outPt4TokenMap[domain] = KeyWithExpiry(pt4token, creationTime, expireTime) } } } -internal class PSKey(data: ByteArray, creationTime: Long, expireTime: Long) : - KeyWithExpiry(data, creationTime, expireTime) - -internal class WtSessionTicket(data: ByteArray, creationTime: Long) : KeyWithCreationTime(data, creationTime) - +@Serializable internal open class KeyWithExpiry( - data: ByteArray, - creationTime: Long, + @SerialName("data1") override val data: ByteArray, + @SerialName("creationTime1") override val creationTime: Long, val expireTime: Long ) : KeyWithCreationTime(data, creationTime) { override fun toString(): String { @@ -201,9 +165,10 @@ internal open class KeyWithExpiry( } } +@Serializable internal open class KeyWithCreationTime( - val data: ByteArray, - val creationTime: Long + open val data: ByteArray, + open val creationTime: Long ) { override fun toString(): String { return "KeyWithCreationTime(data=${data.toUHexString()}, creationTime=$creationTime)" diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacketAndroid.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacketAndroid.kt index 06a0215d5..af5a9173e 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacketAndroid.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacketAndroid.kt @@ -16,8 +16,8 @@ import kotlinx.io.core.buildPacket import kotlinx.io.core.writeFully import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.network.Packet -import net.mamoe.mirai.internal.network.handler.QQAndroidBotNetworkHandler import net.mamoe.mirai.internal.network.QQAndroidClient +import net.mamoe.mirai.internal.network.handler.QQAndroidBotNetworkHandler import net.mamoe.mirai.internal.utils.io.encryptAndWrite import net.mamoe.mirai.internal.utils.io.writeHex import net.mamoe.mirai.internal.utils.io.writeIntLVPacket @@ -286,7 +286,7 @@ internal fun BytePacketBuilder.writeOicqRequestPacket( val body = encryptMethod.makeBody(client, bodyBlock) writeByte(0x02) // head writeShort((27 + 2 + body.remaining).toShort()) // orthodox algorithm - writeShort(client.protocolVersion) + writeShort(8001) writeShort(commandId.toShort()) writeShort(1) // const?? writeInt(client.uin.toInt()) diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt index bd7d46538..8218c853e 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt @@ -26,7 +26,6 @@ import net.mamoe.mirai.internal.network.protocol.packet.login.Heartbeat import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin import net.mamoe.mirai.internal.network.protocol.packet.summarycard.SummaryCard -import net.mamoe.mirai.internal.network.readUShortLVByteArray import net.mamoe.mirai.internal.network.tryDecryptOrNull import net.mamoe.mirai.internal.utils.crypto.TEA import net.mamoe.mirai.internal.utils.crypto.adjustToPublicKey diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/Tlv.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/Tlv.kt index d2d9bd1a7..5f6b74ede 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/Tlv.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/Tlv.kt @@ -15,6 +15,7 @@ import kotlinx.io.core.* import net.mamoe.mirai.internal.network.LoginExtraData import net.mamoe.mirai.internal.network.QQAndroidClient import net.mamoe.mirai.internal.network.protocol.LoginType +import net.mamoe.mirai.internal.network.subAppId import net.mamoe.mirai.internal.network.writeLoginExtraData import net.mamoe.mirai.internal.utils.GuidSource import net.mamoe.mirai.internal.utils.MacOrAndroidIdChangeFlag diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/MusicSharePacket.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/MusicSharePacket.kt index 09a9a50b1..e10c87a6a 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/MusicSharePacket.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/MusicSharePacket.kt @@ -13,6 +13,7 @@ import kotlinx.io.core.ByteReadPacket import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.network.Packet import net.mamoe.mirai.internal.network.QQAndroidClient +import net.mamoe.mirai.internal.network.clientVersion import net.mamoe.mirai.internal.network.protocol.data.proto.OidbCmd0xb77 import net.mamoe.mirai.internal.network.protocol.data.proto.OidbSso import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/TroopManagement.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/TroopManagement.kt index 09a4c3c52..fb42c0986 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/TroopManagement.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/TroopManagement.kt @@ -25,6 +25,7 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.* import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket +import net.mamoe.mirai.internal.network.subAppId import net.mamoe.mirai.internal.utils.io.serialization.* import net.mamoe.mirai.utils.daysToSeconds diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/Heartbeat.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/Heartbeat.kt index 99888cbef..da292e787 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/Heartbeat.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/Heartbeat.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 Mamoe Technologies and contributors. + * Copyright 2019-2021 Mamoe Technologies and contributors. * * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. @@ -14,6 +14,7 @@ import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.network.Packet import net.mamoe.mirai.internal.network.QQAndroidClient import net.mamoe.mirai.internal.network.protocol.packet.* +import net.mamoe.mirai.internal.network.subAppId internal class Heartbeat { diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt index 626dd1ccf..9cba72d90 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt @@ -27,10 +27,7 @@ import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.contact.appId import net.mamoe.mirai.internal.createOtherClient import net.mamoe.mirai.internal.message.contextualBugReportException -import net.mamoe.mirai.internal.network.FriendListCache -import net.mamoe.mirai.internal.network.Packet -import net.mamoe.mirai.internal.network.QQAndroidClient -import net.mamoe.mirai.internal.network.getRandomByteArray +import net.mamoe.mirai.internal.network.* import net.mamoe.mirai.internal.network.protocol.data.jce.* import net.mamoe.mirai.internal.network.protocol.data.proto.Oidb0x769 import net.mamoe.mirai.internal.network.protocol.data.proto.StatSvcGetOnline diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/WtLogin.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/WtLogin.kt index 23b238113..1c38ddd61 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/WtLogin.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/WtLogin.kt @@ -11,6 +11,9 @@ package net.mamoe.mirai.internal.network.protocol.packet.login import kotlinx.io.core.* +import net.mamoe.mirai.Bot +import net.mamoe.mirai.event.AbstractEvent +import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.network.* import net.mamoe.mirai.internal.network.DebuggingProperties.SHOW_TLV_MAP_ON_LOGIN_SUCCESS @@ -95,43 +98,55 @@ internal class WtLogin { } - sealed class LoginPacketResponse : Packet { - object Success : LoginPacketResponse() { + sealed class LoginPacketResponse : Packet, BotEvent, Packet.NoEventLog, AbstractEvent() { + class Success(override val bot: Bot) : LoginPacketResponse() { override fun toString(): String = "LoginPacketResponse.Success" } data class Error( + override val bot: Bot, val code: Int, val title: String, val message: String, - val errorInfo: String + val errorInfo: String, ) : LoginPacketResponse() sealed class Captcha : LoginPacketResponse() { class Slider( - val url: String + override val bot: Bot, + val url: String, ) : Captcha() { override fun toString(): String = "LoginPacketResponse.Captcha.Slider" } class Picture( + override val bot: Bot, val data: ByteArray, - val sign: ByteArray + val sign: ByteArray, ) : Captcha() { override fun toString(): String = "LoginPacketResponse.Captcha.Picture" } } - data class UnsafeLogin(val url: String) : LoginPacketResponse() + data class UnsafeLogin( + override val bot: Bot, + val url: String, + ) : LoginPacketResponse() - class SMSVerifyCodeNeeded(val t402: ByteArray, val t403: ByteArray) : LoginPacketResponse() { + class SMSVerifyCodeNeeded( + override val bot: Bot, + val t402: ByteArray, + val t403: ByteArray, + ) : LoginPacketResponse() { override fun toString(): String { return "LoginPacketResponse.SMSVerifyCodeNeeded(t402=${t402.toUHexString()}, t403=${t403.toUHexString()})" } } - object DeviceLockLogin : LoginPacketResponse() { + class DeviceLockLogin( + override val bot: Bot, + ) : LoginPacketResponse() { override fun toString(): String = "WtLogin.Login.LoginPacketResponse.DeviceLockLogin" } } @@ -165,11 +180,11 @@ internal class WtLogin { return when (type.toInt()) { 0 -> onLoginSuccess(subCommand, tlvMap, bot) 2 -> onSolveLoginCaptcha(tlvMap, bot) - 160, 239 /*-96*/ -> onUnsafeDeviceLogin(tlvMap) + 160, 239 /*-96*/ -> onUnsafeDeviceLogin(tlvMap, bot) 204 /*-52*/ -> onDevLockLogin(tlvMap, bot) // 1, 15 -> onErrorMessage(tlvMap) ?: error("Cannot find error message") else -> { - onErrorMessage(type.toInt(), tlvMap) + onErrorMessage(type.toInt(), tlvMap, bot) ?: error("Cannot find error message, unknown login result type: $type, TLVMap = ${tlvMap._miraiContentToString()}") } } @@ -186,11 +201,11 @@ internal class WtLogin { client.G = (client.device.guid + client.dpwd + tlvMap.getOrFail(0x402)).md5() } // println("403: " + tlvMap[0x403]?.toUHexString()) - return LoginPacketResponse.DeviceLockLogin + return LoginPacketResponse.DeviceLockLogin(bot) } - private fun onUnsafeDeviceLogin(tlvMap: TlvMap): LoginPacketResponse.UnsafeLogin { - return LoginPacketResponse.UnsafeLogin(tlvMap.getOrFail(0x204).encodeToString()) + private fun onUnsafeDeviceLogin(tlvMap: TlvMap, bot: QQAndroidBot): LoginPacketResponse.UnsafeLogin { + return LoginPacketResponse.UnsafeLogin(bot, tlvMap.getOrFail(0x204).encodeToString()) } private fun onSolveLoginCaptcha(tlvMap: TlvMap, bot: QQAndroidBot): LoginPacketResponse.Captcha { @@ -207,7 +222,7 @@ internal class WtLogin { // val ret = tlvMap[0x104]?.let { println(it.toUHexString()) } bot.client.t104 = tlvMap.getOrFail(0x104) tlvMap[0x192]?.let { - return LoginPacketResponse.Captcha.Slider(it.encodeToString()) + return LoginPacketResponse.Captcha.Slider(bot, it.encodeToString()) } tlvMap[0x165]?.let { // if (question[18].toInt() == 0x36) { @@ -220,8 +235,8 @@ internal class WtLogin { val sign = imageData.readBytes(signInfoLength.toInt()) LoginPacketResponse.Captcha.Picture( - data = imageData.readBytes(), - sign = sign + bot, + data = imageData.readBytes(), sign = sign ) } // } else error("UNKNOWN CAPTCHA QUESTION: ${question.toUHexString()}, tlvMap=" + tlvMap.contentToString()) @@ -374,7 +389,7 @@ internal class WtLogin { if (client.wLoginSigInfoInitialized) { client.wLoginSigInfo.apply { superKey = tlvMap119.getOrDefault(0x16d, superKey) - d2 = D2( + d2 = KeyWithExpiry( tlvMap119.getOrDefault(0x143, d2.data), creationTime, creationTime + changeTokenTimeMap.getOrDefault(0x143, 1728000L) @@ -383,13 +398,14 @@ internal class WtLogin { tgt = tlvMap119.getOrDefault(0x10a, tgt) tgtKey = tlvMap119.getOrDefault(0x10d, tgtKey) a2ExpiryTime = creationTime + changeTokenTimeMap.getOrDefault(0x10a, 2160000L) - userStWebSig = UserStWebSig( + userStWebSig = KeyWithExpiry( tlvMap119.getOrDefault(0x103, userStWebSig.data), creationTime, creationTime + changeTokenTimeMap.getOrDefault(0x103, 6000L) ) userStKey = tlvMap119.getOrDefault(0x10e, userStKey) - userStSig = UserStSig((tlvMap119.getOrDefault(0x114, userStSig.data)), creationTime) + userStSig = + KeyWithCreationTime((tlvMap119.getOrDefault(0x114, userStSig.data)), creationTime) appPri = tlvMap119[0x11f]?.let { it.read { //change interval (int time) @@ -398,12 +414,12 @@ internal class WtLogin { } } ?: appPri - sKey = SKey( + sKey = KeyWithExpiry( tlvMap119.getOrEmpty(0x120), creationTime, creationTime + changeTokenTimeMap.getOrDefault(0x120, 86400L) ) - wtSessionTicket = WtSessionTicket( + wtSessionTicket = KeyWithCreationTime( tlvMap119.getOrDefault( 0x133, client.wLoginSigInfo.wtSessionTicket.data @@ -454,50 +470,50 @@ internal class WtLogin { tgt = tlvMap119.getOrFail(0x10a), a2CreationTime = creationTime, tgtKey = tlvMap119.getOrEmpty(0x10d), // from asyncContext._login_bitmap - userStSig = UserStSig((tlvMap119.getOrEmpty(0x114)), creationTime), + userStSig = KeyWithCreationTime((tlvMap119.getOrEmpty(0x114)), creationTime), userStKey = tlvMap119.getOrEmpty(0x10e), - userStWebSig = UserStWebSig( + userStWebSig = KeyWithExpiry( tlvMap119.getOrEmpty(0x103), creationTime, creationTime + changeTokenTimeMap.getOrDefault(0x103, 6000L) ), - userA5 = UserA5(tlvMap119.getOrEmpty(0x10b), creationTime), - userA8 = UserA8( + userA5 = KeyWithCreationTime(tlvMap119.getOrEmpty(0x10b), creationTime), + userA8 = KeyWithExpiry( tlvMap119.getOrEmpty(0x102), creationTime, creationTime + changeTokenTimeMap.getOrDefault(0x102, 72000L) ), - lsKey = LSKey( + lsKey = KeyWithExpiry( tlvMap119.getOrEmpty(0x11c), creationTime, creationTime + changeTokenTimeMap.getOrDefault(0x11c, 1641600L) ), - sKey = SKey( + sKey = KeyWithExpiry( tlvMap119.getOrEmpty(0x120), creationTime, creationTime + changeTokenTimeMap.getOrDefault(0x120, 86400L) ), - userSig64 = UserSig64(tlvMap119.getOrEmpty(0x121), creationTime), + userSig64 = KeyWithCreationTime(tlvMap119.getOrEmpty(0x121), creationTime), openId = openId.orEmpty(), - openKey = OpenKey(openKey.orEmpty(), creationTime), - vKey = VKey( + openKey = KeyWithCreationTime(openKey.orEmpty(), creationTime), + vKey = KeyWithExpiry( tlvMap119.getOrEmpty(0x136), creationTime, creationTime + changeTokenTimeMap.getOrDefault(0x136, 1728000L) ), - accessToken = AccessToken(tlvMap119.getOrEmpty(0x136), creationTime), - d2 = D2( + accessToken = KeyWithCreationTime(tlvMap119.getOrEmpty(0x136), creationTime), + d2 = KeyWithExpiry( tlvMap119.getOrFail(0x143), creationTime, creationTime + changeTokenTimeMap.getOrDefault(0x143, 1728000L) ), d2Key = tlvMap119.getOrEmpty(0x305), - sid = Sid( + sid = KeyWithExpiry( tlvMap119.getOrEmpty(0x164), creationTime, creationTime + changeTokenTimeMap.getOrDefault(0x164, 1728000L) ), - aqSig = AqSig(tlvMap119.getOrEmpty(0x171), creationTime), + aqSig = KeyWithCreationTime(tlvMap119.getOrEmpty(0x171), creationTime), psKeyMap = outPSKeyMap.orEmpty().toMutableMap(), pt4TokenMap = outPt4TokenMap.orEmpty().toMutableMap(), superKey = tlvMap119.getOrEmpty(0x16d), @@ -505,7 +521,7 @@ internal class WtLogin { pf = pf.orEmpty(), pfKey = pfKey.orEmpty(), da2 = tlvMap119.getOrEmpty(0x203), - wtSessionTicket = WtSessionTicket(tlvMap119.getOrEmpty(0x133), creationTime), + wtSessionTicket = KeyWithCreationTime(tlvMap119.getOrEmpty(0x133), creationTime), wtSessionTicketKey = tlvMap119.getOrEmpty(0x134), deviceToken = tlvMap119.getOrEmpty(0x322), encryptedDownloadSession = tlvMap119[0x11d]?.let { @@ -517,7 +533,7 @@ internal class WtLogin { } } - return LoginPacketResponse.Success + return LoginPacketResponse.Success(bot) } } diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin10.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin10.kt index c922c2596..a7ef570f0 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin10.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin10.kt @@ -9,7 +9,7 @@ package net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin -import net.mamoe.mirai.internal.network.QQAndroidClient +import net.mamoe.mirai.internal.network.* import net.mamoe.mirai.internal.network.protocol.packet.* import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin import net.mamoe.mirai.internal.utils.GuidSource diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin15.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin15.kt index 3fe83fcdf..192a69f43 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin15.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin15.kt @@ -9,7 +9,7 @@ package net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin -import net.mamoe.mirai.internal.network.QQAndroidClient +import net.mamoe.mirai.internal.network.* import net.mamoe.mirai.internal.network.protocol.packet.* import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin import net.mamoe.mirai.internal.utils.io.writeShortLVByteArray diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin2.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin2.kt index ee12d8779..8676ef678 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin2.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin2.kt @@ -12,6 +12,8 @@ package net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin import net.mamoe.mirai.internal.network.QQAndroidClient import net.mamoe.mirai.internal.network.protocol.packet.* import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin +import net.mamoe.mirai.internal.network.subAppId +import net.mamoe.mirai.internal.network.subSigMap internal object WtLogin2 : WtLoginExt { diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin20.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin20.kt index f0a331cfd..e14824601 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin20.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin20.kt @@ -12,6 +12,8 @@ package net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin import net.mamoe.mirai.internal.network.QQAndroidClient import net.mamoe.mirai.internal.network.protocol.packet.* import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin +import net.mamoe.mirai.internal.network.subAppId +import net.mamoe.mirai.internal.network.subSigMap internal object WtLogin20 : WtLoginExt { operator fun invoke( diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin9.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin9.kt index ca786f998..dd8e8e631 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin9.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin9.kt @@ -10,7 +10,7 @@ package net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin import kotlinx.io.core.toByteArray -import net.mamoe.mirai.internal.network.QQAndroidClient +import net.mamoe.mirai.internal.network.* import net.mamoe.mirai.internal.network.protocol.packet.* import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLoginExt.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLoginExt.kt index 4dd40f643..2f052f100 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLoginExt.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLoginExt.kt @@ -10,6 +10,7 @@ package net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin import kotlinx.io.core.* +import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.network.LoginExtraData import net.mamoe.mirai.internal.network.QQAndroidClient import net.mamoe.mirai.internal.network.WLoginSigInfo @@ -17,7 +18,6 @@ import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.internal.network.protocol.packet.Tlv import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin import net.mamoe.mirai.internal.network.protocol.packet.t145 -import net.mamoe.mirai.internal.network.readUShortLVByteArray import net.mamoe.mirai.internal.utils.crypto.TEA import net.mamoe.mirai.internal.utils.io.writeShortLVByteArray import net.mamoe.mirai.utils.* @@ -41,14 +41,14 @@ internal inline fun WtLoginExt.analysisTlv0x531( internal interface WtLoginExt { // so as not to register to global extension - fun onErrorMessage(type: Int, tlvMap: TlvMap): WtLogin.Login.LoginPacketResponse.Error? { + fun onErrorMessage(type: Int, tlvMap: TlvMap, bot: QQAndroidBot): WtLogin.Login.LoginPacketResponse.Error? { return tlvMap[0x149]?.read { discardExact(2) //type val title: String = readUShortLVString() val content: String = readUShortLVString() val otherInfo: String = readUShortLVString() - WtLogin.Login.LoginPacketResponse.Error(type, title, content, otherInfo) + WtLogin.Login.LoginPacketResponse.Error(bot, type, title, content, otherInfo) } ?: tlvMap[0x146]?.read { discardExact(2) // ver discardExact(2) // code @@ -57,7 +57,7 @@ internal interface WtLoginExt { // so as not to register to global extension val message = readUShortLVString() val errorInfo = readUShortLVString() - WtLogin.Login.LoginPacketResponse.Error(type, title, message, errorInfo) + WtLogin.Login.LoginPacketResponse.Error(bot, type, title, message, errorInfo) } } diff --git a/mirai-core/src/commonMain/kotlin/utils/RemoteFileImpl.kt b/mirai-core/src/commonMain/kotlin/utils/RemoteFileImpl.kt index 102c82d5c..d71865461 100644 --- a/mirai-core/src/commonMain/kotlin/utils/RemoteFileImpl.kt +++ b/mirai-core/src/commonMain/kotlin/utils/RemoteFileImpl.kt @@ -20,6 +20,7 @@ import net.mamoe.mirai.internal.contact.groupCode import net.mamoe.mirai.internal.message.FileMessageImpl import net.mamoe.mirai.internal.network.highway.Highway import net.mamoe.mirai.internal.network.highway.ResourceKind +import net.mamoe.mirai.internal.network.protocol import net.mamoe.mirai.internal.network.protocol.data.proto.* import net.mamoe.mirai.internal.network.protocol.packet.chat.FileManagement import net.mamoe.mirai.internal.network.protocol.packet.chat.toResult