Commit e129719d authored by Him188moe's avatar Him188moe

Updated robot & network structure

parent c353e8e8
...@@ -10,7 +10,7 @@ class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable { ...@@ -10,7 +10,7 @@ class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable {
val members = ContactList<QQ>() val members = ContactList<QQ>()
override fun sendMessage(message: Message) { override fun sendMessage(message: Message) {
robot.network.packetSystem.sendGroupMessage(this, message) robot.network.messageHandler.sendGroupMessage(this, message)
} }
override fun sendXMLMessage(message: String) { override fun sendXMLMessage(message: String) {
......
...@@ -12,7 +12,7 @@ import net.mamoe.mirai.message.defaults.At ...@@ -12,7 +12,7 @@ import net.mamoe.mirai.message.defaults.At
*/ */
class QQ(robot: Robot, number: Long) : Contact(robot, number) { class QQ(robot: Robot, number: Long) : Contact(robot, number) {
override fun sendMessage(message: Message) { override fun sendMessage(message: Message) {
robot.network.packetSystem.sendFriendMessage(this, message) robot.network.messageHandler.sendFriendMessage(this, message)
} }
override fun sendXMLMessage(message: String) { override fun sendXMLMessage(message: String) {
......
...@@ -7,9 +7,8 @@ import java.util.stream.Collectors ...@@ -7,9 +7,8 @@ import java.util.stream.Collectors
/** /**
* @author Him188moe * @author Him188moe
*/ */
interface Protocol { object Protocol {
companion object { val SERVER_IP: List<String> = object : ArrayList<String>() {
val SERVER_IP: ArrayList<String> = object : ArrayList<String>() {
init { init {
add("183.60.56.29") add("183.60.56.29")
...@@ -25,7 +24,7 @@ interface Protocol { ...@@ -25,7 +24,7 @@ interface Protocol {
} }
} }
get() = Collections.unmodifiableList(field)
const val head = "02" const val head = "02"
const val ver = "37 13" const val ver = "37 13"
...@@ -90,5 +89,4 @@ interface Protocol { ...@@ -90,5 +89,4 @@ interface Protocol {
.map { s -> s.toUByte(16) } .map { s -> s.toUByte(16) }
.collect(Collectors.toList()).toUByteArray() .collect(Collectors.toList()).toUByteArray()
}
} }
...@@ -11,15 +11,15 @@ import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePack ...@@ -11,15 +11,15 @@ import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePack
import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket
import net.mamoe.mirai.network.packet.login.* import net.mamoe.mirai.network.packet.login.*
import net.mamoe.mirai.task.MiraiThreadPool import net.mamoe.mirai.task.MiraiThreadPool
import net.mamoe.mirai.utils.ClientLoginStatus import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.getGTK
import net.mamoe.mirai.utils.lazyEncode
import java.io.Closeable import java.io.Closeable
import java.net.DatagramPacket import java.net.DatagramPacket
import java.net.DatagramSocket import java.net.DatagramSocket
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.util.*
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.reflect.KClass
/** /**
* A RobotNetworkHandler is used to connect with Tencent servers. * A RobotNetworkHandler is used to connect with Tencent servers.
...@@ -28,150 +28,230 @@ import java.util.concurrent.TimeUnit ...@@ -28,150 +28,230 @@ import java.util.concurrent.TimeUnit
*/ */
@Suppress("EXPERIMENTAL_API_USAGE")//to simplify code @Suppress("EXPERIMENTAL_API_USAGE")//to simplify code
internal class RobotNetworkHandler(private val robot: Robot) : Closeable { internal class RobotNetworkHandler(private val robot: Robot) : Closeable {
private val socketHandler: SocketHandler = SocketHandler()
private var socket: DatagramSocket = DatagramSocket((15314 + Math.random() * 100).toInt()) val debugHandler = DebugHandler()
val loginHandler = LoginHandler()
val messageHandler = MessageHandler()
val actionHandler = ActionHandler()
private var serverIP: String = "" private val packetHandlers: Map<KClass<out PacketHandler>, PacketHandler> = mapOf(
set(value) { DebugHandler::class to debugHandler,
serverAddress = InetSocketAddress(value, 8000) LoginHandler::class to loginHandler,
field = value MessageHandler::class to messageHandler,
ActionHandler::class to actionHandler
)
restartSocket()
}
private lateinit var serverAddress: InetSocketAddress
private var closed: Boolean = false private var closed: Boolean = false
private lateinit var token00BA: ByteArray //这些数据全部是login用的
private lateinit var token0825: ByteArray
private var loginTime: Int = 0
private lateinit var loginIP: String
private var tgtgtKey: ByteArray? = null
private var tlv0105: ByteArray
/**
* 0828_decr_key
*/
private lateinit var sessionResponseDecryptionKey: ByteArray
private var verificationCodeSequence: Int = 0//这两个验证码使用
private var verificationCodeCache: ByteArray? = null//每次包只发一部分验证码来
private var verificationCodeCacheCount: Int = 1//
private lateinit var verificationToken: ByteArray
private lateinit var sessionKey: ByteArray//这两个是登录成功后得到的
private lateinit var sKey: String
/** /**
* Used to access web API(for friends list etc.) * Not async
*/ */
private lateinit var cookies: String @ExperimentalUnsignedTypes
private var gtk: Int = 0 fun sendPacket(packet: ClientPacket) {
private var ignoreMessage: Boolean = false socketHandler.sendPacket(packet)
}
private var loginState: LoginState? = null override fun close() {
set(value) { this.packetHandlers.values.forEach {
field = value it.close()
if (value != null) {
loginHook?.invoke(value)
} }
this.socketHandler.close()
} }
private var loginHook: ((LoginState) -> Unit)? = null
init { //private | internal
tlv0105 = lazyEncode {
it.writeHex("01 05 00 30") internal fun tryLogin(loginHook: ((LoginState) -> Unit)? = null) {
it.writeHex("00 01 01 02 00 14 01 01 00 10") val ipQueue: LinkedList<String> = LinkedList(Protocol.SERVER_IP)
it.writeRandom(16) fun login(): Boolean {
it.writeHex("00 14 01 02 00 10") val ip = ipQueue.poll()
it.writeRandom(16) return if (ip != null) {
this@RobotNetworkHandler.socketHandler.touch(ip) { state ->
if (state == LoginState.UNKNOWN) {
login()
} else {
loginHook?.invoke(state)
} }
} }
true
} else false
}
login()
}
/** @ExperimentalUnsignedTypes
* Try to login to server internal fun onPacketReceived(packet: ServerPacket) {
*/ this.packetHandlers.values.forEach {
internal fun tryLogin(loginHook: ((LoginState) -> Unit)? = null) { it.onPacketReceived(packet)
//"14.116.136.106", }
tryLogin()
} }
/**
* Try to login to server
*/
private fun tryLogin(serverAddress: String, loginHook: ((LoginState) -> Unit)? = null) {
touch(serverAddress, loginHook) private inner class SocketHandler : Closeable {
private lateinit var socket: DatagramSocket
internal var serverIP: String = ""
set(value) {
serverAddress = InetSocketAddress(value, 8000)
field = value
restartSocket()
} }
/** private var loginHook: ((LoginState) -> Unit)? = null
* Start network internal var loginState: LoginState? = null
*/ set(value) {
private fun touch(serverAddress: String, loginHook: ((LoginState) -> Unit)? = null) { field = value
serverIP = serverAddress if (value != null && value != LoginState.UNKNOWN) {
if (loginHook != null) { loginHook?.invoke(value)
this.loginHook = loginHook
} }
this.sendPacket(ClientTouchPacket(this.robot.account.qqNumber, this.serverIP))
} }
private lateinit var serverAddress: InetSocketAddress
private fun restartSocket() { private fun restartSocket() {
socket.close()
socket = DatagramSocket((15314 + Math.random() * 100).toInt()) socket = DatagramSocket((15314 + Math.random() * 100).toInt())
socket.close()
socket.connect(this.serverAddress) socket.connect(this.serverAddress)
val zeroByte: Byte = 0
Thread { Thread {
while (true) { while (socket.isConnected) {
val dp1 = DatagramPacket(ByteArray(2048), 2048) val packet = DatagramPacket(ByteArray(2048), 2048)
kotlin
.runCatching { socket.receive(packet) }
.onSuccess {
MiraiThreadPool.getInstance().submit {
try { try {
socket.receive(dp1) onPacketReceived(ServerPacket.ofByteArray(packet.data.removeZeroTail()))
} catch (e: Exception) { } catch (e: Exception) {
if (e.message == "socket closed") { e.printStackTrace()
}
}
}.onFailure {
if (it.message == "socket closed") {
if (!closed) { if (!closed) {
restartSocket() restartSocket()
} }
return@Thread return@Thread
} }
it.printStackTrace()
} }
MiraiThreadPool.getInstance().submit {
var i = dp1.data.size - 1 }
while (dp1.data[i] == zeroByte) { }.start()
--i }
/**
* Start network and touch the server
*/
internal fun touch(serverAddress: String, loginHook: ((LoginState) -> Unit)? = null) {
socketHandler.serverIP = serverAddress
if (loginHook != null) {
this.loginHook = loginHook
} }
sendPacket(ClientTouchPacket(robot.account.qqNumber, socketHandler.serverIP))
}
/**
* Not async
*/
@ExperimentalUnsignedTypes
internal fun sendPacket(packet: ClientPacket) {
try { try {
onPacketReceived(ServerPacket.ofByteArray(dp1.data.copyOfRange(0, i + 1))) packet.encode()
} catch (e: Exception) { packet.writeHex(Protocol.tail)
val data = packet.toByteArray()
socket.send(DatagramPacket(data, data.size))
MiraiLogger info "Packet sent: $packet"
} catch (e: Throwable) {
e.printStackTrace() e.printStackTrace()
} }
} }
override fun close() {
this.socket.close()
this.loginState = null
this.loginHook = null
} }
}.start()
} }
@ExperimentalUnsignedTypes
internal fun onPacketReceived(packet: ServerPacket) { private lateinit var sessionKey: ByteArray
abstract inner class PacketHandler : Closeable {
abstract fun onPacketReceived(packet: ServerPacket)
override fun close() {
}
}
/**
* Kind of [PacketHandler] that prints all packets received in the format of hex byte array.
*/
inner class DebugHandler : PacketHandler() {
override fun onPacketReceived(packet: ServerPacket) {
packet.decode() packet.decode()
MiraiLogger info "Packet received: $packet" MiraiLogger info "Packet received: $packet"
if (packet is ServerEventPacket) { if (packet is ServerEventPacket) {
sendPacket(ClientMessageResponsePacket(this.robot.account.qqNumber, packet.packetId, this.sessionKey, packet.eventIdentity)) sendPacket(ClientMessageResponsePacket(robot.account.qqNumber, packet.packetId, sessionKey, packet.eventIdentity))
}
}
} }
/**
* 处理登录过程
*/
inner class LoginHandler : PacketHandler() {
private lateinit var token00BA: ByteArray
private lateinit var token0825: ByteArray
private var loginTime: Int = 0
private lateinit var loginIP: String
private var tgtgtKey: ByteArray? = null
private var tlv0105: ByteArray = lazyEncode {
it.writeHex("01 05 00 30")
it.writeHex("00 01 01 02 00 14 01 01 00 10")
it.writeRandom(16)
it.writeHex("00 14 01 02 00 10")
it.writeRandom(16)
}
/**
* 0828_decr_key
*/
private lateinit var sessionResponseDecryptionKey: ByteArray
private var verificationCodeSequence: Int = 0//这两个验证码使用
private var verificationCodeCache: ByteArray? = null//每次包只发一部分验证码来
private var verificationCodeCacheCount: Int = 1//
private lateinit var verificationToken: ByteArray
private var heartbeatFuture: ScheduledFuture<*>? = null
private var sKeyRefresherFuture: ScheduledFuture<*>? = null
override fun onPacketReceived(packet: ServerPacket) {
when (packet) { when (packet) {
is ServerTouchResponsePacket -> { is ServerTouchResponsePacket -> {
if (packet.serverIP != null) {//redirection if (packet.serverIP != null) {//redirection
serverIP = packet.serverIP!! socketHandler.serverIP = packet.serverIP!!
//connect(packet.serverIP!!) //connect(packet.serverIP!!)
sendPacket(ClientServerRedirectionPacket(packet.serverIP!!, this.robot.account.qqNumber)) sendPacket(ClientServerRedirectionPacket(packet.serverIP!!, robot.account.qqNumber))
} else {//password submission } else {//password submission
this.loginIP = packet.loginIP this.loginIP = packet.loginIP
this.loginTime = packet.loginTime this.loginTime = packet.loginTime
this.token0825 = packet.token0825 this.token0825 = packet.token0825
this.tgtgtKey = packet.tgtgtKey this.tgtgtKey = packet.tgtgtKey
sendPacket(ClientPasswordSubmissionPacket(this.robot.account.qqNumber, this.robot.account.password, packet.loginTime, packet.loginIP, packet.tgtgtKey, packet.token0825)) sendPacket(ClientPasswordSubmissionPacket(robot.account.qqNumber, robot.account.password, packet.loginTime, packet.loginIP, packet.tgtgtKey, packet.token0825))
} }
} }
is ServerLoginResponseFailedPacket -> { is ServerLoginResponseFailedPacket -> {
this.loginState = packet.loginState socketHandler.loginState = packet.loginState
MiraiLogger error "Login failed: " + packet.loginState.toString() MiraiLogger error "Login failed: " + packet.loginState.toString()
return return
} }
...@@ -181,18 +261,16 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { ...@@ -181,18 +261,16 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable {
this.token00BA = packet.token00BA this.token00BA = packet.token00BA
this.verificationCodeCache = packet.verifyCodePart1 this.verificationCodeCache = packet.verifyCodePart1
if (packet.unknownBoolean != null && packet.unknownBoolean!!) { if (packet.unknownBoolean != null && packet.unknownBoolean!!) {
this.verificationCodeSequence = 1 this.verificationCodeSequence = 1
sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, this.robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA)) sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA))
} }
} }
is ServerVerificationCodeRepeatPacket -> {//todo 这个名字正确么 is ServerVerificationCodeRepeatPacket -> {//todo 这个名字正确么
this.tgtgtKey = packet.tgtgtKeyUpdate this.tgtgtKey = packet.tgtgtKeyUpdate
this.token00BA = packet.token00BA this.token00BA = packet.token00BA
sendPacket(ClientLoginResendPacket3105(this.robot.account.qqNumber, this.robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA)) sendPacket(ClientLoginResendPacket3105(robot.account.qqNumber, robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA))
} }
is ServerVerificationCodeTransmissionPacket -> { is ServerVerificationCodeTransmissionPacket -> {
...@@ -207,18 +285,17 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { ...@@ -207,18 +285,17 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable {
//todo 看易语言 count 和 sequence 是怎样变化的 //todo 看易语言 count 和 sequence 是怎样变化的
if (packet.transmissionCompleted) { if (packet.transmissionCompleted) {
this.verificationCodeCache this.verificationCodeCache
TODO("验证码好了") TODO("验证码好了")
} else { } else {
sendPacket(ClientVerificationCodeTransmissionRequestPacket(this.verificationCodeCacheCount, this.robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA)) sendPacket(ClientVerificationCodeTransmissionRequestPacket(this.verificationCodeCacheCount, robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA))
} }
} }
is ServerLoginResponseSuccessPacket -> { is ServerLoginResponseSuccessPacket -> {
this.sessionResponseDecryptionKey = packet.sessionResponseDecryptionKey this.sessionResponseDecryptionKey = packet.sessionResponseDecryptionKey
sendPacket(ClientSessionRequestPacket(this.robot.account.qqNumber, this.serverIP, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105)) sendPacket(ClientSessionRequestPacket(robot.account.qqNumber, socketHandler.serverIP, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105))
} }
//是ClientPasswordSubmissionPacket之后服务器回复的 //是ClientPasswordSubmissionPacket之后服务器回复的
...@@ -230,8 +307,8 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { ...@@ -230,8 +307,8 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable {
if (packet.flag == ServerLoginResponseResendPacket.Flag.`08 36 31 03`) { if (packet.flag == ServerLoginResponseResendPacket.Flag.`08 36 31 03`) {
this.tgtgtKey = packet.tgtgtKey this.tgtgtKey = packet.tgtgtKey
sendPacket(ClientLoginResendPacket3104( sendPacket(ClientLoginResendPacket3104(
this.robot.account.qqNumber, robot.account.qqNumber,
this.robot.account.password, robot.account.password,
this.loginTime, this.loginTime,
this.loginIP, this.loginIP,
this.tgtgtKey!!, this.tgtgtKey!!,
...@@ -244,8 +321,8 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { ...@@ -244,8 +321,8 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable {
)) ))
} else { } else {
sendPacket(ClientLoginResendPacket3106( sendPacket(ClientLoginResendPacket3106(
this.robot.account.qqNumber, robot.account.qqNumber,
this.robot.account.password, robot.account.password,
this.loginTime, this.loginTime,
this.loginIP, this.loginIP,
this.tgtgtKey!!, this.tgtgtKey!!,
...@@ -259,98 +336,113 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { ...@@ -259,98 +336,113 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable {
} }
} }
is ServerSessionKeyResponsePacket -> { is ServerSessionKeyResponsePacket -> {
this.sessionKey = packet.sessionKey sessionKey = packet.sessionKey
MiraiThreadPool.getInstance().scheduleWithFixedDelay({ heartbeatFuture = MiraiThreadPool.getInstance().scheduleWithFixedDelay({
sendPacket(ClientHeartbeatPacket(this.robot.account.qqNumber, this.sessionKey)) sendPacket(ClientHeartbeatPacket(robot.account.qqNumber, sessionKey))
}, 90000, 90000, TimeUnit.MILLISECONDS) }, 90000, 90000, TimeUnit.MILLISECONDS)
RobotLoginSucceedEvent(robot).broadcast() RobotLoginSucceedEvent(robot).broadcast()
//登录成功后会收到大量上次的消息, 忽略掉
MiraiThreadPool.getInstance().schedule({ MiraiThreadPool.getInstance().schedule({
ignoreMessage = false (packetHandlers[MessageHandler::class] as MessageHandler).ignoreMessage = false
}, 2, TimeUnit.SECONDS) }, 2, TimeUnit.SECONDS)
this.tlv0105 = packet.tlv0105 this.tlv0105 = packet.tlv0105
sendPacket(ClientChangeOnlineStatusPacket(this.robot.account.qqNumber, this.sessionKey, ClientLoginStatus.ONLINE)) sendPacket(ClientChangeOnlineStatusPacket(robot.account.qqNumber, sessionKey, ClientLoginStatus.ONLINE))
} }
is ServerLoginSuccessPacket -> { is ServerLoginSuccessPacket -> {
loginState = LoginState.SUCCEED socketHandler.loginState = LoginState.SUCCEED
sendPacket(ClientSKeyRequestPacket(this.robot.account.qqNumber, this.sessionKey)) sendPacket(ClientSKeyRequestPacket(robot.account.qqNumber, sessionKey))
} }
is ServerSKeyResponsePacket -> { is ServerSKeyResponsePacket -> {
this.sKey = packet.sKey val actionHandler = packetHandlers[ActionHandler::class] as ActionHandler
this.cookies = "uin=o" + this.robot.account.qqNumber + ";skey=" + this.sKey + ";" actionHandler.sKey = packet.sKey
actionHandler.cookies = "uin=o" + robot.account.qqNumber + ";skey=" + actionHandler.sKey + ";"
MiraiThreadPool.getInstance().scheduleWithFixedDelay({ sKeyRefresherFuture = MiraiThreadPool.getInstance().scheduleWithFixedDelay({
sendPacket(ClientSKeyRefreshmentRequestPacket(this.robot.account.qqNumber, this.sessionKey)) sendPacket(ClientSKeyRefreshmentRequestPacket(robot.account.qqNumber, sessionKey))
}, 1800000, 1800000, TimeUnit.MILLISECONDS) }, 1800000, 1800000, TimeUnit.MILLISECONDS)
this.gtk = getGTK(sKey) actionHandler.gtk = getGTK(actionHandler.sKey)
sendPacket(ClientAccountInfoRequestPacket(this.robot.account.qqNumber, this.sessionKey)) sendPacket(ClientAccountInfoRequestPacket(robot.account.qqNumber, sessionKey))
} }
is ServerHeartbeatResponsePacket -> { is ServerEventPacket.Raw -> onPacketReceived(packet.distribute())
} is ServerVerificationCodePacket.Encrypted -> onPacketReceived(packet.decrypt())
is ServerLoginResponseVerificationCodeInitPacket.Encrypted -> onPacketReceived(packet.decrypt())
is ServerLoginResponseResendPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
is ServerLoginResponseSuccessPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
is ServerSessionKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionResponseDecryptionKey))
is ServerTouchResponsePacket.Encrypted -> onPacketReceived(packet.decrypt())
is ServerSKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(sessionKey))
is ServerAccountInfoResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(sessionKey))
is ServerEventPacket.Raw.Encrypted -> onPacketReceived(packet.decrypt(sessionKey))
is ServerAccountInfoResponsePacket -> {
is ServerAccountInfoResponsePacket,
is ServerHeartbeatResponsePacket,
is UnknownServerPacket -> {
//ignored
} }
else -> {
is ServerFriendMessageEventPacket -> {
if (ignoreMessage) {
return
} }
FriendMessageEvent(this.robot, this.robot.contacts.getQQ(packet.qq), packet.message)
} }
is ServerGroupMessageEventPacket -> {
//todo message chain
//GroupMessageEvent(this.robot, this.robot.contacts.getGroupByNumber(packet.groupNumber), this.robot.contacts.getQQ(packet.qq), packet.message)
} }
is UnknownServerEventPacket -> { override fun close() {
//unknown message event this.verificationCodeCache = null
} this.tgtgtKey = null
is UnknownServerPacket -> { this.heartbeatFuture?.cancel(true)
this.sKeyRefresherFuture?.cancel(true)
this.heartbeatFuture = null
this.sKeyRefresherFuture = null
}
} }
is ServerGroupUploadFileEventPacket -> { /**
* 处理消息事件, 承担消息发送任务.
*/
inner class MessageHandler : PacketHandler() {
internal var ignoreMessage: Boolean = false
override fun onPacketReceived(packet: ServerPacket) {
when (packet) {
is ServerGroupUploadFileEventPacket -> {
//todo
} }
is ServerEventPacket.Raw -> onPacketReceived(packet.distribute()) is ServerFriendMessageEventPacket -> {
if (ignoreMessage) {
return
}
is ServerVerificationCodePacket.Encrypted -> onPacketReceived(packet.decrypt()) FriendMessageEvent(robot, robot.contacts.getQQ(packet.qq), packet.message)
is ServerLoginResponseVerificationCodeInitPacket.Encrypted -> onPacketReceived(packet.decrypt()) }
is ServerLoginResponseResendPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
is ServerLoginResponseSuccessPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
is ServerSessionKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionResponseDecryptionKey))
is ServerTouchResponsePacket.Encrypted -> onPacketReceived(packet.decrypt())
is ServerSKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey))
is ServerAccountInfoResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey))
is ServerEventPacket.Raw.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey))
is ServerGroupMessageEventPacket -> {
//todo message chain
//GroupMessageEvent(this.robot, robot.contacts.getGroupByNumber(packet.groupNumber), robot.contacts.getQQ(packet.qq), packet.message)
}
is UnknownServerEventPacket,
is ServerSendFriendMessageResponsePacket, is ServerSendFriendMessageResponsePacket,
is ServerSendGroupMessageResponsePacket -> { is ServerSendGroupMessageResponsePacket -> {
//ignored
}
else -> {
//ignored
} }
else -> throw IllegalArgumentException(packet.toString())
} }
} }
internal val packetSystem: PacketSystem = PacketSystem()
inner class PacketSystem {
fun sendFriendMessage(qq: QQ, message: Message) { fun sendFriendMessage(qq: QQ, message: Message) {
TODO() TODO()
//sendPacket(ClientSendFriendMessagePacket(robot.account.qqNumber, qq.number, sessionKey, message)) //sendPacket(ClientSendFriendMessagePacket(robot.account.qqNumber, qq.number, sessionKey, message))
...@@ -360,31 +452,23 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable { ...@@ -360,31 +452,23 @@ internal class RobotNetworkHandler(private val robot: Robot) : Closeable {
TODO() TODO()
//sendPacket(ClientSendGroupMessagePacket(group.groupId, robot.account.qqNumber, sessionKey, message)) //sendPacket(ClientSendGroupMessagePacket(group.groupId, robot.account.qqNumber, sessionKey, message))
} }
} }
/** /**
* Not async * 动作: 获取好友列表, 点赞, 踢人等.
* 处理动作事件, 承担动作任务.
*/ */
@ExperimentalUnsignedTypes inner class ActionHandler : PacketHandler() {
fun sendPacket(packet: ClientPacket) { internal lateinit var cookies: String
try { internal lateinit var sKey: String
packet.encode() internal var gtk: Int = 0
packet.writeHex(Protocol.tail)
override fun onPacketReceived(packet: ServerPacket) {
val data = packet.toByteArray()
socket.send(DatagramPacket(data, data.size))
MiraiLogger info "Packet sent: $packet"
} catch (e: Throwable) {
e.printStackTrace()
}
} }
override fun close() { override fun close() {
this.socket.close()
this.loginState = null }
this.loginHook = null
this.verificationCodeCache = null
this.tgtgtKey = null
} }
} }
\ No newline at end of file
...@@ -17,6 +17,7 @@ class ClientAccountInfoRequestPacket( ...@@ -17,6 +17,7 @@ class ClientAccountInfoRequestPacket(
) : ClientPacket() { ) : ClientPacket() {
override fun encode() { override fun encode() {
this.writeRandom(2)//part of packet id this.writeRandom(2)//part of packet id
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex(Protocol.fixVer2) this.writeHex(Protocol.fixVer2)
this.encryptAndWrite(sessionKey) { this.encryptAndWrite(sessionKey) {
......
...@@ -53,11 +53,13 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { ...@@ -53,11 +53,13 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
551, 487 -> LoginState.DEVICE_LOCK 551, 487 -> LoginState.DEVICE_LOCK
359 -> LoginState.TAKEN_BACK 359 -> LoginState.TAKEN_BACK
else -> LoginState.UNKNOWN
/*
//unknown //unknown
63 -> throw IllegalArgumentException(bytes.size.toString() + " (Unknown error)") 63 -> throw IllegalArgumentException(bytes.size.toString() + " (Unknown error)")
351 -> throw IllegalArgumentException(bytes.size.toString() + " (Illegal package data or Unknown error)")//包数据有误 351 -> throw IllegalArgumentException(bytes.size.toString() + " (Illegal package data or Unknown error)")//包数据有误
else -> throw IllegalArgumentException(bytes.size.toString()) else -> throw IllegalArgumentException(bytes.size.toString())*/
}, stream) }, stream)
} }
...@@ -112,17 +114,6 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { ...@@ -112,17 +114,6 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
} }
fun DataInputStream.readUntil(byte: Byte): ByteArray {
var buff = byteArrayOf()
var b: Byte
b = readByte()
while (b != byte) {
buff += b
b = readByte()
}
return buff
}
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
fun DataInputStream.readIP(): String { fun DataInputStream.readIP(): String {
var buff = "" var buff = ""
......
...@@ -14,5 +14,7 @@ enum class LoginState { ...@@ -14,5 +14,7 @@ enum class LoginState {
DEVICE_LOCK,//设备锁 DEVICE_LOCK,//设备锁
TAKEN_BACK,//被回收 TAKEN_BACK,//被回收
// VERIFICATION_CODE,//需要验证码 // VERIFICATION_CODE,//需要验证码
// SUCCEED,
UNKNOWN,
} }
\ No newline at end of file
...@@ -11,9 +11,8 @@ import java.util.Random; ...@@ -11,9 +11,8 @@ import java.util.Random;
* @author iweiz https://github.com/iweizime/StepChanger/blob/master/app/src/main/java/me/iweizi/stepchanger/qq/Cryptor.java * @author iweiz https://github.com/iweizime/StepChanger/blob/master/app/src/main/java/me/iweizi/stepchanger/qq/Cryptor.java
*/ */
public final class TEA { public final class TEA {
public static final TEA CRYPTOR_SHARE_KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.shareKey)); public static final TEA CRYPTOR_SHARE_KEY = new TEA(Protocol.INSTANCE.hexToBytes(Protocol.shareKey));
public static final TEA CRYPTOR_0825KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key0825)); public static final TEA CRYPTOR_0825KEY = new TEA(Protocol.INSTANCE.hexToBytes(Protocol.key0825));
public static final TEA CRYPTOR_00BAKEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key00BA));
private static final long UINT32_MASK = 0xffffffffL; private static final long UINT32_MASK = 0xffffffffL;
private final long[] mKey; private final long[] mKey;
......
...@@ -79,7 +79,7 @@ operator fun File.plus(child: String): File = File(this, child) ...@@ -79,7 +79,7 @@ operator fun File.plus(child: String): File = File(this, child)
private const val GTK_BASE_VALUE: Int = 5381 private const val GTK_BASE_VALUE: Int = 5381
fun getGTK(sKey: String): Int { internal fun getGTK(sKey: String): Int {
var value = GTK_BASE_VALUE var value = GTK_BASE_VALUE
for (c in sKey.toCharArray()) { for (c in sKey.toCharArray()) {
value += (value shl 5) + c.toInt() value += (value shl 5) + c.toInt()
...@@ -89,7 +89,7 @@ fun getGTK(sKey: String): Int { ...@@ -89,7 +89,7 @@ fun getGTK(sKey: String): Int {
return value return value
} }
fun getCrc32(key: ByteArray): Int = CRC32().let { it.update(key); it.value.toInt() } internal fun getCrc32(key: ByteArray): Int = CRC32().let { it.update(key); it.value.toInt() }
/** /**
...@@ -122,3 +122,13 @@ fun Any.getAllDeclaredFields(): List<Field> { ...@@ -122,3 +122,13 @@ fun Any.getAllDeclaredFields(): List<Field> {
return list return list
} }
private const val ZERO_BYTE: Byte = 0
fun ByteArray.removeZeroTail(): ByteArray {
var i = this.size - 1
while (this[i] == ZERO_BYTE) {
--i
}
return this.copyOfRange(0, i + 1)
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment