From 32e854db299f32895e22e47d03c9dad158a89e15 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Fri, 14 Feb 2020 21:09:36 +0800
Subject: [PATCH] Improve DeviceInfo

---
 .../net/mamoe/mirai/utils/SystemDeviceInfo.kt |  13 ++-
 .../net.mamoe.mirai/utils/BotConfiguration.kt |   2 +-
 .../net.mamoe.mirai/utils/DeviceInfo.kt       |   9 +-
 .../net.mamoe.mirai/utils/SystemDeviceInfo.kt |   8 +-
 .../net/mamoe/mirai/utils/SystemDeviceInfo.kt | 105 ++++++++++++++----
 5 files changed, 103 insertions(+), 34 deletions(-)

diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt
index b20ffbca2..30e01dc1b 100644
--- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt
+++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt
@@ -14,13 +14,23 @@ import android.net.wifi.WifiManager
 import android.os.Build
 import android.telephony.TelephonyManager
 import kotlinx.io.core.toByteArray
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.Transient
 import java.io.File
 
 /**
  * 部分引用指向 [Build].
  * 部分需要权限, 若无权限则会使用默认值.
  */
-actual open class SystemDeviceInfo actual constructor(context: Context) : DeviceInfo(context) {
+@Serializable
+actual open class SystemDeviceInfo actual constructor() : DeviceInfo() {
+    actual constructor(context: Context) : this() {
+        this.context = context
+    }
+
+    @Transient
+    final override lateinit var context: Context
+
     override val display: ByteArray get() = Build.DISPLAY.toByteArray()
     override val product: ByteArray get() = Build.PRODUCT.toByteArray()
     override val device: ByteArray get() = Build.DEVICE.toByteArray()
@@ -88,6 +98,7 @@ actual open class SystemDeviceInfo actual constructor(context: Context) : Device
     override val androidId: ByteArray get() = Build.ID.toByteArray()
     override val apn: ByteArray get() = "wifi".toByteArray()
 
+    @Serializable
     object Version : DeviceInfo.Version {
         override val incremental: ByteArray get() = Build.VERSION.INCREMENTAL.toByteArray()
         override val release: ByteArray get() = Build.VERSION.RELEASE.toByteArray()
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt
index 899f3d177..b23e274d6 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt
@@ -45,7 +45,7 @@ class BotConfiguration {
      */
     var networkLoggerSupplier: ((BotNetworkHandler) -> MiraiLogger) = { DefaultLogger("Network(${it.bot.uin})") }
     /**
-     * 设备信息覆盖
+     * 设备信息覆盖. 默认使用随机的设备信息.
      */
     var deviceInfo: ((Context) -> DeviceInfo)? = null
 
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DeviceInfo.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DeviceInfo.kt
index 89e76eabe..491b952fe 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DeviceInfo.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DeviceInfo.kt
@@ -11,16 +11,15 @@ package net.mamoe.mirai.utils
 
 import kotlinx.serialization.SerialId
 import kotlinx.serialization.Serializable
+import kotlinx.serialization.Transient
 import kotlinx.serialization.protobuf.ProtoBuf
-import net.mamoe.mirai.utils.cryptor.contentToString
 
 /**
  * 设备信息. 可通过继承 [SystemDeviceInfo] 来在默认的基础上修改
  */
-abstract class DeviceInfo internal constructor(
-    context: Context
-) {
-    val context: Context by context.unsafeWeakRef()
+abstract class DeviceInfo {
+    @Transient
+    abstract val context: Context
 
     abstract val display: ByteArray
     abstract val product: ByteArray
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SystemDeviceInfo.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SystemDeviceInfo.kt
index ef4780220..bd4f0b259 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SystemDeviceInfo.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SystemDeviceInfo.kt
@@ -9,13 +9,13 @@
 
 package net.mamoe.mirai.utils
 
-import net.mamoe.mirai.utils.Context
-import net.mamoe.mirai.utils.DeviceInfo
-
 /**
  * 通过本机信息来获取设备信息.
  *
  * Android: 获取手机信息, 与 QQ 官方相同.
  * JVM: 部分为常量, 部分为随机
  */
-open expect class SystemDeviceInfo(context: Context) : DeviceInfo
\ No newline at end of file
+expect open class SystemDeviceInfo : DeviceInfo {
+    constructor()
+    constructor(context: Context)
+}
\ No newline at end of file
diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt
index 217b202ce..b1274bdaf 100644
--- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt
+++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt
@@ -10,38 +10,97 @@
 package net.mamoe.mirai.utils
 
 import kotlinx.io.core.toByteArray
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.Transient
+import kotlinx.serialization.UnstableDefault
+import kotlinx.serialization.json.Json
 import net.mamoe.mirai.utils.io.getRandomByteArray
 import net.mamoe.mirai.utils.io.getRandomString
+import java.io.File
 
+/**
+ * 加载或创建一个设备信息.
+ */
+@UseExperimental(UnstableDefault::class)
+fun File.loadAsDeviceInfo(context: Context = ContextImpl()): DeviceInfo {
+    if (!this.exists() || this.length() == 0L) {
+        return SystemDeviceInfo(context).also {
+            this.writeText(Json.plain.stringify(SystemDeviceInfo.serializer(), it))
+        }
+    }
+    return Json.nonstrict.parse(DeviceInfoData.serializer(), this.readText()).also {
+        it.context = context
+    }
+}
+
+
+@Serializable
 @UseExperimental(ExperimentalUnsignedTypes::class)
-actual open class SystemDeviceInfo actual constructor(context: Context) : DeviceInfo(context) {
-    override val display: ByteArray get() = "MIRAI.200122.001".toByteArray()
-    override val product: ByteArray get() = "mirai".toByteArray()
-    override val device: ByteArray get() = "mirai".toByteArray()
-    override val board: ByteArray get() = "mirai".toByteArray()
-    override val brand: ByteArray get() = "mamoe".toByteArray()
-    override val model: ByteArray get() = "mirai".toByteArray()
-    override val bootloader: ByteArray get() = "unknown".toByteArray()
-    override val fingerprint: ByteArray get() = "mamoe/mirai/mirai:10/MIRAI.200122.001/5891938:user/release-keys".toByteArray()
+actual open class SystemDeviceInfo actual constructor() : DeviceInfo() {
+    actual constructor(context: Context) : this() {
+        this.context = context
+    }
+
+    @Transient
+    final override lateinit var context: Context
+
+    override val display: ByteArray = "MIRAI.200122.001".toByteArray()
+    override val product: ByteArray = "mirai".toByteArray()
+    override val device: ByteArray = "mirai".toByteArray()
+    override val board: ByteArray = "mirai".toByteArray()
+    override val brand: ByteArray = "mamoe".toByteArray()
+    override val model: ByteArray = "mirai".toByteArray()
+    override val bootloader: ByteArray = "unknown".toByteArray()
+    override val fingerprint: ByteArray = "mamoe/mirai/mirai:10/MIRAI.200122.001/${getRandomString(7, '0'..'9')}:user/release-keys".toByteArray()
     override val bootId: ByteArray = ExternalImage.generateUUID(md5(getRandomByteArray(16))).toByteArray()
-    override val procVersion: ByteArray get() = "Linux version 3.0.31-g6fb96c9 (android-build@xxx.xxx.xxx.xxx.com)".toByteArray()
-    override val baseBand: ByteArray get() = byteArrayOf()
+    override val procVersion: ByteArray = "Linux version 3.0.31-${getRandomString(8)} (android-build@xxx.xxx.xxx.xxx.com)".toByteArray()
+    override val baseBand: ByteArray = byteArrayOf()
     override val version: DeviceInfo.Version get() = Version
-    override val simInfo: ByteArray get() = "T-Mobile".toByteArray()
-    override val osType: ByteArray get() = "android".toByteArray()
-    override val macAddress: ByteArray get() = "02:00:00:00:00:00".toByteArray()
-    override val wifiBSSID: ByteArray? get() = "02:00:00:00:00:00".toByteArray()
-    override val wifiSSID: ByteArray? get() = "<unknown ssid>".toByteArray()
-    override val imsiMd5: ByteArray get() = md5(getRandomByteArray(16))
-    override val imei: String get() = getRandomString(15, '0'..'9')
+    override val simInfo: ByteArray = "T-Mobile".toByteArray()
+    override val osType: ByteArray = "android".toByteArray()
+    override val macAddress: ByteArray = "02:00:00:00:00:00".toByteArray()
+    override val wifiBSSID: ByteArray? = "02:00:00:00:00:00".toByteArray()
+    override val wifiSSID: ByteArray? = "<unknown ssid>".toByteArray()
+    override val imsiMd5: ByteArray = md5(getRandomByteArray(16))
+    override val imei: String = getRandomString(15, '0'..'9')
     override val ipAddress: ByteArray get() = localIpAddress().split(".").map { it.toUByte().toByte() }.takeIf { it.size == 4 }?.toByteArray() ?: byteArrayOf()
     override val androidId: ByteArray get() = display
-    override val apn: ByteArray get() = "wifi".toByteArray()
+    override val apn: ByteArray = "wifi".toByteArray()
 
+    @Serializable
     object Version : DeviceInfo.Version {
-        override val incremental: ByteArray get() = "5891938".toByteArray()
-        override val release: ByteArray get() = "10".toByteArray()
-        override val codename: ByteArray get() = "REL".toByteArray()
-        override val sdk: Int get() = 29
+        override val incremental: ByteArray = "5891938".toByteArray()
+        override val release: ByteArray = "10".toByteArray()
+        override val codename: ByteArray = "REL".toByteArray()
+        override val sdk: Int = 29
     }
+}
+
+@Serializable
+class DeviceInfoData(
+    override val display: ByteArray,
+    override val product: ByteArray,
+    override val device: ByteArray,
+    override val board: ByteArray,
+    override val brand: ByteArray,
+    override val model: ByteArray,
+    override val bootloader: ByteArray,
+    override val fingerprint: ByteArray,
+    override val bootId: ByteArray,
+    override val procVersion: ByteArray,
+    override val baseBand: ByteArray,
+    override val version: Version,
+    override val simInfo: ByteArray,
+    override val osType: ByteArray,
+    override val macAddress: ByteArray,
+    override val wifiBSSID: ByteArray?,
+    override val wifiSSID: ByteArray?,
+    override val imsiMd5: ByteArray,
+    override val imei: String,
+    override val ipAddress: ByteArray,
+    override val androidId: ByteArray,
+    override val apn: ByteArray
+) : DeviceInfo() {
+    @Transient
+    override lateinit var context: Context
 }
\ No newline at end of file