mirror of
https://github.com/mamoe/mirai.git
synced 2025-04-24 20:43:33 +08:00
Support login cache and login without password. close #1158
This commit is contained in:
parent
455ed6fbeb
commit
f3d3130f2d
binary-compatibility-validator
mirai-core-api/src/commonMain/kotlin/utils
mirai-core-utils/src/commonMain/kotlin
mirai-core/src/commonMain/kotlin
MiraiImpl.ktQQAndroidBot.kt
network
utils
@ -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
|
||||
|
@ -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
|
||||
|
@ -485,6 +485,20 @@ public open class BotConfiguration { // open for Java
|
||||
contactListCache.groupMemberListCacheEnabled = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录缓存.
|
||||
*
|
||||
* 开始后在密码登录成功时会保存秘钥等信息, 在下次启动时通过这些信息登录, 而不提交密码.
|
||||
* 可以减少验证码出现的频率.
|
||||
*
|
||||
* 秘钥信息会由密码加密保存. 如果秘钥过期, 则会进行普通密码登录.
|
||||
*
|
||||
* 默认 `true` (开启).
|
||||
*
|
||||
* @since 2.6
|
||||
*/
|
||||
public var loginCacheEnabled: Boolean = true
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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()
|
||||
|
@ -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 <T> File.loadNotBlankAs(
|
||||
return stringFormat.decodeFromString(serializer, this.readText())
|
||||
}
|
||||
|
||||
public fun <T> File.loadNotBlankAs(
|
||||
serializer: DeserializationStrategy<T>,
|
||||
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) }
|
||||
|
@ -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
|
||||
|
@ -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<QQAndroidBotNetworkHandler>(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<WtLogin.Login.LoginPacketResponse> { 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
|
||||
|
83
mirai-core/src/commonMain/kotlin/network/AccountSecrets.kt
Normal file
83
mirai-core/src/commonMain/kotlin/network/AccountSecrets.kt
Normal file
@ -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<LoginExtraData>
|
||||
|
||||
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<LoginExtraData>,
|
||||
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),
|
||||
)
|
||||
}
|
@ -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<PendingGroupMessageReceiptSyncId>(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<LoginExtraData> = 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)
|
||||
|
@ -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
|
||||
|
@ -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<String, KeyWithExpiry> = 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<String, PSKey>
|
||||
internal typealias Pt4TokenMap = MutableMap<String, Pt4Token>
|
||||
|
||||
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<String, KeyWithExpiry>
|
||||
internal typealias Pt4TokenMap = MutableMap<String, KeyWithExpiry>
|
||||
|
||||
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)"
|
||||
|
@ -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())
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user