Simplify DeviceInfo (#655)

* Simplify DeviceInfo

* Place random string helper properly

* Make DeviceInfo::random java-friendly
This commit is contained in:
AdoptOSS 2020-10-27 08:57:28 +08:00 committed by GitHub
parent 54df8d63aa
commit bb3d039bf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 170 additions and 240 deletions

View File

@ -53,7 +53,7 @@ public expect open class BotConfiguration() : BotConfigurationBase {
public fun randomDeviceInfo()
/**
* 使用特定由 [DeviceInfoData] 序列化产生的 JSON 的设备信息
* 使用特定由 [DeviceInfo] 序列化产生的 JSON 的设备信息
*
* @see deviceInfo
*/
@ -251,5 +251,5 @@ internal val deviceInfoStub: (Context) -> DeviceInfo = {
MiraiLogger.warning("未指定设备信息, 已使用随机设备信息. 请查看 BotConfiguration.deviceInfo 以获取更多信息.")
@Suppress("DEPRECATION")
MiraiLogger.warning("Device info isn't specified. Please refer to BotConfiguration.deviceInfo for more information")
SystemDeviceInfo()
DeviceInfo.random()
}

View File

@ -9,124 +9,106 @@
package net.mamoe.mirai.utils
import kotlinx.io.core.toByteArray
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.protobuf.ProtoBuf
import kotlinx.serialization.protobuf.ProtoNumber
import net.mamoe.mirai.utils.internal.getRandomByteArray
import net.mamoe.mirai.utils.internal.getRandomIntString
import net.mamoe.mirai.utils.internal.getRandomString
import net.mamoe.mirai.utils.internal.md5
import kotlin.jvm.JvmStatic
/**
* 设备信息. 可通过继承 [SystemDeviceInfo] 来在默认的基础上修改
*/
public abstract class DeviceInfo {
@Transient
public abstract val context: Context
public abstract val display: ByteArray
public abstract val product: ByteArray
public abstract val device: ByteArray
public abstract val board: ByteArray
public abstract val brand: ByteArray
public abstract val model: ByteArray
public abstract val bootloader: ByteArray
public abstract val fingerprint: ByteArray
public abstract val bootId: ByteArray
public abstract val procVersion: ByteArray
public abstract val baseBand: ByteArray
public abstract val version: Version
public abstract val simInfo: ByteArray
public abstract val osType: ByteArray
public abstract val macAddress: ByteArray
public abstract val wifiBSSID: ByteArray?
public abstract val wifiSSID: ByteArray?
public abstract val imsiMd5: ByteArray
public abstract val imei: String
@Serializable
public class DeviceInfo(
public val display: ByteArray,
public val product: ByteArray,
public val device: ByteArray,
public val board: ByteArray,
public val brand: ByteArray,
public val model: ByteArray,
public val bootloader: ByteArray,
public val fingerprint: ByteArray,
public val bootId: ByteArray,
public val procVersion: ByteArray,
public val baseBand: ByteArray,
public val version: Version,
public val simInfo: ByteArray,
public val osType: ByteArray,
public val macAddress: ByteArray,
public val wifiBSSID: ByteArray?,
public val wifiSSID: ByteArray?,
public val imsiMd5: ByteArray,
public val imei: String,
public val apn: ByteArray
) {
public val androidId: ByteArray get() = display
public val ipAddress: ByteArray get() = byteArrayOf(192.toByte(), 168.toByte(), 1, 123)
public abstract val androidId: ByteArray
@Serializable
public class Version(
public val incremental: ByteArray = "5891938".toByteArray(),
public val release: ByteArray = "10".toByteArray(),
public val codename: ByteArray = "REL".toByteArray(),
public val sdk: Int = 29
)
public abstract val apn: ByteArray
public fun generateDeviceInfoData(): ByteArray {
@Serializable
class DevInfo(
@ProtoNumber(1) val bootloader: ByteArray,
@ProtoNumber(2) val procVersion: ByteArray,
@ProtoNumber(3) val codename: ByteArray,
@ProtoNumber(4) val incremental: ByteArray,
@ProtoNumber(5) val fingerprint: ByteArray,
@ProtoNumber(6) val bootId: ByteArray,
@ProtoNumber(7) val androidId: ByteArray,
@ProtoNumber(8) val baseBand: ByteArray,
@ProtoNumber(9) val innerVersion: ByteArray
)
return ProtoBuf.encodeToByteArray(
DevInfo.serializer(), DevInfo(
bootloader,
procVersion,
version.codename,
version.incremental,
fingerprint,
bootId,
androidId,
baseBand,
version.incremental
public companion object {
@JvmStatic
public fun random(): DeviceInfo {
return DeviceInfo(
display = "MIRAI.${getRandomString(6, '0'..'9')}.001".toByteArray(),
product = "mirai".toByteArray(),
device = "mirai".toByteArray(),
board = "mirai".toByteArray(),
brand = "mamoe".toByteArray(),
model = "mirai".toByteArray(),
bootloader = "unknown".toByteArray(),
fingerprint = "mamoe/mirai/mirai:10/MIRAI.200122.001/${getRandomIntString(7)}:user/release-keys".toByteArray(),
bootId = ExternalImage.generateUUID(getRandomByteArray(16).md5()).toByteArray(),
procVersion = "Linux version 3.0.31-${getRandomString(8)} (android-build@xxx.xxx.xxx.xxx.com)".toByteArray(),
baseBand = byteArrayOf(),
version = Version(),
simInfo = "T-Mobile".toByteArray(),
osType = "android".toByteArray(),
macAddress = "02:00:00:00:00:00".toByteArray(),
wifiBSSID = "02:00:00:00:00:00".toByteArray(),
wifiSSID = "<unknown ssid>".toByteArray(),
imsiMd5 = getRandomByteArray(16).md5(),
imei = getRandomIntString(15),
apn = "wifi".toByteArray()
)
)
}
public interface Version {
public val incremental: ByteArray
public val release: ByteArray
public val codename: ByteArray
public val sdk: Int
}
}
}
@Serializable
public class DeviceInfoData(
public override val display: ByteArray,
public override val product: ByteArray,
public override val device: ByteArray,
public override val board: ByteArray,
public override val brand: ByteArray,
public override val model: ByteArray,
public override val bootloader: ByteArray,
public override val fingerprint: ByteArray,
public override val bootId: ByteArray,
public override val procVersion: ByteArray,
public override val baseBand: ByteArray,
public override val version: VersionData,
public override val simInfo: ByteArray,
public override val osType: ByteArray,
public override val macAddress: ByteArray,
public override val wifiBSSID: ByteArray?,
public override val wifiSSID: ByteArray?,
public override val imsiMd5: ByteArray,
public override val imei: String,
public override val apn: ByteArray
) : DeviceInfo() {
@Transient
public override lateinit var context: Context
public override val androidId: ByteArray get() = display
public fun DeviceInfo.generateDeviceInfoData(): ByteArray {
@Serializable
public class VersionData(
public override val incremental: ByteArray = SystemDeviceInfo.Version.incremental,
public override val release: ByteArray = SystemDeviceInfo.Version.release,
public override val codename: ByteArray = SystemDeviceInfo.Version.codename,
public override val sdk: Int = SystemDeviceInfo.Version.sdk
) : Version
class DevInfo(
@ProtoNumber(1) val bootloader: ByteArray,
@ProtoNumber(2) val procVersion: ByteArray,
@ProtoNumber(3) val codename: ByteArray,
@ProtoNumber(4) val incremental: ByteArray,
@ProtoNumber(5) val fingerprint: ByteArray,
@ProtoNumber(6) val bootId: ByteArray,
@ProtoNumber(7) val androidId: ByteArray,
@ProtoNumber(8) val baseBand: ByteArray,
@ProtoNumber(9) val innerVersion: ByteArray
)
return ProtoBuf.encodeToByteArray(
DevInfo.serializer(), DevInfo(
bootloader,
procVersion,
version.codename,
version.incremental,
fingerprint,
bootId,
androidId,
baseBand,
version.incremental
)
)
}
/*

View File

@ -1,23 +0,0 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.utils
/**
* 通过本机信息来获取设备信息.
*
* Android: 获取手机信息, QQ 官方相同.
* JVM: 部分为常量, 部分为随机
*/
public expect open class SystemDeviceInfo : DeviceInfo {
public constructor()
public constructor(context: Context)
public object Version : DeviceInfo.Version
}

View File

@ -0,0 +1,49 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.utils.internal
import kotlin.jvm.JvmSynthetic
import kotlin.random.Random
import kotlin.random.nextInt
/**
* 生成长度为 [length], 元素为随机 `0..255` [ByteArray]
*/
@JvmSynthetic
internal fun getRandomByteArray(length: Int): ByteArray = ByteArray(length) { Random.nextInt(0..255).toByte() }
/**
* 随机生成长度为 [length] [String].
*/
@JvmSynthetic
internal fun getRandomString(length: Int): String =
getRandomString(length, *defaultRanges)
private val defaultRanges: Array<CharRange> = arrayOf('a'..'z', 'A'..'Z', '0'..'9')
private val intCharRanges: Array<CharRange> = arrayOf('0'..'9')
/**
* 根据所给 [charRange] 随机生成长度为 [length] [String].
*/
@JvmSynthetic
internal fun getRandomString(length: Int, charRange: CharRange): String =
CharArray(length) { charRange.random() }.concatToString()
/**
* 根据所给 [charRanges] 随机生成长度为 [length] [String].
*/
@JvmSynthetic
internal fun getRandomString(length: Int, vararg charRanges: CharRange): String =
CharArray(length) { charRanges[Random.Default.nextInt(0..charRanges.lastIndex)].random() }.concatToString()
@JvmSynthetic
internal fun getRandomIntString(length: Int): String =
getRandomString(length, *intCharRanges)

View File

@ -57,14 +57,14 @@ public actual open class BotConfiguration : BotConfigurationBase() { // open for
}
/**
* 使用特定由 [DeviceInfoData] 序列化产生的 JSON 的设备信息
* 使用特定由 [DeviceInfo] 序列化产生的 JSON 的设备信息
*
* @see deviceInfo
*/
@SinceMirai("1.2.0")
public actual fun loadDeviceInfoJson(json: String) {
deviceInfo = { context ->
this.json.decodeFromString(DeviceInfoData.serializer(), json).also { it.context = context }
this.json.decodeFromString(DeviceInfo.serializer(), json)
}
}

View File

@ -0,0 +1,25 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.utils
import kotlinx.serialization.json.Json
import java.io.File
/**
* 加载一个设备信息. 若文件不存在或为空则随机并创建一个设备信息保存.
*/
public fun File.loadAsDeviceInfo(json: Json): DeviceInfo {
if (!this.exists() || this.length() == 0L) {
return DeviceInfo.random().also {
this.writeText(json.encodeToString(DeviceInfo.serializer(), it))
}
}
return json.decodeFromString(DeviceInfo.serializer(), this.readText())
}

View File

@ -154,7 +154,7 @@ public actual abstract class LoginSolver {
internal fun BotConfiguration.getFileBasedDeviceInfoSupplier(filename: String): ((Context) -> DeviceInfo)? {
return {
File(filename).loadAsDeviceInfo(json, it)
File(filename).loadAsDeviceInfo(json)
}
}

View File

@ -1,104 +0,0 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.utils
import kotlinx.io.core.toByteArray
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.json.Json
import net.mamoe.mirai.utils.internal.md5
import java.io.File
import kotlin.random.Random
import kotlin.random.nextInt
/**
* 加载一个设备信息. 若文件不存在或为空则随机并创建一个设备信息保存.
*/
public fun File.loadAsDeviceInfo(json: Json, context: Context = ContextImpl()): DeviceInfo {
if (!this.exists() || this.length() == 0L) {
return SystemDeviceInfo(context).also {
this.writeText(json.encodeToString(SystemDeviceInfo.serializer(), it))
}
}
return json.decodeFromString(DeviceInfoData.serializer(), this.readText()).also {
it.context = context
}
}
@Serializable
public actual open class SystemDeviceInfo actual constructor() : DeviceInfo() {
public actual constructor(context: Context) : this() {
this.context = context
}
@Transient
public final override lateinit var context: Context
public override val display: ByteArray = "MIRAI.${getRandomString(6, '0'..'9')}.001".toByteArray()
public override val product: ByteArray = "mirai".toByteArray()
public override val device: ByteArray = "mirai".toByteArray()
public override val board: ByteArray = "mirai".toByteArray()
public override val brand: ByteArray = "mamoe".toByteArray()
public override val model: ByteArray = "mirai".toByteArray()
public override val bootloader: ByteArray = "unknown".toByteArray()
public override val fingerprint: ByteArray =
"mamoe/mirai/mirai:10/MIRAI.200122.001/${getRandomString(7, '0'..'9')}:user/release-keys".toByteArray()
public override val bootId: ByteArray = ExternalImage.generateUUID(getRandomByteArray(16).md5()).toByteArray()
public override val procVersion: ByteArray =
"Linux version 3.0.31-${getRandomString(8)} (android-build@xxx.xxx.xxx.xxx.com)".toByteArray()
public override val baseBand: ByteArray = byteArrayOf()
public override val version: Version = Version
public override val simInfo: ByteArray = "T-Mobile".toByteArray()
public override val osType: ByteArray = "android".toByteArray()
public override val macAddress: ByteArray = "02:00:00:00:00:00".toByteArray()
public override val wifiBSSID: ByteArray? = "02:00:00:00:00:00".toByteArray()
public override val wifiSSID: ByteArray? = "<unknown ssid>".toByteArray()
public override val imsiMd5: ByteArray = getRandomByteArray(16).md5()
public override val imei: String = getRandomString(15, '0'..'9')
public override val androidId: ByteArray get() = display
public override val apn: ByteArray = "wifi".toByteArray()
@Serializable
public actual object Version : DeviceInfo.Version {
public override val incremental: ByteArray = "5891938".toByteArray()
public override val release: ByteArray = "10".toByteArray()
public override val codename: ByteArray = "REL".toByteArray()
public override val sdk: Int = 29
}
}
/**
* 生成长度为 [length], 元素为随机 `0..255` [ByteArray]
*/
@JvmSynthetic
internal fun getRandomByteArray(length: Int): ByteArray = ByteArray(length) { Random.nextInt(0..255).toByte() }
/**
* 随机生成长度为 [length] [String].
*/
@JvmSynthetic
internal fun getRandomString(length: Int): String =
getRandomString(length, *defaultRanges)
private val defaultRanges: Array<CharRange> = arrayOf('a'..'z', 'A'..'Z', '0'..'9')
/**
* 根据所给 [charRange] 随机生成长度为 [length] [String].
*/
@JvmSynthetic
internal fun getRandomString(length: Int, charRange: CharRange): String =
String(CharArray(length) { charRange.random() })
/**
* 根据所给 [charRanges] 随机生成长度为 [length] [String].
*/
@JvmSynthetic
internal fun getRandomString(length: Int, vararg charRanges: CharRange): String =
String(CharArray(length) { charRanges[Random.Default.nextInt(0..charRanges.lastIndex)].random() })

View File

@ -264,7 +264,7 @@ internal abstract class QQAndroidBotBase constructor(
context,
account,
bot = @Suppress("LeakingThis") this as QQAndroidBot,
device = configuration.deviceInfo?.invoke(context) ?: SystemDeviceInfo(context)
device = configuration.deviceInfo?.invoke(context) ?: DeviceInfo.random()
)
internal var firstLoginSucceed: Boolean = false

View File

@ -75,7 +75,7 @@ internal open class QQAndroidClient(
context: Context,
val account: BotAccount,
val ecdh: ECDH = ECDH(),
val device: DeviceInfo = SystemDeviceInfo(context),
val device: DeviceInfo,
bot: QQAndroidBot
) {
@Suppress("INVISIBLE_MEMBER")

View File

@ -21,6 +21,7 @@ import net.mamoe.mirai.internal.utils.guidFlag
import net.mamoe.mirai.internal.utils.io.*
import net.mamoe.mirai.utils.currentTimeSeconds
import net.mamoe.mirai.utils.error
import net.mamoe.mirai.utils.generateDeviceInfoData
internal class WtLogin {
/**