diff --git a/build.gradle b/build.gradle index 7ab059651..ce4dfd3b8 100644 --- a/build.gradle +++ b/build.gradle @@ -19,6 +19,7 @@ allprojects { version = "1.0" repositories { + jcenter()//klock google() maven { url "https://mirrors.huaweicloud.com/repository/maven/" } } diff --git a/dependencies.gradle b/dependencies.gradle index a36a8788c..225a24ea6 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -30,4 +30,5 @@ ext { kotlinxIOJS = "org.jetbrains.kotlinx:kotlinx-io-js:$kotlinx_io_version" kotlinxIONative = "org.jetbrains.kotlinx:kotlinx-io-native:$kotlinx_io_version" + klock = "com.soywiz.korlibs.klock:klock:1.7.0" } diff --git a/mirai-core/build.gradle b/mirai-core/build.gradle index da83aab15..e0d3dbd42 100644 --- a/mirai-core/build.gradle +++ b/mirai-core/build.gradle @@ -35,6 +35,7 @@ kotlin { implementation rootProject.ext.atomicFUCommon implementation rootProject.ext.kotlinxIOCommon + implementation rootProject.ext.klock } } @@ -51,6 +52,7 @@ kotlin { implementation 'org.yaml:snakeyaml:1.18' implementation 'org.jsoup:jsoup:1.12.1' implementation 'org.ini4j:ini4j:0.5.2' + implementation rootProject.ext.klock } } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt index 11205f135..582393ff5 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt @@ -14,8 +14,6 @@ import net.mamoe.mirai.utils.toUHexString /** * The mirror of functions in inner classes of [Bot] - * - * @author Him188moe */ //Contacts diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt index ffd657bf8..51fee80f9 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt @@ -147,7 +147,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : val expect = expectPacket() NetworkScope.launch { processReceive() } NetworkScope.launch { - if (withTimeoutOrNull(configuration.touchTimeoutMillis) { expect.join() } == null) { + if (withTimeoutOrNull(configuration.touchTimeout.millisecondsLong) { expect.join() } == null) { loginResult.complete(LoginResult.TIMEOUT) } } @@ -342,7 +342,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : this.token00BA = packet.token00BA this.captchaCache = packet.captchaPart1 - if (packet.unknownBoolean == true) { + if (packet.unknownBoolean) { this.captchaSectionId = 1 socket.sendPacket(ClientCaptchaTransmissionRequestPacket(bot.qqAccount, this.token0825, this.captchaSectionId++, packet.token00BA)) } @@ -403,11 +403,11 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : heartbeatJob = NetworkScope.launch { while (socket.isOpen) { - delay(configuration.heartbeatPeriodMillis) + delay(configuration.heartbeatPeriod.millisecondsLong) with(session) { class HeartbeatTimeoutException : CancellationException("heartbeat timeout") - if (withTimeoutOrNull(configuration.heartbeatTimeoutMillis) { + if (withTimeoutOrNull(configuration.heartbeatTimeout.millisecondsLong) { ClientHeartbeatPacket(bot.qqAccount, sessionKey).sendAndExpect {} } == null) { bot.logPurple("Heartbeat timed out") diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMProtocol.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMProtocol.kt index 3562b4446..70c81be15 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMProtocol.kt @@ -20,7 +20,7 @@ object TIMProtocol { ).forEach { list.add(solveIpAddress(it)) } list.toList() - }() + }()//不使用lazy是为了在启动时就加载. const val head = "02" const val ver = "37 13" @@ -36,6 +36,9 @@ object TIMProtocol { const val constantData1 = "00 18 00 16 00 01 " const val constantData2 = "00 00 04 53 00 00 00 01 00 00 15 85 " + + //todo 使用 byte array + /** * Touch 发出时写入, 并用于加密, 接受 sendTouch response 时解密. */ diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/PasswordSubmission.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/PasswordSubmission.kt index 48ac3478a..1dc9e3618 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/PasswordSubmission.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/PasswordSubmission.kt @@ -22,22 +22,23 @@ class ClientPasswordSubmissionPacket constructor( private val loginIP: String, private val privateKey: ByteArray, private val token0825: ByteArray, - private val token00BA: ByteArray? = null,// + private val token00BA: ByteArray? = null, private val randomDeviceName: Boolean = false, private val tlv0006: IoBuffer? = null ) : ClientPacket() { override fun encode(builder: BytePacketBuilder) = with(builder) { - this.writeQQ(bot) - this.writeHex(TIMProtocol.passwordSubmissionTLV1) + writeQQ(bot) + writeHex(TIMProtocol.passwordSubmissionTLV1) - this.writeShort(25) - this.writeHex(TIMProtocol.publicKey)//25 + writeShort(25) + writeHex(TIMProtocol.publicKey)//=25 - this.writeHex("00 00 00 10")//=16 - this.writeHex(TIMProtocol.key0836)//16 + writeZero(2) + writeShort(16) + writeHex(TIMProtocol.key0836)//=16 //TODO shareKey 极大可能为 publicKey, key0836 计算得到 - this.encryptAndWrite(TIMProtocol.shareKey.hexToBytes()) { + encryptAndWrite(TIMProtocol.shareKey) { writePart1(bot, password, loginTime, loginIP, privateKey, token0825, randomDeviceName, tlv0006) if (token00BA != null) { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/ServerLoginResponse.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/ServerLoginResponse.kt index 0c00c9e9c..2bc547ba3 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/ServerLoginResponse.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/ServerLoginResponse.kt @@ -127,7 +127,7 @@ class ServerLoginResponseCaptchaInitPacket(input: ByteReadPacket) : ServerLoginR lateinit var captchaPart1: IoBuffer lateinit var token00BA: ByteArray - var unknownBoolean: Boolean? = null + var unknownBoolean: Boolean by Delegates.notNull() @Tested diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotNetworkConfiguration.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotNetworkConfiguration.kt index 6647b03da..bed1e0c5a 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotNetworkConfiguration.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotNetworkConfiguration.kt @@ -1,5 +1,7 @@ package net.mamoe.mirai.utils +import com.soywiz.klock.TimeSpan +import com.soywiz.klock.seconds import net.mamoe.mirai.network.protocol.tim.packet.login.ServerTouchResponsePacket /** @@ -9,7 +11,7 @@ class BotNetworkConfiguration { /** * 等待 [ServerTouchResponsePacket] 的时间 */ - var touchTimeoutMillis: Long = 2000 + var touchTimeout: TimeSpan = 2.seconds /** * 是否使用随机的设备名. @@ -21,13 +23,13 @@ class BotNetworkConfiguration { /** * 心跳周期. 过长会导致被服务器断开连接. */ - var heartbeatPeriodMillis: Long = 1 * 60 * 1000 + var heartbeatPeriod: TimeSpan = 60.seconds /** * 每次心跳时等待结果的时间. * 一旦心跳超时, 整个网络服务将会重启 (将消耗约 1s). 除正在进行的任务 (如图片上传) 会被中断外, 事件和插件均不受影响. */ - var heartbeatTimeoutMillis: Long = 2000 + var heartbeatTimeout: TimeSpan = 2.seconds companion object { val Default = BotNetworkConfiguration() diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt index f8a558c4d..18d781312 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt @@ -1,9 +1,11 @@ package net.mamoe.mirai.utils +import com.soywiz.klock.DateTime + /** * 时间戳 */ -expect val currentTime: Long +val currentTime: Long = DateTime.nowUnixLong() /** * 设备名 diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/TypeConvertion.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/TypeConvertion.kt index 437ba2080..d69c2fafc 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/TypeConvertion.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/TypeConvertion.kt @@ -41,13 +41,22 @@ fun UInt.toByteArray(): ByteArray = byteArrayOf( fun Int.toUHexString(separator: String = " "): String = this.toByteArray().toUHexString(separator) fun Byte.toUHexString(): String = this.toUByte().toString(16).toUpperCase() fun String.hexToBytes(): ByteArray = HexCache.hexToBytes(this) + +/** + * 将 Hex 转为 UByteArray, 有根据 hex 的 [hashCode] 建立的缓存. + */ fun String.hexToUBytes(): UByteArray = HexCache.hexToUBytes(this) + fun String.hexToInt(): Int = hexToBytes().toUInt().toInt() fun getRandomByteArray(length: Int): ByteArray = ByteArray(length) { Random.nextInt(0..255).toByte() } fun ByteArray.toUInt(): UInt = this[0].toUInt().and(255u).shl(24) + this[1].toUInt().and(255u).shl(16) + this[2].toUInt().and(255u).shl(8) + this[3].toUInt().and(255u).shl(0) fun ByteArray.toIoBuffer(): IoBuffer = IoBuffer.Pool.borrow().let { it.writeFully(this); it } +/** + * Hex 转换 [ByteArray] 和 [UByteArray] 缓存. + * 为 [net.mamoe.mirai.network.protocol.tim.TIMProtocol] 的 hex 常量使用 + */ internal object HexCache { private val hexToByteArrayCacheMap: MutableMap = mutableMapOf() diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt index eaecd582f..d92ad1bb4 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt @@ -8,8 +8,6 @@ import java.net.InetAddress import java.security.MessageDigest import java.util.zip.CRC32 -actual val currentTime: Long = System.currentTimeMillis() - actual val deviceName: String = InetAddress.getLocalHost().hostName diff --git a/mirai-debug/build.gradle b/mirai-debug/build.gradle index 1e8346a2b..4a6ab6d66 100644 --- a/mirai-debug/build.gradle +++ b/mirai-debug/build.gradle @@ -5,9 +5,9 @@ dependencies { implementation project(':mirai-core') compile files('./lib/jpcap.jar') - compile rootProject.ext.coroutineCommon - compile rootProject.ext.kotlinJvm - compile rootProject.ext.kotlinxIOJvm + implementation rootProject.ext.coroutineCommon + implementation rootProject.ext.kotlinJvm + implementation rootProject.ext.kotlinxIOJvm } tasks.withType(JavaCompile) { diff --git a/mirai-debug/src/main/java/PacketDebuger.kt b/mirai-debug/src/main/java/PacketDebuger.kt index 6e5788137..0f24c41da 100644 --- a/mirai-debug/src/main/java/PacketDebuger.kt +++ b/mirai-debug/src/main/java/PacketDebuger.kt @@ -23,32 +23,11 @@ object Main { @JvmStatic fun main(args: Array) { - /*-------------- 第一步绑定网络设备 --------------*/ val devices = JpcapCaptor.getDeviceList() - - /* - \Device\NPF_{0E7103E4-BF96-4B66-A23B-F6F630D814CD} | Microsoft - \Device\NPF_{2CCA31E2-93D5-42F2-92C1-5882E18A8E95} | VMware Virtual Ethernet Adapter - \Device\NPF_{A12C8971-858B-4BC8-816C-4077E1636AC5} | VMware Virtual Ethernet Adapter - \Device\NPF_{231C4E27-AF20-4362-BCA3-107236CB8A2E} | MS NDIS 6.0 LoopBack Driver - \Device\NPF_{500B5537-AA10-4E2F-8F7D-E6BD365BDCD1} | Microsoft - \Device\NPF_{A177317B-903A-45B5-8AEA-3698E423ABD6} | Microsoft - */ - /* - for (n in devices) { - println(n.name + " | " + n.description) - } - println("-------------------------------------------") - exitProcess(0)*/ - val jpcap: JpcapCaptor? val caplen = 4096 val promiscCheck = true - jpcap = JpcapCaptor.openDevice(devices[0], caplen, promiscCheck, 50) - - - /*----------第二步抓包-----------------*/ while (true) { assert(jpcap != null) val pk = jpcap!!.packet @@ -60,7 +39,11 @@ object Main { } if (localIp in pk.dst_ip.hostAddress) {//接受 - dataReceived(pk.data) + try { + dataReceived(pk.data) + } catch (e: Exception) { + e.printStackTrace() + } } else { try { dataSent(pk.data) @@ -88,7 +71,7 @@ object Main { * 6. 运行到 `mov eax,dword ptr ss:[ebp+10]` * 7. 查看内存, 从 `eax` 开始的 16 bytes 便是 `sessionKey` */ - val sessionKey: ByteArray = "F1 68 24 ED A8 6D 33 6E 5C B7 E0 F4 45 77 21 04".hexToBytes() + val sessionKey: ByteArray = "99 91 B9 8B 79 45 FD CF 51 4A B9 DE 14 61 ED E3".hexToBytes() fun dataReceived(data: ByteArray) { println("--------------") diff --git a/mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt b/mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt index ba38e899b..fbf785fca 100644 --- a/mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt +++ b/mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt @@ -24,7 +24,6 @@ suspend fun main() { ), Console()) bot.login { - touchTimeoutMillis = 2000 randomDeviceName = true }.let { if (it != LoginResult.SUCCESS) { diff --git a/settings.gradle b/settings.gradle index 30681eac6..540e4a00f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,4 +5,6 @@ include(':mirai-api') include(':mirai-demos:mirai-demo-1') include(':mirai-demos') include(':mirai-debug') -project(':mirai-demos:mirai-demo-1').projectDir = file('mirai-demos/mirai-demo-1') \ No newline at end of file +project(':mirai-demos:mirai-demo-1').projectDir = file('mirai-demos/mirai-demo-1') + +enableFeaturePreview('GRADLE_METADATA')