Adjust package names and file names

This commit is contained in:
Him188 2019-10-22 20:08:08 +08:00
parent 3f30bb4d54
commit b7628cd3d6
61 changed files with 408 additions and 469 deletions

View File

@ -6,7 +6,7 @@ ext {
kotlinCommon = "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version"
kotlinNative = "org.jetbrains.kotlin:kotlin-stdlib-native:$kotlin_version"
// coroutine
// kotlinx.coroutine
coroutine_version = "1.3.0"
coroutine = "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine_version"
coroutineCommon = "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutine_version"
@ -16,19 +16,29 @@ ext {
coroutineIo = "org.jetbrains.kotlinx:kotlinx-coroutines-io:0.24.0"
// reflect
// kotlin.reflect
reflect = "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
// atomicfu
// kotlinx.atomicfu
atomicfu_version = "0.13.1"
atomicFUCommon = "org.jetbrains.kotlinx:atomicfu-common:$atomicfu_version"
// kotlinx.io
kotlinx_io_version = "0.1.15"
kotlinxIOJvm = "org.jetbrains.kotlinx:kotlinx-io-jvm:$kotlinx_io_version"
kotlinxIOCommon = "org.jetbrains.kotlinx:kotlinx-io:$kotlinx_io_version"
kotlinxIOJS = "org.jetbrains.kotlinx:kotlinx-io-js:$kotlinx_io_version"
kotlinxIONative = "org.jetbrains.kotlinx:kotlinx-io-native:$kotlinx_io_version"
// klock
klock = "com.soywiz.korlibs.klock:klock:1.7.0"
// ktor
ktor_version = "1.2.4"
ktorClientCore = "io.ktor:ktor-client-core:$ktor_version"
ktorClientCoreNative = "io.ktor:ktor-client-core-native:$ktor_version"
ktorClientCoreJvm = "io.ktor:ktor-client-core-jvm:$ktor_version"
ktorClientCio = "io.ktor:ktor-client-cio:$ktor_version"
ktorHttp = "io.ktor:ktor-http:$ktor_version"
ktorHttpCio = "io.ktor:ktor-http-cio:$ktor_version"
}

View File

@ -4,7 +4,6 @@ package net.mamoe.mirai
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import net.mamoe.mirai.utils.BotAccount
import net.mamoe.mirai.utils.LoggerTextFormat
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.config.MiraiConfig

View File

@ -36,6 +36,11 @@ kotlin {
implementation rootProject.ext.kotlinxIOCommon
implementation rootProject.ext.klock
implementation rootProject.ext.ktorClientCore
implementation rootProject.ext.ktorClientCio
implementation rootProject.ext.ktorHttp
implementation rootProject.ext.ktorHttpCio
}
}
@ -53,6 +58,12 @@ kotlin {
implementation 'org.jsoup:jsoup:1.12.1'
implementation 'org.ini4j:ini4j:0.5.2'
implementation rootProject.ext.klock
implementation rootProject.ext.ktorClientCore
implementation rootProject.ext.ktorClientCoreJvm
implementation rootProject.ext.ktorClientCio
implementation rootProject.ext.ktorHttp
implementation rootProject.ext.ktorHttpCio
}
}

View File

@ -11,9 +11,17 @@ import net.mamoe.mirai.contact.groupIdToNumber
import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.BotNetworkConfiguration
import net.mamoe.mirai.utils.ContactList
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.log
import kotlin.jvm.JvmOverloads
data class BotAccount(
val account: UInt,
val password: String//todo 不保存 password?
)
/**
* Mirai 的机器人. 一个机器人实例登录一个 QQ 账号.
* Mirai 为多账号设计, 可同时维护多个机器人.

View File

@ -5,12 +5,12 @@ package net.mamoe.mirai
import kotlinx.io.core.readBytes
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import net.mamoe.mirai.utils.BotNetworkConfiguration
import net.mamoe.mirai.utils.ContactList
import net.mamoe.mirai.utils.toUHexString
import net.mamoe.mirai.utils.io.toUHexString
/**
* The mirror of functions in inner classes of [Bot]
@ -32,7 +32,7 @@ val Bot.qqs: ContactList<QQ> get() = this.contacts.qqs
//NetworkHandler
suspend fun Bot.sendPacket(packet: ClientPacket) = this.network.sendPacket(packet)
suspend fun Bot.sendPacket(packet: OutgoingPacket) = this.network.sendPacket(packet)
suspend fun Bot.login(configuration: BotNetworkConfiguration.() -> Unit): LoginResult = this.network.login(BotNetworkConfiguration().apply(configuration))

View File

@ -6,6 +6,13 @@ import net.mamoe.mirai.event.internal.Handler
import net.mamoe.mirai.event.internal.subscribeInternal
import kotlin.reflect.KClass
/*
* 该文件为所有的订阅事件的方法.
*/
/**
* 订阅者的状态
*/
enum class ListeningStatus {
LISTENING,
STOPPED

View File

@ -2,7 +2,7 @@ package net.mamoe.mirai.event.events
import net.mamoe.mirai.Bot
import net.mamoe.mirai.event.Cancellable
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.Packet
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
@ -14,17 +14,17 @@ sealed class PacketEvent<out P : Packet>(bot: Bot, open val packet: P) : BotEven
/* Client to Server */
sealed class ClientPacketEvent<out P : ClientPacket>(bot: Bot, packet: P) : PacketEvent<P>(bot, packet)
sealed class ClientPacketEvent<out P : OutgoingPacket>(bot: Bot, packet: P) : PacketEvent<P>(bot, packet)
/**
* 包已发送. 不可被取消
*/
class PacketSentEvent<P : ClientPacket>(bot: Bot, packet: P) : ClientPacketEvent<P>(bot, packet)
class PacketSentEvent<P : OutgoingPacket>(bot: Bot, packet: P) : ClientPacketEvent<P>(bot, packet)
/**
* 包发送前. 可被取消
*/
class BeforePacketSendEvent<P : ClientPacket>(bot: Bot, packet: P) : ClientPacketEvent<P>(bot, packet), Cancellable
class BeforePacketSendEvent<P : OutgoingPacket>(bot: Bot, packet: P) : ClientPacketEvent<P>(bot, packet), Cancellable
/* Server to Client */

View File

@ -4,7 +4,7 @@ import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import net.mamoe.mirai.event.Event
import net.mamoe.mirai.event.ListeningStatus
import net.mamoe.mirai.utils.removeIfInlined
import net.mamoe.mirai.utils.inlinedRemoveIf
import kotlin.reflect.KClass
/**
@ -59,7 +59,7 @@ internal object EventListenerManger {
internal suspend fun <E : Event> E.broadcastInternal(): E {
suspend fun callListeners(listeners: EventListeners<in E>) = listeners.lock.withLock {
//fixme 这个锁会导致在事件处理时再监听这个事件死锁
listeners.removeIfInlined { it.onEvent(this) == ListeningStatus.STOPPED }
listeners.inlinedRemoveIf { it.onEvent(this) == ListeningStatus.STOPPED }
}
callListeners(this::class.listeners as EventListeners<in E>)

View File

@ -4,7 +4,11 @@ package net.mamoe.mirai.message.internal
import kotlinx.io.core.*
import net.mamoe.mirai.message.*
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.*
import net.mamoe.mirai.utils.toUHexString
import net.mamoe.mirai.utils.writeHex
import net.mamoe.mirai.utils.writeShortLVPacket
import net.mamoe.mirai.utils.writeShortLVString
internal fun IoBuffer.parseMessageFace(): Face {
//00 01 AF 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 F0

View File

@ -6,11 +6,10 @@ import kotlinx.coroutines.cancelChildren
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.BotSocketAdapter
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.LoginHandler
import net.mamoe.mirai.network.protocol.tim.handler.*
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.HeartbeatPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.Packet
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.ClientSKeyRefreshmentRequestPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import net.mamoe.mirai.utils.BotNetworkConfiguration
import net.mamoe.mirai.utils.PlatformDatagramChannel
@ -22,7 +21,7 @@ import kotlin.coroutines.ContinuationInterceptor
*
* [BotNetworkHandler] 2 个模块构成:
* - [BotSocketAdapter]: 处理数据包底层的发送([ByteArray])
* - [PacketHandler]: 制作 [ClientPacket] 并传递给 [BotSocketAdapter] 发送; 分析 [ServerPacket] 并处理
* - [PacketHandler]: 制作 [OutgoingPacket] 并传递给 [BotSocketAdapter] 发送; 分析 [ServerPacket] 并处理
*
* 其中, [PacketHandler] 3 个子模块构成:
* - [LoginHandler] 处理 sendTouch/login/verification code 相关
@ -40,7 +39,7 @@ interface BotNetworkHandler<Socket : DataPacketSocketAdapter> {
* [BotNetworkHandler] 的协程包含:
* - UDP 包接收: [PlatformDatagramChannel.read]
* - 心跳 Job [HeartbeatPacket]
* - SKey 刷新 [ClientSKeyRefreshmentRequestPacket]
* - SKey 刷新 [RefreshSKeyRequestPacket]
* - 所有数据包处理和发送
*
* [BotNetworkHandler.close] 时将会 [取消][kotlin.coroutines.CoroutineContext.cancelChildren] 所有此作用域下的协程
@ -75,7 +74,7 @@ interface BotNetworkHandler<Socket : DataPacketSocketAdapter> {
/**
* 发送数据包
*/
suspend fun sendPacket(packet: ClientPacket)
suspend fun sendPacket(packet: OutgoingPacket)
fun close(cause: Throwable? = null) {
//todo check??

View File

@ -9,7 +9,7 @@ import net.mamoe.mirai.Bot
import net.mamoe.mirai.network.protocol.tim.handler.ActionPacketHandler
import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter
import net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.utils.getGTK
import kotlin.coroutines.coroutineContext
@ -24,7 +24,7 @@ class BotSession(
val bot: Bot,
val sessionKey: ByteArray,//TODO 协议抽象? 可能并不是所有协议均需要 sessionKey
val socket: DataPacketSocketAdapter,
val scope: CoroutineScope
val NetworkScope: CoroutineScope
) {
/**
@ -65,7 +65,7 @@ class BotSession(
* @param P 期待的包
* @param handler 处理期待的包
*/
suspend inline fun <reified P : ServerPacket, R> ClientPacket.sendAndExpect(noinline handler: suspend (P) -> R): CompletableDeferred<R> {
suspend inline fun <reified P : ServerPacket, R> OutgoingPacket.sendAndExpect(noinline handler: suspend (P) -> R): CompletableDeferred<R> {
val deferred: CompletableDeferred<R> = coroutineContext[Job].takeIf { it != null }?.let { CompletableDeferred<R>(it) } ?: CompletableDeferred()
bot.network.addHandler(TemporaryPacketHandler(P::class, deferred, this@BotSession).also {
it.toSend(this)
@ -74,14 +74,14 @@ class BotSession(
return deferred
}
suspend inline fun <reified P : ServerPacket> ClientPacket.sendAndExpect(): CompletableDeferred<Unit> = sendAndExpect<P, Unit> {}
suspend inline fun <reified P : ServerPacket> OutgoingPacket.sendAndExpect(): CompletableDeferred<Unit> = sendAndExpect<P, Unit> {}
suspend inline fun ClientPacket.send() = socket.sendPacket(this)
suspend inline fun OutgoingPacket.send() = socket.sendPacket(this)
}
suspend fun BotSession.distributePacket(packet: ServerPacket) = this.socket.distributePacket(packet)
val BotSession.isOpen: Boolean get() = socket.isOpen
val BotSession.account: UInt get() = bot.account.account
val BotSession.qqAccount: UInt get() = bot.account.account
val <T : BotNetworkHandler<*>> T.session get() = this[ActionPacketHandler].session

View File

@ -16,14 +16,16 @@ import net.mamoe.mirai.event.subscribe
import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.handler.*
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.HeartbeatPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.UnknownServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.*
import net.mamoe.mirai.network.session
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.parseServerPacket
import net.mamoe.mirai.utils.io.toUHexString
/**
* [BotNetworkHandler] TIM PC 协议实现
@ -100,7 +102,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
this.socket.close()
}
override suspend fun sendPacket(packet: ClientPacket) = socket.sendPacket(packet)
override suspend fun sendPacket(packet: OutgoingPacket) = socket.sendPacket(packet)
internal inner class BotSocketAdapter(override val serverIp: String, val configuration: BotNetworkConfiguration) : DataPacketSocketAdapter {
override val channel: PlatformDatagramChannel = PlatformDatagramChannel(serverIp, 8000)
@ -154,7 +156,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
loginResult.complete(LoginResult.TIMEOUT)
}
}
sendPacket(ClientTouchPacket(bot.qqAccount, this.serverIp))
sendPacket(OutgoingTouchPacket(bot.qqAccount, this.serverIp))
return loginResult.await()
}
@ -188,7 +190,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
}
handlersLock.withLock {
temporaryPacketHandlers.removeIfInlined {
temporaryPacketHandlers.inlinedRemoveIf {
it.shouldRemove(this@TIMBotNetworkHandler[ActionPacketHandler].session, packet)
}
}
@ -229,7 +231,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
}
}*/
override suspend fun sendPacket(packet: ClientPacket) = withContext(NetworkScope.coroutineContext) {
override suspend fun sendPacket(packet: OutgoingPacket) = withContext(NetworkScope.coroutineContext) {
check(channel.isOpen) { "channel is not open" }
if (BeforePacketSendEvent(bot, packet).broadcast().cancelled) {
@ -305,7 +307,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
this.loginTime = packet.loginTime
this.token0825 = packet.token0825
socket.sendPacket(ClientPasswordSubmissionPacket(
socket.sendPacket(OutgoingPasswordSubmissionPacket(
bot = bot.qqAccount,
password = bot.account.password,
loginTime = loginTime,
@ -327,7 +329,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
this.privateKey = getRandomByteArray(16)//似乎是必须的
this.token00BA = packet.token00BA
socket.sendPacket(ClientPasswordSubmissionPacket(
socket.sendPacket(OutgoingPasswordSubmissionPacket(
bot = bot.qqAccount,
password = bot.account.password,
loginTime = loginTime,
@ -346,7 +348,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
if (packet.unknownBoolean) {
this.captchaSectionId = 1
socket.sendPacket(ClientCaptchaTransmissionRequestPacket(bot.qqAccount, this.token0825, this.captchaSectionId++, packet.token00BA))
socket.sendPacket(OutgoingCaptchaTransmissionRequestPacket(bot.qqAccount, this.token0825, this.captchaSectionId++, packet.token00BA))
}
}
@ -367,26 +369,26 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
this.captchaCache = null
if (code == null) {
this.captchaSectionId = 1//意味着正在刷新验证码
socket.sendPacket(ClientCaptchaRefreshPacket(bot.qqAccount, token0825))
socket.sendPacket(OutgoingCaptchaRefreshPacket(bot.qqAccount, token0825))
} else {
this.captchaSectionId = 0//意味着已经提交验证码
socket.sendPacket(ClientCaptchaSubmitPacket(bot.qqAccount, token0825, code, packet.verificationToken))
socket.sendPacket(OutgoingCaptchaSubmitPacket(bot.qqAccount, token0825, code, packet.verificationToken))
}
} else {
socket.sendPacket(ClientCaptchaTransmissionRequestPacket(bot.qqAccount, token0825, captchaSectionId++, packet.token00BA))
socket.sendPacket(OutgoingCaptchaTransmissionRequestPacket(bot.qqAccount, token0825, captchaSectionId++, packet.token00BA))
}
}
is ServerLoginResponseSuccessPacket -> {
this.sessionResponseDecryptionKey = packet.sessionResponseDecryptionKey
socket.sendPacket(ClientSessionRequestPacket(bot.qqAccount, socket.serverIp, packet.token38, packet.token88, packet.encryptionKey))
socket.sendPacket(OutgoingSessionRequestPacket(bot.qqAccount, socket.serverIp, packet.token38, packet.token88, packet.encryptionKey))
}
//是ClientPasswordSubmissionPacket之后服务器回复的可能之一
is ServerLoginResponseKeyExchangePacket -> {
this.privateKey = packet.privateKeyUpdate
socket.sendPacket(ClientPasswordSubmissionPacket(
socket.sendPacket(OutgoingPasswordSubmissionPacket(
bot = bot.qqAccount,
password = bot.account.password,
loginTime = loginTime,
@ -449,7 +451,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
@Suppress("MemberVisibilityCanBePrivate")
suspend fun setOnlineStatus(status: OnlineStatus) {
socket.sendPacket(ClientChangeOnlineStatusPacket(bot.qqAccount, sessionKey, status))
socket.sendPacket(ChangeOnlineStatusPacket(bot.qqAccount, sessionKey, status))
}
fun close() {

View File

@ -2,24 +2,18 @@
package net.mamoe.mirai.network.protocol.tim.handler
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.isOpen
import net.mamoe.mirai.network.protocol.tim.packet.ClientAccountInfoRequestPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerAccountInfoResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.RequestAccountInfoPacket
import net.mamoe.mirai.network.protocol.tim.packet.ResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerSessionPacket
import net.mamoe.mirai.network.protocol.tim.packet.action.AddFriendResult
import net.mamoe.mirai.network.protocol.tim.packet.action.ClientAddFriendPacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ClientCanAddFriendPacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ServerCanAddFriendResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.ClientSKeyRefreshmentRequestPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.ClientSKeyRequestPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.ServerSKeyResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.login.RequestSKeyPacket
import net.mamoe.mirai.network.qqAccount
import net.mamoe.mirai.utils.log
/**
@ -31,70 +25,58 @@ import net.mamoe.mirai.utils.log
class ActionPacketHandler(session: BotSession) : PacketHandler(session) {
companion object Key : PacketHandler.Key<ActionPacketHandler>
private val addFriendSessions = mutableListOf<AddFriendSession>()
private val uploadImageSessions = mutableListOf<UploadImageSession>()
private var sKeyRefresherJob: Job? = null
@ExperimentalStdlibApi
override suspend fun onPacketReceived(packet: ServerPacket) {
override suspend fun onPacketReceived(packet: ServerPacket) = with(session) {
when (packet) {
is ServerCanAddFriendResponsePacket -> {
this.uploadImageSessions.forEach {
it.onPacketReceived(packet)
}
}
//is AddFriendPacket.Response -> {
// this.uploadImageSessions.forEach {
// it.onPacketReceived(packet)
// }
//}
is ServerAccountInfoResponsePacket.Encrypted -> session.socket.distributePacket(packet.decrypt(session.sessionKey))
is ServerAccountInfoResponsePacket -> {
}
is ServerSKeyResponsePacket.Encrypted -> session.socket.distributePacket(packet.decrypt(session.sessionKey))
is ServerSKeyResponsePacket -> {
session.sKey = packet.sKey
session.cookies = "uin=o" + session.bot.account.account + ";skey=" + session.sKey + ";"
is RequestSKeyPacket.Response -> {
sKey = packet.sKey
cookies = "uin=o$qqAccount;skey=$sKey;"
sKeyRefresherJob = session.scope.launch {
while (session.isOpen) {
delay(1800000)
try {
session.socket.sendPacket(ClientSKeyRefreshmentRequestPacket(session.bot.account.account, session.sessionKey))
} catch (e: Throwable) {
e.log()
if (sKeyRefresherJob?.isActive != true) {
sKeyRefresherJob = NetworkScope.launch {
while (isOpen) {
delay(1800000)
try {
requestSKey()
} catch (e: Throwable) {
e.log()
}
}
}
}
}
is ServerEventPacket.Raw.Encrypted -> session.socket.distributePacket(packet.decrypt(session.sessionKey))
is ServerEventPacket.Raw -> session.socket.distributePacket(packet.distribute())
is ServerSessionPacket.Encrypted<*> -> session.socket.distributePacket(packet.decrypt(session.sessionKey))
is ServerEventPacket.Raw.Encrypted -> socket.distributePacket(packet.decrypt(sessionKey))
is ServerEventPacket.Raw -> socket.distributePacket(packet.distribute())
is ResponsePacket.Encrypted<*> -> socket.distributePacket(packet.decrypt(sessionKey))
else -> {
}
}
}
//@JvmSynthetic
suspend fun addFriend(account: UInt, message: Lazy<String> = lazyOf("")): CompletableDeferred<AddFriendResult> {
val future = CompletableDeferred<AddFriendResult>()
val session = AddFriendSession(account, future, message)
// uploadImageSessions.add(session)
session.sendAddRequest()
return future
suspend fun requestSKey() = with(session) {
withContext(NetworkScope.coroutineContext) {
socket.sendPacket(RequestSKeyPacket())
}
}
suspend fun requestSKey() {
session.socket.sendPacket(ClientSKeyRequestPacket(session.bot.account.account, session.sessionKey))
}
suspend fun requestAccountInfo() {
session.socket.sendPacket(ClientAccountInfoRequestPacket(session.bot.account.account, session.sessionKey))
suspend fun requestAccountInfo() = with(session) {
withContext(NetworkScope.coroutineContext) {
socket.sendPacket(RequestAccountInfoPacket(qqAccount, sessionKey))
}
}
override fun close() {
@ -102,111 +84,6 @@ class ActionPacketHandler(session: BotSession) : PacketHandler(session) {
this.sKeyRefresherJob = null
}
private inner class UploadImageSession(
private val group: Long,
private val future: CompletableDeferred<AddFriendResult>
//private val image: BufferedImage
) {
var id: UShort = UninitializedPacketId
fun onPacketReceived(packet: ServerPacket) {
if (id == UninitializedPacketId) {
return
}
when (packet) {
is ServerCanAddFriendResponsePacket -> {
if (packet.id != id) {
return
}
when (packet.state) {
ServerCanAddFriendResponsePacket.State.FAILED -> {
future.complete(AddFriendResult.FAILED)
close()
}
ServerCanAddFriendResponsePacket.State.ALREADY_ADDED -> {
future.complete(AddFriendResult.ALREADY_ADDED)
close()
}
ServerCanAddFriendResponsePacket.State.REQUIRE_VERIFICATION -> {
// session.socket.sendPacket(ClientAddFriendPacket(session.bot.account.account, qq, session.sessionKey))
}
ServerCanAddFriendResponsePacket.State.NOT_REQUIRE_VERIFICATION -> {
}
}
}
}
}
fun sendRequest() {
}
fun close() {
uploadImageSessions.remove(this)
}
}
private inner class AddFriendSession(
private val qq: UInt,
private val future: CompletableDeferred<AddFriendResult>,
private val message: Lazy<String>
) {
var id: UShort = UninitializedPacketId
suspend fun onPacketReceived(packet: ServerPacket) {
if (id == UninitializedPacketId) {
return
}
when (packet) {
is ServerCanAddFriendResponsePacket -> {
if (packet.id != id) {
return
}
when (packet.state) {
ServerCanAddFriendResponsePacket.State.FAILED -> {
future.complete(AddFriendResult.FAILED)
close()
}
ServerCanAddFriendResponsePacket.State.ALREADY_ADDED -> {
future.complete(AddFriendResult.ALREADY_ADDED)
close()
}
ServerCanAddFriendResponsePacket.State.REQUIRE_VERIFICATION -> {
session.socket.sendPacket(ClientAddFriendPacket(session.bot.account.account, qq, session.sessionKey))
}
ServerCanAddFriendResponsePacket.State.NOT_REQUIRE_VERIFICATION -> {
}
}
}
}
}
suspend fun sendAddRequest() {
session.socket.sendPacket(ClientCanAddFriendPacket(session.bot.account.account, qq, session.sessionKey))
}
fun close() {
// uploadImageSessions.remove(this)
}
}
}
private val UninitializedPacketId: UShort = 0u

View File

@ -5,7 +5,7 @@ import net.mamoe.mirai.Bot
import net.mamoe.mirai.event.events.ServerPacketReceivedEvent
import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.utils.PlatformDatagramChannel
@ -43,7 +43,7 @@ interface DataPacketSocketAdapter : Closeable {
*
* @see [BotSession.sendAndExpect] kotlin DSL
*/
suspend fun sendPacket(packet: ClientPacket)
suspend fun sendPacket(packet: OutgoingPacket)
override fun close()
}

View File

@ -12,10 +12,8 @@ import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.distributePacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerFriendOnlineStatusChangedPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ClientSendFriendMessagePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ClientSendGroupMessagePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ServerSendFriendMessageResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ServerSendGroupMessageResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.SendFriendMessagePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.SendGroupMessagePacket
import net.mamoe.mirai.network.protocol.tim.packet.event.IgnoredServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerFriendMessageEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerGroupMessageEventPacket
@ -55,11 +53,6 @@ class EventPacketHandler(session: BotSession) : PacketHandler(session) {
).broadcast()
}
is ServerSendFriendMessageResponsePacket,
is ServerSendGroupMessageResponsePacket -> {
//ignored
}
is ServerFriendOnlineStatusChangedPacket.Encrypted -> distributePacket(packet.decrypt(sessionKey))
is ServerFriendOnlineStatusChangedPacket -> {
//TODO
@ -75,10 +68,10 @@ class EventPacketHandler(session: BotSession) : PacketHandler(session) {
}
suspend fun sendFriendMessage(qq: QQ, message: MessageChain) {
session.socket.sendPacket(ClientSendFriendMessagePacket(session.bot.account.account, qq.number, session.sessionKey, message))
session.socket.sendPacket(SendFriendMessagePacket(session.bot.account.account, qq.number, session.sessionKey, message))
}
suspend fun sendGroupMessage(group: Group, message: MessageChain) {
session.socket.sendPacket(ClientSendGroupMessagePacket(session.bot.account.account, group.groupId, session.sessionKey, message))
session.socket.sendPacket(SendGroupMessagePacket(session.bot.account.account, group.groupId, session.sessionKey, message))
}
}

View File

@ -2,7 +2,7 @@ package net.mamoe.mirai.network.protocol.tim.handler
import kotlinx.coroutines.CompletableDeferred
import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import kotlin.reflect.KClass
@ -10,7 +10,7 @@ import kotlin.reflect.KClass
* 临时数据包处理器
* ```kotlin
* session.addHandler<ClientTouchResponsePacket>{
* toSend { ClientTouchPacket() }
* toSend { OutgoingTouchPacket() }
* onExpect {//it: ClientTouchResponsePacket
* //do sth.
* }
@ -24,14 +24,14 @@ class TemporaryPacketHandler<P : ServerPacket, R>(
private val deferred: CompletableDeferred<R>,
private val fromSession: BotSession
) {
private lateinit var toSend: ClientPacket
private lateinit var toSend: OutgoingPacket
private lateinit var handler: suspend (P) -> R
lateinit var session: BotSession//无需覆盖
fun toSend(packet: ClientPacket) {
fun toSend(packet: OutgoingPacket) {
this.toSend = packet
}

View File

@ -16,10 +16,10 @@ import net.mamoe.mirai.utils.writeQQ
* @author Him188moe
*/
@PacketId(0x00_5Cu)
class ClientAccountInfoRequestPacket(
class RequestAccountInfoPacket(
private val qq: UInt,
private val sessionKey: ByteArray
) : ClientPacket() {
) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
this.writeQQ(qq)
this.writeHex(TIMProtocol.fixVer2)
@ -29,19 +29,11 @@ class ClientAccountInfoRequestPacket(
writeByte(0x00)
}
}
}
@PacketId(0x00_5Cu)
class ServerAccountInfoResponsePacket(input: ByteReadPacket) : ServerPacket(input) {
//等级
//升级剩余活跃天数
//ignored
override fun decode() {
}
@PacketId(0x00_5Cu)
class Encrypted(input: ByteReadPacket) : ServerPacket(input) {
fun decrypt(sessionKey: ByteArray): ServerAccountInfoResponsePacket = ServerAccountInfoResponsePacket(this.decryptBy(sessionKey)).applySequence(sequenceId)
class Response(input: ByteReadPacket) : ResponsePacket(input) {
//等级
//升级剩余活跃天数
//ignored
}
}

View File

@ -13,7 +13,7 @@ import net.mamoe.mirai.utils.writeQQ
class HeartbeatPacket(
private val bot: UInt,
private val sessionKey: ByteArray
) : ClientPacket() {
) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
writeQQ(bot)
writeHex(TIMProtocol.fixVer)
@ -23,5 +23,5 @@ class HeartbeatPacket(
}
@PacketId(0x00_58u)
class Response(input: ByteReadPacket) : ServerSessionPacket(input)
class Response(input: ByteReadPacket) : ResponsePacket(input)
}

View File

@ -8,9 +8,9 @@ import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.utils.writeHex
/**
* 发给服务器的数据包. 必须有 [PacketId] 注解或 `override` [packetId]. 否则将会抛出 [IllegalStateException]
* 发给服务器的数据包. 必须有 [PacketId] 注解或 `override` [id]. 否则将会抛出 [IllegalStateException]
*/
abstract class ClientPacket : Packet(), Closeable {
abstract class OutgoingPacket : Packet(), Closeable {
/**
* Encode this packet.
*
@ -53,7 +53,7 @@ abstract class ClientPacket : Packet(), Closeable {
override fun close() = if (this.packet === UninitializedByteReadPacket) Unit else this.packet.close()
private fun BytePacketBuilder.writePacketId() {
writeUShort(this@ClientPacket.id)
writeUShort(this@OutgoingPacket.id)
writeUShort(sequenceId)
}
}

View File

@ -7,13 +7,13 @@ import kotlinx.io.core.writeFully
import net.mamoe.mirai.utils.encryptAndWrite
import net.mamoe.mirai.utils.writeQQ
class ClientRawPacket(
class OutgoingRawPacket(
override val id: UShort,
private val bot: UInt,
private val version: ByteArray,
private val sessionKey: ByteArray,
private val data: ByteArray
) : ClientPacket() {
) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
writeQQ(bot)
writeFully(version)

View File

@ -0,0 +1,27 @@
package net.mamoe.mirai.network.protocol.tim.packet
import kotlinx.io.core.ByteReadPacket
/**
* 返回包.
* 在登录完成后, 任意一个 [OutgoingPacket] 发送后服务器都会给返回包. 则一个 [OutgoingPacket] 一定对应一个 [ResponsePacket]
* 它们都使用 sessionKey 解密.
* 它们都必须有一个公开的仅有一个 [ByteReadPacket] 参数的构造器.
*
* 注意: 需要指定 ID, 通过 [PacketId].
*/
abstract class ResponsePacket(input: ByteReadPacket) : ServerPacket(input) {
/**
* 加密过的 [ResponsePacket]. 将会在处理时解密为对应的 [ResponsePacket]
*/
class Encrypted<P : ResponsePacket>(input: ByteReadPacket, val constructor: (ByteReadPacket) -> P) : ServerPacket(input) {
fun decrypt(sessionKey: ByteArray): P = constructor(decryptBy(sessionKey)).applySequence(sequenceId)
}
companion object {
@Suppress("FunctionName")
inline fun <reified P : ResponsePacket> Encrypted(input: ByteReadPacket): Encrypted<P> = Encrypted(input) { P::class.constructors.first().call(it) }
}
}

View File

@ -6,14 +6,19 @@ import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.Closeable
import kotlinx.io.core.IoBuffer
import kotlinx.io.core.readBytes
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.TEA
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.io.cutTail
import net.mamoe.mirai.utils.io.parseServerPacket
import net.mamoe.mirai.utils.io.readRemainingBytes
import net.mamoe.mirai.utils.io.toReadPacket
import kotlin.properties.Delegates
/**
* 来自服务器的数据包
*
* @see parseServerPacket
* @see parseServerPacket 解析包种类
*/
abstract class ServerPacket(val input: ByteReadPacket) : Packet(), Closeable {
override val id: UShort by lazy { super.id }

View File

@ -1,26 +0,0 @@
package net.mamoe.mirai.network.protocol.tim.packet
import kotlinx.io.core.ByteReadPacket
/**
* 登录完成之后的所有 packet.
* 它们都使用 sessionKey 解密.
* 它们都必须有一个公开的仅有一个 [ByteReadPacket] 参数的构造器.
*
* 注意: 需要为指定 ID, 通过 [PacketId].
*/
abstract class ServerSessionPacket(input: ByteReadPacket) : ServerPacket(input) {
/**
* 加密过的 [ServerSessionPacket]. 将会在处理时解密为对应的 [ServerSessionPacket]
*/
class Encrypted<P : ServerSessionPacket>(input: ByteReadPacket, val constructor: (ByteReadPacket) -> P) : ServerPacket(input) {
fun decrypt(sessionKey: ByteArray): P = constructor(decryptBy(sessionKey)).applySequence(sequenceId)
}
companion object {
@Suppress("FunctionName")
inline fun <reified P : ServerSessionPacket> Encrypted(input: ByteReadPacket): Encrypted<P> = Encrypted(input) { P::class.constructors.first().call(it) }
}
}

View File

@ -6,7 +6,7 @@ import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.readBytes
import net.mamoe.mirai.utils.LoggerTextFormat
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.toUHexString
import net.mamoe.mirai.utils.io.toUHexString
class UnknownServerPacket(

View File

@ -5,11 +5,12 @@ package net.mamoe.mirai.network.protocol.tim.packet
import kotlinx.io.core.*
import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.message.ImageId
import net.mamoe.mirai.network.account
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.qqAccount
import net.mamoe.mirai.network.session
import net.mamoe.mirai.qqAccount
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.*
/**
* 上传图片
@ -17,14 +18,14 @@ import net.mamoe.mirai.utils.*
suspend fun QQ.uploadImage(image: BufferedImage): ImageId = with(bot.network.session) {
//SubmitImageFilenamePacket(account, account, "sdiovaoidsa.png", sessionKey).sendAndExpect<ServerSubmitImageFilenameResponsePacket>().join()
DebugLogger.logPurple("正在上传好友图片, md5=${image.md5.toUHexString()}")
return FriendImageIdRequestPacket(account, sessionKey, account, image).sendAndExpect<FriendImageIdRequestPacket.Response, ImageId> {
return FriendImageIdRequestPacket(this.qqAccount, sessionKey, this.qqAccount, image).sendAndExpect<FriendImageIdRequestPacket.Response, ImageId> {
if (it.uKey != null)
require(httpPostFriendImage(
uKeyHex = it.uKey!!.toUHexString(""),
botNumber = bot.qqAccount,
imageData = image.data,
fileSize = image.fileSize,
qq = account
qq = this.qqAccount
))
it.imageId!!
}.await()
@ -49,7 +50,7 @@ class SubmitImageFilenamePacket(
private val target: UInt,
private val filename: String,
private val sessionKey: ByteArray
) : ClientPacket() {
) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
writeQQ(bot)
writeHex(TIMProtocol.fixVer2)//?
@ -80,7 +81,7 @@ class SubmitImageFilenamePacket(
@PacketId(0x01_BDu)
@PacketVersion(date = "2019.10.19", timVersion = "2.3.2.21173")
class Response(input: ByteReadPacket) : ServerSessionPacket(input) {
class Response(input: ByteReadPacket) : ResponsePacket(input) {
override fun decode() = with(input) {
require(readBytes().contentEquals(expecting))
}
@ -105,7 +106,7 @@ class FriendImageIdRequestPacket(
private val sessionKey: ByteArray,
private val target: UInt,
private val image: BufferedImage
) : ClientPacket() {
) : OutgoingPacket() {
//00 00 00 07 00 00 00 4B 08 01 12 03 98 01 01 08 01 12 47 08 A2 FF 8C F0 03 10 89 FC A6 8C 0B 18 00 22 10 2B 23 D7 05 CA D1 F2 CF 37 10 FE 58 26 92 FC C4 28 FD 08 32 1A 7B 00 47 00 47 00 42 00 7E 00 49 00 31 00 5A 00 4D 00 43 00 28 00 25 00 49 00 38 01 48 00 70 42 78 42
@ -253,7 +254,7 @@ class FriendImageIdRequestPacket(
@PacketId(0x0352u)
@PacketVersion(date = "2019.10.20", timVersion = "2.3.2.21173")
class Response(input: ByteReadPacket) : ServerSessionPacket(input) {
class Response(input: ByteReadPacket) : ResponsePacket(input) {
var uKey: ByteArray? = null//最终可能为null
var imageId: ImageId? = null//最终不会为null

View File

@ -7,6 +7,8 @@ import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.network.session
import net.mamoe.mirai.qqAccount
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.read
import net.mamoe.mirai.utils.io.toUHexString
suspend fun Group.uploadImage(
@ -36,7 +38,7 @@ class GroupImageIdRequestPacket(
private val groupId: UInt,
private val image: BufferedImage,
private val sessionKey: ByteArray
) : ClientPacket() {
) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
//未知图片A
@ -235,7 +237,7 @@ class GroupImageIdRequestPacket(
@PacketId(0x0388u)
@PacketVersion(date = "2019.10.20", timVersion = "2.3.2.21173")
class Response(input: ByteReadPacket) : ServerSessionPacket(input) {
class Response(input: ByteReadPacket) : ResponsePacket(input) {
var uKey: ByteArray? = null
override fun decode(): Unit = with(input) {

View File

@ -18,11 +18,11 @@ import net.mamoe.mirai.utils.writeQQ
* @author Him188moe
*/
@PacketId(0x00_A7u)
class ClientCanAddFriendPacket(
class CanAddFriendPacket(
val bot: UInt,
val qq: UInt,
val sessionKey: ByteArray
) : ClientPacket() {
) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
writeQQ(bot)
writeHex(TIMProtocol.fixVer2)
@ -30,70 +30,62 @@ class ClientCanAddFriendPacket(
writeQQ(qq)
}
}
}
@PacketId(0x00_A7u)
class ServerCanAddFriendResponsePacket(input: ByteReadPacket) : ServerPacket(input) {
lateinit var state: State
enum class State {
/**
* 已经添加
*/
ALREADY_ADDED,
/**
* 需要验证信息
*/
REQUIRE_VERIFICATION,
/**
* 不需要验证信息
*/
NOT_REQUIRE_VERIFICATION,
/**
* 对方拒绝添加
*/
FAILED,
}
override fun decode() = with(input) {
//需要验证信息 00 23 24 8B 00 01
if (input.remaining > 20) {//todo check
state = State.ALREADY_ADDED
return
}
discardExact(4)//对方qq号
state = when (val state = readUShort().toUInt()) {
0x00u -> State.NOT_REQUIRE_VERIFICATION
0x01u -> State.REQUIRE_VERIFICATION//需要验证信息
0x99u -> State.ALREADY_ADDED
0x03u,
0x04u -> State.FAILED
else -> throw IllegalStateException(state.toString())
}
}
@PacketId(0x00_A7u)
class Encrypted(input: ByteReadPacket) : ServerPacket(input) {
fun decrypt(sessionKey: ByteArray): ServerCanAddFriendResponsePacket {
return ServerCanAddFriendResponsePacket(decryptBy(sessionKey)).applySequence(sequenceId)
class Response(input: ByteReadPacket) : ResponsePacket(input) {
lateinit var state: State
enum class State {
/**
* 已经添加
*/
ALREADY_ADDED,
/**
* 需要验证信息
*/
REQUIRE_VERIFICATION,
/**
* 不需要验证信息
*/
NOT_REQUIRE_VERIFICATION,
/**
* 对方拒绝添加
*/
FAILED,
}
override fun decode() = with(input) {
//需要验证信息 00 23 24 8B 00 01
if (input.remaining > 20) {//todo check
state = State.ALREADY_ADDED
return
}
discardExact(4)//对方qq号
state = when (val state = readUShort().toUInt()) {
0x00u -> State.NOT_REQUIRE_VERIFICATION
0x01u -> State.REQUIRE_VERIFICATION//需要验证信息
0x99u -> State.ALREADY_ADDED
0x03u,
0x04u -> State.FAILED
else -> throw IllegalStateException(state.toString())
}
}
}
}
/**
* 请求添加好友
*/
@PacketId(0x00_AEu)
class ClientAddFriendPacket(
class AddFriendPacket(
val bot: UInt,
val qq: UInt,
val sessionKey: ByteArray
) : ClientPacket() {
) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
this.writeQQ(bot)
this.writeHex(TIMProtocol.fixVer2)
@ -102,14 +94,8 @@ class ClientAddFriendPacket(
writeQQ(qq)
}
}
}
class ServerAddFriendResponsePacket(input: ByteReadPacket) : ServerAddContactResponsePacket(input)
class ServerAddGroupResponsePacket(input: ByteReadPacket) : ServerAddContactResponsePacket(input)
/**
* 添加好友/群的回复
*/

View File

@ -3,7 +3,7 @@
package net.mamoe.mirai.network.protocol.tim.packet.action
import kotlinx.io.core.BytePacketBuilder
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.PacketId
// 用户资料的头像
@ -11,7 +11,7 @@ import net.mamoe.mirai.network.protocol.tim.packet.PacketId
* 请求获取头像
*/
@PacketId(0x00_31u)
class ClientProfilePictureRequestPacket : ClientPacket() {
class RequestProfilePicturePacket : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) {
TODO("not implemented")
}

View File

@ -8,26 +8,26 @@ import net.mamoe.mirai.message.internal.toPacket
import net.mamoe.mirai.message.toChain
import net.mamoe.mirai.message.toMessage
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.PacketId
import net.mamoe.mirai.network.protocol.tim.packet.PacketVersion
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.ResponsePacket
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.toUHexString
fun main() {
println("牛逼".toMessage().toChain().toPacket(true).readBytes().toUHexString())
}
@PacketId(0x00_CDu)
class ClientSendFriendMessagePacket(
@PacketVersion(date = "2019.10.19", timVersion = "2.3.2.21173")
class SendFriendMessagePacket(
private val botQQ: UInt,
private val targetQQ: UInt,
private val sessionKey: ByteArray,
private val message: MessageChain
) : ClientPacket() {
) : OutgoingPacket() {
@PacketVersion(date = "2019.10.19", timVersion = "2.3.2.21173")
override fun encode(builder: BytePacketBuilder) = with(builder) {
writeQQ(botQQ)
writeHex(TIMProtocol.version0x02)
@ -124,7 +124,7 @@ class ClientSendFriendMessagePacket(
it.write(bytes)*/
}
}
}
@PacketId(0x00_CDu)
class ServerSendFriendMessageResponsePacket(input: ByteReadPacket) : ServerPacket(input)
@PacketId(0x00_CDu)
class Response(input: ByteReadPacket) : ResponsePacket(input)
}

View File

@ -7,19 +7,19 @@ import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.message.internal.toPacket
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.PacketId
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.ResponsePacket
import net.mamoe.mirai.utils.*
@PacketId(0x00_02u)
class ClientSendGroupMessagePacket(
class SendGroupMessagePacket(
private val botQQ: UInt,
private val groupId: UInt,//不是 number
private val sessionKey: ByteArray,
private val message: MessageChain
) : ClientPacket() {
) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
this.writeQQ(botQQ)
this.writeHex(TIMProtocol.fixVer2)
@ -47,7 +47,7 @@ class ClientSendGroupMessagePacket(
it.write(bytes)*/
}
}
}
@PacketId(0x00_02u)
class ServerSendGroupMessageResponsePacket(input: ByteReadPacket) : ServerPacket(input)
@PacketId(0x00_02u)
class Response(input: ByteReadPacket) : ResponsePacket(input)
}

View File

@ -4,7 +4,7 @@ package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import net.mamoe.mirai.utils.readString
import net.mamoe.mirai.utils.io.readString
/**

View File

@ -7,7 +7,7 @@ import kotlinx.io.core.discardExact
import kotlinx.io.core.readUInt
import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.message.internal.readMessageChain
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.*
import kotlin.properties.Delegates

View File

@ -4,11 +4,14 @@ package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.*
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.applySequence
import net.mamoe.mirai.network.protocol.tim.packet.decryptBy
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.readBoolean
import net.mamoe.mirai.utils.io.readIoBuffer
import net.mamoe.mirai.utils.io.toUHexString
/**
* 事件的识别 ID. [事件确认包][ServerEventPacket.ResponsePacket] 中被使用.
@ -103,7 +106,7 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
inner class ResponsePacket(
val bot: UInt,
val sessionKey: ByteArray
) : ClientPacket() {
) : OutgoingPacket() {
override val id: UShort get() = this@ServerEventPacket.id
override val sequenceId: UShort get() = this@ServerEventPacket.sequenceId

View File

@ -5,7 +5,7 @@ package net.mamoe.mirai.network.protocol.tim.packet.login
import kotlinx.io.core.BytePacketBuilder
import kotlinx.io.core.writeUByte
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.PacketId
import net.mamoe.mirai.utils.OnlineStatus
import net.mamoe.mirai.utils.encryptAndWrite
@ -16,11 +16,11 @@ import net.mamoe.mirai.utils.writeQQ
* 改变在线状态: "我在线上", "隐身"
*/
@PacketId(0x00_ECu)
class ClientChangeOnlineStatusPacket(
class ChangeOnlineStatusPacket(
private val bot: UInt,
private val sessionKey: ByteArray,
private val loginStatus: OnlineStatus
) : ClientPacket() {
) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
this.writeQQ(bot)
this.writeHex(TIMProtocol.fixVer2)

View File

@ -6,7 +6,7 @@ import kotlinx.io.core.BytePacketBuilder
import kotlinx.io.core.IoBuffer
import kotlinx.io.core.writeFully
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.PacketId
import net.mamoe.mirai.utils.*
@ -15,7 +15,7 @@ import net.mamoe.mirai.utils.*
* 提交密码
*/
@PacketId(0x08_36u)
class ClientPasswordSubmissionPacket constructor(
class OutgoingPasswordSubmissionPacket constructor(
private val bot: UInt,
private val password: String,
private val loginTime: Int,
@ -25,7 +25,7 @@ class ClientPasswordSubmissionPacket constructor(
private val token00BA: ByteArray? = null,
private val randomDeviceName: Boolean = false,
private val tlv0006: IoBuffer? = null
) : ClientPacket() {
) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
writeQQ(bot)
writeHex(TIMProtocol.passwordSubmissionTLV1)

View File

@ -5,18 +5,31 @@ package net.mamoe.mirai.network.protocol.tim.packet.login
import kotlinx.io.core.BytePacketBuilder
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.PacketId
import net.mamoe.mirai.network.protocol.tim.packet.ResponsePacket
import net.mamoe.mirai.network.qqAccount
import net.mamoe.mirai.utils.encryptAndWrite
import net.mamoe.mirai.utils.io.DebugLogger
import net.mamoe.mirai.utils.io.readRemainingBytes
import net.mamoe.mirai.utils.io.readString
import net.mamoe.mirai.utils.io.toUHexString
import net.mamoe.mirai.utils.writeHex
import net.mamoe.mirai.utils.writeQQ
fun BotSession.RequestSKeyPacket() = RequestSKeyPacket(qqAccount, sessionKey)
/**
* 请求 `SKey`
* SKey 用于 http api
*/
@PacketId(0x00_1Du)
class ClientSKeyRequestPacket(
class RequestSKeyPacket(
private val qq: UInt,
private val sessionKey: ByteArray
) : ClientPacket() {
) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
writeQQ(qq)
writeHex(TIMProtocol.fixVer2)
@ -24,35 +37,17 @@ class ClientSKeyRequestPacket(
writeHex("33 00 05 00 08 74 2E 71 71 2E 63 6F 6D 00 0A 71 75 6E 2E 71 71 2E 63 6F 6D 00 0C 71 7A 6F 6E 65 2E 71 71 2E 63 6F 6D 00 0C 6A 75 62 61 6F 2E 71 71 2E 63 6F 6D 00 09 6B 65 2E 71 71 2E 63 6F 6D")
}
}
}
@PacketId(0x00_1Du)
class ClientSKeyRefreshmentRequestPacket(
private val qq: UInt,
private val sessionKey: ByteArray
) : ClientPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
this.writeQQ(qq)
this.encryptAndWrite(sessionKey) {
writeHex("33 00 05 00 08 74 2E 71 71 2E 63 6F 6D 00 0A 71 75 6E 2E 71 71 2E 63 6F 6D 00 0C 71 7A 6F 6E 65 2E 71 71 2E 63 6F 6D 00 0C 6A 75 62 61 6F 2E 71 71 2E 63 6F 6D 00 09 6B 65 2E 71 71 2E 63 6F 6D")
@PacketId(0x00_1Du)
class Response(input: ByteReadPacket) : ResponsePacket(input) {
lateinit var sKey: String
override fun decode() = with(input) {
discardExact(4)
//debugDiscardExact(2)
sKey = this.readString(10)//16??
DebugLogger.logPurple("SKey=$sKey")
DebugLogger.logPurple("Skey包后面${this.readRemainingBytes().toUHexString()}")
}
}
}
@PacketId(0x00_1Du)
class ServerSKeyResponsePacket(input: ByteReadPacket) : ServerPacket(input) {
lateinit var sKey: String
override fun decode() = with(input) {
discardExact(4)
//debugDiscardExact(2)
sKey = this.readString(10)//16??
DebugLogger.logPurple("SKey=$sKey")
DebugLogger.logPurple("Skey包后面${this.readRemainingBytes().toUHexString()}")
}
@PacketId(0x00_1Du)
class Encrypted(input: ByteReadPacket) : ServerPacket(input) {
fun decrypt(sessionKey: ByteArray): ServerSKeyResponsePacket = ServerSKeyResponsePacket(this.decryptBy(sessionKey)).applySequence(sequenceId)
}
}

View File

@ -5,7 +5,11 @@ package net.mamoe.mirai.network.protocol.tim.packet.login
import kotlinx.io.core.*
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.Tested
import net.mamoe.mirai.utils.io.readBoolean
import net.mamoe.mirai.utils.io.readIoBuffer
import net.mamoe.mirai.utils.io.readString
import net.mamoe.mirai.utils.io.toReadPacket
import kotlin.properties.Delegates
@PacketId(0x08_36u)

View File

@ -6,15 +6,16 @@ import kotlinx.io.core.*
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.readIoBuffer
@PacketId(0x08_28u)
class ClientSessionRequestPacket(
class OutgoingSessionRequestPacket(
private val bot: UInt,
private val serverIp: String,
private val token38: IoBuffer,
private val token88: IoBuffer,
private val encryptionKey: IoBuffer
) : ClientPacket() {
) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
this.writeQQ(bot)
this.writeHex("02 00 00 00 01 2E 01 00 00 68 52 00 30 00 3A")

View File

@ -9,12 +9,13 @@ import kotlinx.io.core.readBytes
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.readIP
/**
* The packet received when logging in, used to redirect server address
*
* @see ClientTouchRedirectionPacket
* @see ClientPasswordSubmissionPacket
* @see OutgoingTouchRedirectionPacket
* @see OutgoingPasswordSubmissionPacket
*
* @author Him188moe
*/
@ -60,7 +61,7 @@ class ServerTouchResponsePacket(input: ByteReadPacket) : ServerPacket(input) {
* @author Him188moe
*/
@PacketId(0x08_25u)
class ClientTouchPacket(private val bot: UInt, private val serverIp: String) : ClientPacket() {
class OutgoingTouchPacket(private val bot: UInt, private val serverIp: String) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
this.writeQQ(bot)
this.writeHex(TIMProtocol.fixVer)
@ -84,7 +85,7 @@ class ClientTouchPacket(private val bot: UInt, private val serverIp: String) : C
* @author Him188moe
*/
@PacketId(0x08_25u)
class ClientTouchRedirectionPacket(private val serverIP: String, private val qq: UInt) : ClientPacket() {
class OutgoingTouchRedirectionPacket(private val serverIP: String, private val qq: UInt) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
this.writeQQ(qq)
this.writeHex(TIMProtocol.fixVer)

View File

@ -5,18 +5,23 @@ package net.mamoe.mirai.network.protocol.tim.packet.login
import kotlinx.io.core.*
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.Tested
import net.mamoe.mirai.utils.encryptAndWrite
import net.mamoe.mirai.utils.io.readIoBuffer
import net.mamoe.mirai.utils.io.toReadPacket
import net.mamoe.mirai.utils.writeHex
import net.mamoe.mirai.utils.writeQQ
/**
* 客户端请求验证码图片数据的第几部分
*/
@PacketId(0x00_BAu)
class ClientCaptchaTransmissionRequestPacket(
class OutgoingCaptchaTransmissionRequestPacket(
private val qq: UInt,
private val token0825: ByteArray,
private val verificationSequence: Int,
private val token00BA: ByteArray
) : ClientPacket() {
) : OutgoingPacket() {
@Tested
override fun encode(builder: BytePacketBuilder) = with(builder) {
this.writeQQ(qq)
@ -43,12 +48,12 @@ class ClientCaptchaTransmissionRequestPacket(
* 提交验证码
*/
@PacketId(0x00_BAu)
class ClientCaptchaSubmitPacket(
class OutgoingCaptchaSubmitPacket(
private val qq: UInt,
private val token0825: ByteArray,
private val captcha: String,
private val verificationToken: IoBuffer
) : ClientPacket() {
) : OutgoingPacket() {
init {
require(captcha.length == 4) { "captcha.length must == 4" }
}
@ -82,10 +87,10 @@ class ClientCaptchaSubmitPacket(
* 刷新验证码
*/
@PacketId(0x00_BAu)
class ClientCaptchaRefreshPacket(
class OutgoingCaptchaRefreshPacket(
private val qq: UInt,
private val token0825: ByteArray
) : ClientPacket() {
) : OutgoingPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) {
this.writeQQ(qq)
this.writeHex(TIMProtocol.fixVer)

View File

@ -1,9 +0,0 @@
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.utils
data class BotAccount(
val account: UInt,
val password: String//todo 不保存 password?
)

View File

@ -12,6 +12,9 @@ class BufferedImage(
) {
val fileSize: Long = data.remaining
/**
* 用于发送消息的 [ImageId]
*/
val groupImageId: ImageId by lazy { ImageId("{${md5[0..3]}-${md5[4..5]}-${md5[6..7]}-${md5[8..9]}-${md5[10..15]}}.$format") }
override fun toString(): String = "[BufferedImage(${width}x${height} $format)]"

View File

@ -1,12 +0,0 @@
package net.mamoe.mirai.utils
inline fun <T> MutableIterable<T>.removeIfInlined(predicate: (T) -> Boolean) = iterator().removeIfInlined(predicate)
inline fun <T> MutableIterator<T>.removeIfInlined(predicate: (T) -> Boolean) {
while (this.hasNext()) {
if (predicate(this.next())) {
this.remove()
}
}
}

View File

@ -6,7 +6,7 @@ package net.mamoe.mirai.utils
* QQ 在线状态
*
* @author Him188moe
* @see net.mamoe.mirai.network.protocol.tim.packet.login.ClientChangeOnlineStatusPacket
* @see net.mamoe.mirai.network.protocol.tim.packet.login.ChangeOnlineStatusPacket
*/
enum class OnlineStatus(
val id: UByte//1 ubyte

View File

@ -4,6 +4,7 @@ package net.mamoe.mirai.utils
import com.soywiz.klock.DateTime
import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.utils.io.printStringFromHex
/**
* 时间戳

View File

@ -2,6 +2,7 @@ package net.mamoe.mirai.utils
import kotlinx.io.core.IoBuffer
import kotlinx.io.core.readBytes
import net.mamoe.mirai.utils.io.toUHexString
import kotlin.jvm.JvmStatic
internal expect object TEA { //TODO 优化为 buffer

View File

@ -0,0 +1,15 @@
@file:JvmName("IterableUtil")
package net.mamoe.mirai.utils
import kotlin.jvm.JvmName
internal inline fun <T> MutableIterable<T>.inlinedRemoveIf(predicate: (T) -> Boolean) = iterator().inlinedRemoveIf(predicate)
internal inline fun <T> MutableIterator<T>.inlinedRemoveIf(predicate: (T) -> Boolean) {
while (this.hasNext()) {
if (predicate(this.next())) {
this.remove()
}
}
}

View File

@ -1,6 +1,6 @@
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
package net.mamoe.mirai.utils
package net.mamoe.mirai.utils.io
import kotlinx.io.charsets.Charset
import kotlinx.io.charsets.Charsets

View File

@ -1,6 +1,10 @@
package net.mamoe.mirai.utils
package net.mamoe.mirai.utils.io
import kotlinx.io.core.*
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.PlatformLogger
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.toIoBuffer
internal object DebugLogger : MiraiLogger by PlatformLogger("Packet Debug")

View File

@ -1,15 +1,17 @@
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
package net.mamoe.mirai.utils
package net.mamoe.mirai.utils.io
import kotlinx.io.core.*
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.network.protocol.tim.packet.action.ServerCanAddFriendResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ServerSendFriendMessageResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ServerSendGroupMessageResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.CanAddFriendPacket
import net.mamoe.mirai.network.protocol.tim.packet.action.SendFriendMessagePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.SendGroupMessagePacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.*
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.decryptBy
fun ByteReadPacket.readRemainingBytes(
@ -71,19 +73,19 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket {
0x08_28u -> ServerSessionKeyResponsePacket.Encrypted(this)
0x00_ECu -> ServerLoginSuccessPacket(this)
0x00_1Du -> ServerSKeyResponsePacket.Encrypted(this)
0x00_5Cu -> ServerAccountInfoResponsePacket.Encrypted(this)
0x00_BAu -> ServerCaptchaPacket.Encrypted(this)
0x00_CEu, 0x00_17u -> ServerEventPacket.Raw.Encrypted(this, id, sequenceId)
0x00_81u -> ServerFriendOnlineStatusChangedPacket.Encrypted(this)
0x00_CDu -> ServerSendFriendMessageResponsePacket(this)
0x00_02u -> ServerSendGroupMessageResponsePacket(this)
0x00_A7u -> ServerCanAddFriendResponsePacket(this)
0x00_58u -> ServerSessionPacket.Encrypted<HeartbeatPacket.Response>(this)
0x03_88u -> ServerSessionPacket.Encrypted<GroupImageIdRequestPacket.Response>(this)
0x03_52u -> ServerSessionPacket.Encrypted<FriendImageIdRequestPacket.Response>(this)
0x01_BDu -> ServerSessionPacket.Encrypted<SubmitImageFilenamePacket.Response>(this)
0x00_1Du -> ResponsePacket.Encrypted<RequestSKeyPacket.Response>(this)
0X00_5Cu -> ResponsePacket.Encrypted<RequestAccountInfoPacket.Response>(this)
0x00_02u -> ResponsePacket.Encrypted<SendGroupMessagePacket.Response>(this)
0x00_CDu -> ResponsePacket.Encrypted<SendFriendMessagePacket.Response>(this)
0x00_A7u -> ResponsePacket.Encrypted<CanAddFriendPacket.Response>(this)
0x00_58u -> ResponsePacket.Encrypted<HeartbeatPacket.Response>(this)
0x03_88u -> ResponsePacket.Encrypted<GroupImageIdRequestPacket.Response>(this)
0x03_52u -> ResponsePacket.Encrypted<FriendImageIdRequestPacket.Response>(this)
0x01_BDu -> ResponsePacket.Encrypted<SubmitImageFilenamePacket.Response>(this)
else -> UnknownServerPacket.Encrypted(this, id, sequenceId)
}.applySequence(sequenceId)

View File

@ -4,6 +4,7 @@ package net.mamoe.mirai.utils
import kotlinx.io.core.IoBuffer
import kotlinx.io.core.writeFully
import net.mamoe.mirai.utils.io.toUHexString
import kotlin.jvm.Synchronized
import kotlin.random.Random
import kotlin.random.nextInt

View File

@ -4,7 +4,7 @@ package net.mamoe.mirai.network.protocol.tim.packet
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.IoBuffer
import net.mamoe.mirai.utils.toUHexString
import net.mamoe.mirai.utils.io.toUHexString
import java.lang.reflect.Field
internal object PacketNameFormatter {

View File

@ -2,6 +2,13 @@
package net.mamoe.mirai.utils
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.request.post
import io.ktor.content.ByteArrayContent
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.http.URLProtocol
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.io.core.ByteReadPacket
@ -14,6 +21,9 @@ import java.util.zip.CRC32
actual val deviceName: String = InetAddress.getLocalHost().hostName
/*
* TODO we may use libraries that provide these functions
*/
actual fun crc32(key: ByteArray): Int = CRC32().let { it.update(key); it.value.toInt() }
@ -23,27 +33,37 @@ actual fun solveIpAddress(hostname: String): String = InetAddress.getByName(host
actual fun localIpAddress(): String = InetAddress.getLocalHost().hostAddress
fun main() {
"00 00 00 08 00 00 01 0D 12 06 98 01 01 A0 01 00 08 01 12 86 02 08 00 10 AB A7 89 D8 02 18 00 28 00 38 B4 C7 E6 B0 02 38 F1 C0 A1 BF 05 38 FB AE FA 95 0A 38 E5 C6 BF EC 06 40 B0 6D 40 90 3F 40 50 40 BB 03 4A 80 01 B5 29 1A 1B 0E 63 79 8B 34 B1 4E 2A 2A 9E 69 09 A7 69 F5 C6 4F 95 DA 96 A9 1B E3 CD 6F 3D 30 EE 59 C0 30 22 BF F0 2D 88 2D A7 6C B2 09 AD D6 CE E1 46 84 FC 7D 19 AF 1A 37 91 98 AD 2C 45 25 AA 17 2F 81 DC 5A 7F 30 F4 2D 73 E5 1C 8B 8A 23 85 42 9D 8D 5C 18 15 32 D1 CA A3 4D 01 7C 59 11 73 DA B6 09 C2 6D 58 35 EF 48 88 44 0F 2D 17 09 52 DF D4 EA A7 85 2F 27 CE DF A8 F5 9B CD C9 84 C2 52 25 2F 30 31 65 65 36 34 32 36 2D 35 66 66 31 2D 34 63 66 30 2D 38 32 37 38 2D 65 38 36 33 34 64 32 39 30 39 65 66 5A 25 2F 30 31 65 65 36 34 32 36 2D 35 66 66 31 2D 34 63 66 30 2D 38 32 37 38 2D 65 38 36 33 34 64 32 39 30 39 65 66 60 00 68 80 80 08 20 01"
.printStringFromHex()
println(md5("00 00 00 08 00 00 01 0D 12 06 98 01 01 A0 01 00 08 01 12 86 02 08 00 10 AB A7 89 D8 02 18 00 28 00 38 B4 C7 E6 B0 02 38 F1 C0 A1 BF 05 38 FB AE FA 95 0A 38 E5 C6 BF EC 06 40 B0 6D 40 90 3F 40 50 40 BB 03 4A 80 01 B5 29 1A 1B 0E 63 79 8B 34 B1 4E 2A 2A 9E 69 09 A7 69 F5 C6 4F 95 DA 96 A9 1B E3 CD 6F 3D 30 EE 59 C0 30 22 BF F0 2D 88 2D A7 6C B2 09 AD D6 CE E1 46 84 FC 7D 19 AF 1A 37 91 98 AD 2C 45 25 AA 17 2F 81 DC 5A 7F 30 F4 2D 73 E5 1C 8B 8A 23 85 42 9D 8D 5C 18 15 32 D1 CA A3 4D 01 7C 59 11 73 DA B6 09 C2 6D 58 35 EF 48 88 44 0F 2D 17 09 52 DF D4 EA A7 85 2F 27 CE DF A8 F5 9B CD C9 84 C2 52 25 2F 30 31 65 65 36 34 32 36 2D 35 66 66 31 2D 34 63 66 30 2D 38 32 37 38 2D 65 38 36 33 34 64 32 39 30 39 65 66 5A 25 2F 30 31 65 65 36 34 32 36 2D 35 66 66 31 2D 34 63 66 30 2D 38 32 37 38 2D 65 38 36 33 34 64 32 39 30 39 65 66 60 00 68 80 80 08 20 01").toUHexString())
/**
* Provided by Ktor Http
*/
private val httpClient: HttpClient = HttpClient {
engine { CIO }
}
actual suspend fun httpPostFriendImage(
uKeyHex: String,
fileSize: Long,
botNumber: UInt,
qq: UInt,
imageData: ByteReadPacket
): Boolean = Jsoup.connect("http://htdata2.qq.com/cgi-bin/httpconn" +
"?htcmd=0x6ff0070" +
"&ver=5603" +
"&ukey=${uKeyHex}" +
"&filezise=${imageData.remaining}" +
"&range=0" +
"&uin=$botNumber")
.postImage(imageData)
): Boolean = (httpClient.post {
url {
protocol = URLProtocol.HTTP
host = "htdata2.qq.com"
path("cgi-bin/httpconn")
parameters["htcmd"] = "0x6ff0070"
parameters["ver"] = "5603"
parameters["ukey"] = uKeyHex
parameters["filezise"] = imageData.remaining.toString()
parameters["range"] = 0.toString()
parameters["uin"] = qq.toString()
}
body = ByteArrayContent(imageData.readBytes(), ContentType.Image.Any)
} as HttpStatusCode).value == 200
//.postImage(imageData)
/**
* 上传群图片

View File

@ -1,8 +1,9 @@
@file:Suppress("ObjectPropertyName", "MayBeConstant", "NonAsciiCharacters", "SpellCheckingInspection")
package net.mamoe.mirai.utils
package net.mamoe.mirai.utils.io
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.utils.toUHexString
import java.lang.reflect.Field
import java.util.*
import kotlin.math.max

View File

@ -5,9 +5,9 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotAccount
import net.mamoe.mirai.login
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import net.mamoe.mirai.utils.BotAccount
import net.mamoe.mirai.utils.Console
import java.util.*

View File

@ -2,9 +2,9 @@
import net.mamoe.mirai.network.protocol.tim.packet.GroupImageIdRequestPacket
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.readRemainingBytes
import net.mamoe.mirai.utils.io.readRemainingBytes
import net.mamoe.mirai.utils.io.toUHexString
import net.mamoe.mirai.utils.toMiraiImage
import net.mamoe.mirai.utils.toUHexString
import java.io.File
import javax.imageio.ImageIO

View File

@ -1,6 +1,6 @@
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.stringOfWitch
import net.mamoe.mirai.utils.toUHexString
import net.mamoe.mirai.utils.io.stringOfWitch
import net.mamoe.mirai.utils.io.toUHexString
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.util.*

View File

@ -1,4 +1,4 @@
import net.mamoe.mirai.utils.toUHexString
import net.mamoe.mirai.utils.io.toUHexString
import org.jsoup.Connection
import org.jsoup.Jsoup

View File

@ -1,6 +1,6 @@
@file:Suppress("ObjectPropertyName", "unused", "NonAsciiCharacters", "MayBeConstant")
import net.mamoe.mirai.utils.printCompareHex
import net.mamoe.mirai.utils.io.printCompareHex
import java.util.*

View File

@ -12,7 +12,11 @@ import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.UnknownServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.UnknownServerEventPacket
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.DecryptionFailedException
import net.mamoe.mirai.utils.decryptBy
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.io.*
import net.mamoe.mirai.utils.toUHexString
/**
* 抓包分析器

View File

@ -7,6 +7,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotAccount
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.event.events.FriendMessageEvent
@ -18,12 +19,13 @@ import net.mamoe.mirai.login
import net.mamoe.mirai.message.Image
import net.mamoe.mirai.message.ImageId
import net.mamoe.mirai.message.PlainText
import net.mamoe.mirai.network.protocol.tim.packet.ClientRawPacket
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingRawPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import net.mamoe.mirai.network.protocol.tim.packet.uploadImage
import net.mamoe.mirai.network.session
import net.mamoe.mirai.qqAccount
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.toUHexString
import java.io.File
import javax.imageio.ImageIO
@ -82,7 +84,7 @@ suspend fun main() {
"直接发送包" in it.message -> {
val d = ("01 " + 1994701021u.toByteArray().toUHexString() + " 3E 03 3F A2 00 00 02 BB 00 0A 00 01 00 01 00 5E 4F 53 52 6F 6F 74 3A 43 3A 5C 55 73 65 72 73 5C 48 69 6D 31 38 5C 44 6F 63 75 6D 65 6E 74 73 5C 54 65 6E 63 65 6E 74 20 46 69 6C 65 73 5C 31 30 34 30 34 30 30 32 39 30 5C 49 6D 61 67 65 5C 43 32 43 5C 7B 47 47 42 7E 49 31 5A 4D 43 28 25 49 4D 5A 5F 47 55 51 36 35 5D 51 2E 6A 70 67 00 00 04 7D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 35 02")
.hexToBytes()
it.bot.network.socket.sendPacket(ClientRawPacket(0x01_BDu, it.bot.qqAccount, "00 00 00 01 2E 01 00 00 69 35".hexToBytes(), it.bot.network.session.sessionKey, d))
it.bot.network.socket.sendPacket(OutgoingRawPacket(0x01_BDu, it.bot.qqAccount, "00 00 00 01 2E 01 00 00 69 35".hexToBytes(), it.bot.network.session.sessionKey, d))
}
"上传好友图片" in it.message -> withTimeoutOrNull(5000) {