Use Klock

This commit is contained in:
Him188 2019-10-19 13:41:36 +08:00
parent 244996ac28
commit cf052614f5
16 changed files with 51 additions and 50 deletions

View File

@ -19,6 +19,7 @@ allprojects {
version = "1.0"
repositories {
jcenter()//klock
google()
maven { url "https://mirrors.huaweicloud.com/repository/maven/" }
}

View File

@ -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"
}

View File

@ -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
}
}

View File

@ -14,8 +14,6 @@ import net.mamoe.mirai.utils.toUHexString
/**
* The mirror of functions in inner classes of [Bot]
*
* @author Him188moe
*/
//Contacts

View File

@ -147,7 +147,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
val expect = expectPacket<ServerTouchResponsePacket>()
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<ServerHeartbeatResponsePacket> {}
} == null) {
bot.logPurple("Heartbeat timed out")

View File

@ -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 时解密.
*/

View File

@ -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) {

View File

@ -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

View File

@ -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()

View File

@ -1,9 +1,11 @@
package net.mamoe.mirai.utils
import com.soywiz.klock.DateTime
/**
* 时间戳
*/
expect val currentTime: Long
val currentTime: Long = DateTime.nowUnixLong()
/**
* 设备名

View File

@ -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<Int, ByteArray> = mutableMapOf()

View File

@ -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

View File

@ -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) {

View File

@ -23,32 +23,11 @@ object Main {
@JvmStatic
fun main(args: Array<String>) {
/*-------------- 第一步绑定网络设备 --------------*/
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("--------------")

View File

@ -24,7 +24,6 @@ suspend fun main() {
), Console())
bot.login {
touchTimeoutMillis = 2000
randomDeviceName = true
}.let {
if (it != LoginResult.SUCCESS) {

View File

@ -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')
project(':mirai-demos:mirai-demo-1').projectDir = file('mirai-demos/mirai-demo-1')
enableFeaturePreview('GRADLE_METADATA')