mirror of
https://github.com/mamoe/mirai.git
synced 2024-12-27 09:00:15 +08:00
[core] Add encryption SPI & T544 support (#2566)
* Initial design for encryption SPI & T544 support * Fix missed vararg * Move EncryptWorkerService to internal spi * Add useAndroid val to QQAndroidClient and rebase to the latest dev branch * Remove docs and annotations (Throws and MiraiExperimentalApi) * Remove unwanted changes * Remove redundant runBlocking in tlv544 * Tweak the file annotation location * Remove suspend modifier for doTLVEncrypt * Disable DebuggingProperties * Fix format * Remove empty line * Remove empty line again * Use instance field directly * Add Volatile annotation to instance * Use atomicRef instead of field * Use kotlin lambda for readability * wip * Improve EncryptService API * Add possible values * remove docs * Add key BOT_PROTOCOL --------- Co-authored-by: Him188 <Him188@mamoe.net>
This commit is contained in:
parent
68c991c078
commit
3ec8e552cd
@ -41,6 +41,7 @@ internal fun <T : BaseService> SpiServiceLoader(
|
||||
|
||||
internal interface SpiServiceLoader<T : BaseService?> {
|
||||
val service: T
|
||||
val allServices: List<T & Any>
|
||||
}
|
||||
|
||||
internal class SpiServiceLoaderImpl<T : BaseService?>(
|
||||
@ -52,9 +53,15 @@ internal class SpiServiceLoaderImpl<T : BaseService?>(
|
||||
}
|
||||
private val lock = SynchronizedObject()
|
||||
|
||||
override val service: T get() = _service
|
||||
override val service: T get() = _service.bestService
|
||||
override val allServices: List<T & Any> get() = _service.allServices
|
||||
|
||||
private var _service: T by lateinitMutableProperty {
|
||||
private class Loaded<T>(
|
||||
val bestService: T,
|
||||
val allServices: List<T & Any>,
|
||||
)
|
||||
|
||||
private var _service: Loaded<T> by lateinitMutableProperty {
|
||||
synchronized(lock) {
|
||||
reloadAndSelect()
|
||||
}
|
||||
@ -66,9 +73,12 @@ internal class SpiServiceLoaderImpl<T : BaseService?>(
|
||||
}
|
||||
}
|
||||
|
||||
private fun reloadAndSelect(): T {
|
||||
private fun reloadAndSelect(): Loaded<T> {
|
||||
val allServices = loadServices(serviceType).toList()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return (loadServices(serviceType).minByOrNull { it.priority } ?: defaultInstance) as T
|
||||
val bestService = (allServices.minByOrNull { it.priority } ?: defaultInstance) as T
|
||||
return Loaded(bestService, allServices)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -82,6 +82,10 @@ internal open class QQAndroidClient(
|
||||
override var outgoingPacketSessionId: ByteArray = 0x02B05B8B.toByteArray()
|
||||
override var loginState = 0
|
||||
|
||||
val useAndroid by lazy {
|
||||
bot.configuration.protocol == BotConfiguration.MiraiProtocol.ANDROID_PHONE ||
|
||||
bot.configuration.protocol == BotConfiguration.MiraiProtocol.ANDROID_PAD
|
||||
}
|
||||
var onlineStatus: OnlineStatus = OnlineStatus.ONLINE
|
||||
|
||||
var fileStoragePushFSSvcList: FileStoragePushFSSvcList? = null
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2023 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,8 @@ package net.mamoe.mirai.internal.network.protocol.packet
|
||||
import io.ktor.utils.io.core.*
|
||||
import net.mamoe.mirai.internal.network.*
|
||||
import net.mamoe.mirai.internal.network.protocol.LoginType
|
||||
import net.mamoe.mirai.internal.spi.EncryptService
|
||||
import net.mamoe.mirai.internal.spi.EncryptServiceContext
|
||||
import net.mamoe.mirai.internal.utils.GuidSource
|
||||
import net.mamoe.mirai.internal.utils.MacOrAndroidIdChangeFlag
|
||||
import net.mamoe.mirai.internal.utils.NetworkType
|
||||
@ -961,10 +963,55 @@ internal fun TlvMapWriter.t548(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun TlvMapWriter.t544( // 1334
|
||||
|
||||
internal fun TlvMapWriter.t544ForToken( // 1348
|
||||
uin: Long,
|
||||
guid: ByteArray,
|
||||
sdkVersion: String,
|
||||
subCommandId: Int,
|
||||
commandStr: String
|
||||
) {
|
||||
val service = EncryptService.instance ?: return
|
||||
tlv(0x544) {
|
||||
writeFully(byteArrayOf(0, 0, 0, 11)) // means native throws exception
|
||||
buildPacket {
|
||||
writeFully(buildPacket {
|
||||
writeLong(uin)
|
||||
}.readBytes(4))
|
||||
writeShortLVByteArray(guid)
|
||||
writeShortLVString(sdkVersion)
|
||||
writeInt(subCommandId)
|
||||
writeInt(0)
|
||||
}.use { dataIn ->
|
||||
service.encryptTlv(EncryptServiceContext(uin, buildTypeSafeMap {
|
||||
set(EncryptServiceContext.KEY_COMMAND_STR, commandStr)
|
||||
}), 0x544, dataIn.readBytes())
|
||||
}.let { result ->
|
||||
writeFully(result ?: "".toByteArray()) // Empty str means native throws exception
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun TlvMapWriter.t544ForVerify( // 1348
|
||||
uin: Long,
|
||||
guid: ByteArray,
|
||||
sdkVersion: String,
|
||||
subCommandId: Int,
|
||||
commandStr: String
|
||||
) {
|
||||
val service = EncryptService.instance ?: return
|
||||
tlv(0x544) {
|
||||
buildPacket {
|
||||
writeLong(uin)
|
||||
writeShortLVByteArray(guid)
|
||||
writeShortLVString(sdkVersion)
|
||||
writeInt(subCommandId)
|
||||
}.use { dataIn ->
|
||||
service.encryptTlv(EncryptServiceContext(uin, buildTypeSafeMap {
|
||||
set(EncryptServiceContext.KEY_COMMAND_STR, commandStr)
|
||||
}), 0x544, dataIn.readBytes())
|
||||
}.let { result ->
|
||||
writeFully(result ?: "".toByteArray()) // Empty str means native throws exception
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,15 @@ internal object WtLogin10 : WtLoginExt {
|
||||
t194(client.device.imsiMd5)
|
||||
t511()
|
||||
t202(client.device.wifiBSSID, client.device.wifiSSID)
|
||||
//t544()
|
||||
if (client.useAndroid) {
|
||||
t544ForToken(
|
||||
uin = client.uin,
|
||||
guid = client.device.guid,
|
||||
sdkVersion = client.sdkVersion,
|
||||
subCommandId = 10,
|
||||
commandStr = "810_a"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -135,7 +135,15 @@ internal object WtLogin15 : WtLoginExt {
|
||||
|
||||
t521() // new
|
||||
t525(client.loginExtraData) // new
|
||||
//t544() // new 810_f
|
||||
if (client.useAndroid) {
|
||||
t544ForToken(
|
||||
uin = client.uin,
|
||||
guid = client.device.guid,
|
||||
sdkVersion = client.sdkVersion,
|
||||
subCommandId = 15,
|
||||
commandStr = "810_f"
|
||||
)
|
||||
}
|
||||
t545(client.qimei16 ?: client.device.imei)
|
||||
}
|
||||
}
|
||||
|
@ -10,12 +10,9 @@
|
||||
package net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin
|
||||
|
||||
import io.ktor.utils.io.core.*
|
||||
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||
import net.mamoe.mirai.internal.network.miscBitMap
|
||||
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.network.subAppId
|
||||
import net.mamoe.mirai.internal.network.subSigMap
|
||||
import net.mamoe.mirai.utils._writeTlvMap
|
||||
|
||||
|
||||
@ -34,6 +31,15 @@ internal object WtLogin2 : WtLoginExt {
|
||||
t104(client.t104)
|
||||
t116(client.miscBitMap, client.subSigMap)
|
||||
client.t547?.let { t547(it) }
|
||||
if (client.useAndroid) {
|
||||
t544ForVerify(
|
||||
uin = client.uin,
|
||||
guid = client.device.guid,
|
||||
sdkVersion = client.sdkVersion,
|
||||
subCommandId = 2,
|
||||
commandStr = "810_2"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -54,6 +60,15 @@ internal object WtLogin2 : WtLoginExt {
|
||||
t104(client.t104)
|
||||
t116(client.miscBitMap, client.subSigMap)
|
||||
client.t547?.let { t547(it) }
|
||||
if (client.useAndroid) {
|
||||
t544ForVerify(
|
||||
uin = client.uin,
|
||||
guid = client.device.guid,
|
||||
sdkVersion = client.sdkVersion,
|
||||
subCommandId = 2,
|
||||
commandStr = "810_2"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,12 +10,9 @@
|
||||
package net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin
|
||||
|
||||
import io.ktor.utils.io.core.*
|
||||
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||
import net.mamoe.mirai.internal.network.miscBitMap
|
||||
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.network.subAppId
|
||||
import net.mamoe.mirai.internal.network.subSigMap
|
||||
import net.mamoe.mirai.utils.DeviceVerificationRequests
|
||||
import net.mamoe.mirai.utils._writeTlvMap
|
||||
|
||||
@ -44,6 +41,15 @@ internal object WtLogin7 : WtLoginExt {
|
||||
t17c(code.encodeToByteArray())
|
||||
t401(client.G)
|
||||
t198()
|
||||
if (client.useAndroid) {
|
||||
t544ForVerify(
|
||||
uin = client.uin,
|
||||
guid = client.device.guid,
|
||||
sdkVersion = client.sdkVersion,
|
||||
subCommandId = 7,
|
||||
commandStr = "810_7"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,6 +134,15 @@ internal object WtLogin9 : WtLoginExt {
|
||||
// this.build().debugPrint("傻逼")
|
||||
|
||||
// ignored t318 because not logging in by QR
|
||||
if (client.useAndroid) {
|
||||
t544ForToken(
|
||||
uin = client.uin,
|
||||
guid = client.device.guid,
|
||||
sdkVersion = client.sdkVersion,
|
||||
subCommandId = 9,
|
||||
commandStr = "810_9"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
56
mirai-core/src/commonMain/kotlin/spi/EncryptService.kt
Normal file
56
mirai-core/src/commonMain/kotlin/spi/EncryptService.kt
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2019-2023 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/dev/LICENSE
|
||||
*/
|
||||
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
|
||||
package net.mamoe.mirai.internal.spi
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.spi.BaseService
|
||||
import net.mamoe.mirai.spi.SpiServiceLoader
|
||||
import net.mamoe.mirai.utils.BotConfiguration
|
||||
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||
import net.mamoe.mirai.utils.TypeKey
|
||||
import net.mamoe.mirai.utils.TypeSafeMap
|
||||
|
||||
|
||||
/**
|
||||
* @since 2.15.0
|
||||
*/
|
||||
public class EncryptServiceContext @MiraiInternalApi constructor(
|
||||
/**
|
||||
* [Bot.id]
|
||||
*/
|
||||
public val id: Long,
|
||||
public val extraArgs: TypeSafeMap = TypeSafeMap.EMPTY
|
||||
) {
|
||||
public companion object {
|
||||
public val KEY_COMMAND_STR: TypeKey<String> = TypeKey("KEY_COMMAND_STR")
|
||||
public val KEY_BOT_PROTOCOL: TypeKey<BotConfiguration.MiraiProtocol> = TypeKey("BOT_PROTOCOL")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.15.0
|
||||
*/
|
||||
public interface EncryptService : BaseService {
|
||||
/**
|
||||
* Returns `null` if not supported.
|
||||
*/
|
||||
public fun encryptTlv(
|
||||
context: EncryptServiceContext,
|
||||
tlvType: Int,
|
||||
payload: ByteArray, // Do not write to payload
|
||||
): ByteArray?
|
||||
|
||||
public companion object {
|
||||
private val loader = SpiServiceLoader(EncryptService::class)
|
||||
|
||||
internal val instance: EncryptService? get() = loader.service
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user