mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-10 04:00:08 +08:00
Adjust package names and file names
This commit is contained in:
parent
3f30bb4d54
commit
b7628cd3d6
@ -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"
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 为多账号设计, 可同时维护多个机器人.
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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>)
|
||||
|
@ -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
|
||||
|
@ -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??
|
||||
|
@ -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
|
@ -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() {
|
||||
|
@ -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
|
@ -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()
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
||||
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
||||
/**
|
||||
* 添加好友/群的回复
|
||||
*/
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
@ -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
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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?
|
||||
)
|
@ -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)]"
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
||||
/**
|
||||
* 上传群图片
|
||||
|
@ -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
|
@ -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.*
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.*
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.*
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
/**
|
||||
* 抓包分析器
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user