mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-14 07:10:09 +08:00
Adjust class names
This commit is contained in:
parent
6c6f0a48c7
commit
d5bf51a357
@ -85,7 +85,6 @@ kotlin {
|
||||
|
||||
jvmTest {
|
||||
apply plugin: 'java'
|
||||
|
||||
}
|
||||
|
||||
all {
|
||||
|
@ -46,6 +46,8 @@ sealed class Contact(val bot: Bot, val id: UInt) {
|
||||
*/
|
||||
inline class GroupId(val value: UInt)
|
||||
|
||||
fun UInt.groupId(): GroupId = GroupId(this)
|
||||
|
||||
/**
|
||||
* 一些群 API 使用的 ID. 在使用时会特别注明
|
||||
*
|
||||
@ -62,7 +64,7 @@ inline class GroupInternalId(val value: UInt)
|
||||
* @author Him188moe
|
||||
*/
|
||||
class Group internal constructor(bot: Bot, id: UInt) : Contact(bot, id) {
|
||||
val internalId = groupNumberToId(id)
|
||||
val internalId = GroupId(id).toInternalId()
|
||||
val members: ContactList<QQ>
|
||||
//todo members
|
||||
get() = throw UnsupportedOperationException("Not yet supported")
|
||||
@ -95,43 +97,4 @@ class QQ internal constructor(bot: Bot, number: UInt) : Contact(bot, number) {
|
||||
override suspend fun sendXMLMessage(message: String) {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun Group.Companion.groupNumberToId(number: UInt): UInt {//求你别出错
|
||||
val left: Long = number.toString().let {
|
||||
if (it.length < 6) {
|
||||
return@groupNumberToId number
|
||||
}
|
||||
it.substring(0, it.length - 6).toLong()
|
||||
}
|
||||
val right: Long = number.toString().let {
|
||||
it.substring(it.length - 6).toLong()
|
||||
}
|
||||
|
||||
return when (left) {
|
||||
in 1..10 -> {
|
||||
((left + 202).toString() + right.toString()).toUInt()
|
||||
}
|
||||
in 11..19 -> {
|
||||
((left + 469).toString() + right.toString()).toUInt()
|
||||
}
|
||||
in 20..66 -> {
|
||||
((left + 208).toString() + right.toString()).toUInt()
|
||||
}
|
||||
in 67..156 -> {
|
||||
((left + 1943).toString() + right.toString()).toUInt()
|
||||
}
|
||||
in 157..209 -> {
|
||||
((left + 199).toString() + right.toString()).toUInt()
|
||||
}
|
||||
in 210..309 -> {
|
||||
((left + 389).toString() + right.toString()).toUInt()
|
||||
}
|
||||
in 310..499 -> {
|
||||
((left + 349).toString() + right.toString()).toUInt()
|
||||
}
|
||||
else -> number
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -7,7 +7,7 @@ import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.event.Event
|
||||
import net.mamoe.mirai.event.EventScope
|
||||
import net.mamoe.mirai.event.ListeningStatus
|
||||
import net.mamoe.mirai.utils.inlinedRemoveIf
|
||||
import net.mamoe.mirai.utils.internal.inlinedRemoveIf
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
|
@ -6,9 +6,6 @@ import kotlinx.io.core.*
|
||||
import net.mamoe.mirai.message.*
|
||||
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
|
||||
@ -38,7 +35,8 @@ internal fun IoBuffer.parseMessageImage0x06(): Image {
|
||||
discardExact(1)
|
||||
//MiraiLogger.logDebug(this.toUHexString())
|
||||
val filenameLength = readShort()
|
||||
val suffix = readString(filenameLength).substringAfter(".")
|
||||
|
||||
discardExact(filenameLength.toInt())
|
||||
discardExact(8)//03 00 04 00 00 02 9C 04
|
||||
val length = readShort()//=27
|
||||
return Image(ImageId(readString(length)))
|
||||
|
@ -24,6 +24,7 @@ import net.mamoe.mirai.network.protocol.tim.packet.login.*
|
||||
import net.mamoe.mirai.network.session
|
||||
import net.mamoe.mirai.qqAccount
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.internal.inlinedRemoveIf
|
||||
import net.mamoe.mirai.utils.io.parseServerPacket
|
||||
import net.mamoe.mirai.utils.io.toUHexString
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
@ -55,23 +56,23 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
temporaryPacketHandler.send(this[ActionPacketHandler].session)
|
||||
}
|
||||
|
||||
override suspend fun login(configuration: BotNetworkConfiguration): LoginResult {
|
||||
override suspend fun login(configuration: BotNetworkConfiguration): LoginResult = withContext(this.coroutineContext) {
|
||||
TIMProtocol.SERVER_IP.forEach {
|
||||
bot.logger.logInfo("Connecting server $it")
|
||||
this.socket = BotSocketAdapter(it, configuration)
|
||||
socket = BotSocketAdapter(it, configuration)
|
||||
|
||||
loginResult = CompletableDeferred()
|
||||
|
||||
val state = socket.resendTouch()
|
||||
|
||||
if (state != LoginResult.TIMEOUT) {
|
||||
return state
|
||||
return@withContext state
|
||||
}
|
||||
bot.logger.logPurple("Timeout. Retrying next server")
|
||||
|
||||
socket.close()
|
||||
}
|
||||
return LoginResult.TIMEOUT
|
||||
return@withContext LoginResult.TIMEOUT
|
||||
}
|
||||
|
||||
internal var loginResult: CompletableDeferred<LoginResult> = CompletableDeferred()
|
||||
@ -156,7 +157,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
loginHandler = LoginHandler(configuration)
|
||||
|
||||
|
||||
val expect = expectPacket<ServerTouchResponsePacket>()
|
||||
val expect = expectPacket<TouchResponsePacket>()
|
||||
launch { processReceive() }
|
||||
launch {
|
||||
if (withTimeoutOrNull(configuration.touchTimeout.millisecondsLong) { expect.join() } == null) {
|
||||
@ -240,11 +241,11 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
}
|
||||
}*/
|
||||
|
||||
override suspend fun sendPacket(packet: OutgoingPacket): Unit = coroutineScope {
|
||||
override suspend fun sendPacket(packet: OutgoingPacket): Unit = withContext(coroutineContext) {
|
||||
check(channel.isOpen) { "channel is not open" }
|
||||
|
||||
if (BeforePacketSendEvent(bot, packet).broadcast().cancelled) {
|
||||
return@coroutineScope
|
||||
return@withContext
|
||||
}
|
||||
|
||||
packet.packet.use { build ->
|
||||
@ -255,7 +256,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
} catch (e: SendPacketInternalException) {
|
||||
bot.logger.logError("Caught SendPacketInternalException: ${e.cause?.message}")
|
||||
bot.reinitializeNetworkHandler(configuration, e)
|
||||
return@coroutineScope
|
||||
return@withContext
|
||||
} finally {
|
||||
buffer.release(IoBuffer.Pool)
|
||||
}
|
||||
@ -294,6 +295,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
|
||||
private var captchaSectionId: Int = 1
|
||||
private var captchaCache: IoBuffer? = null
|
||||
//set 为 null 时自动 release; get 为 null 时自动 borrow
|
||||
get() {
|
||||
if (field == null) field = IoBuffer.Pool.borrow()
|
||||
return field
|
||||
@ -307,7 +309,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
|
||||
suspend fun onPacketReceived(packet: ServerPacket) {
|
||||
when (packet) {
|
||||
is ServerTouchResponsePacket -> {
|
||||
is TouchResponsePacket -> {
|
||||
if (packet.serverIP != null) {//redirection
|
||||
socket.close()
|
||||
socket = BotSocketAdapter(packet.serverIP!!, socket.configuration)
|
||||
@ -319,7 +321,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
this.token0825 = packet.token0825
|
||||
|
||||
socket.sendPacket(
|
||||
OutgoingPasswordSubmissionPacket(
|
||||
SubmitPasswordPacket(
|
||||
bot = bot.qqAccount,
|
||||
password = bot.account.password,
|
||||
loginTime = loginTime,
|
||||
@ -333,17 +335,17 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
}
|
||||
}
|
||||
|
||||
is ServerLoginResponseFailedPacket -> {
|
||||
is LoginResponseFailedPacket -> {
|
||||
loginResult.complete(packet.loginResult)
|
||||
return
|
||||
}
|
||||
|
||||
is ServerCaptchaCorrectPacket -> {
|
||||
is CaptchaCorrectPacket -> {
|
||||
this.privateKey = getRandomByteArray(16)//似乎是必须的
|
||||
this.token00BA = packet.token00BA
|
||||
|
||||
socket.sendPacket(
|
||||
OutgoingPasswordSubmissionPacket(
|
||||
SubmitPasswordPacket(
|
||||
bot = bot.qqAccount,
|
||||
password = bot.account.password,
|
||||
loginTime = loginTime,
|
||||
@ -356,7 +358,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
)
|
||||
}
|
||||
|
||||
is ServerLoginResponseCaptchaInitPacket -> {
|
||||
is LoginResponseCaptchaInitPacket -> {
|
||||
//[token00BA]来源之一: 验证码
|
||||
this.token00BA = packet.token00BA
|
||||
this.captchaCache = packet.captchaPart1
|
||||
@ -364,7 +366,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
if (packet.unknownBoolean) {
|
||||
this.captchaSectionId = 1
|
||||
socket.sendPacket(
|
||||
OutgoingCaptchaTransmissionRequestPacket(
|
||||
RequestCaptchaTransmissionPacket(
|
||||
bot.qqAccount,
|
||||
this.token0825,
|
||||
this.captchaSectionId++,
|
||||
@ -374,7 +376,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
}
|
||||
}
|
||||
|
||||
is ServerCaptchaTransmissionPacket -> {
|
||||
is CaptchaTransmissionResponsePacket -> {
|
||||
//packet is ServerCaptchaWrongPacket
|
||||
if (this.captchaSectionId == 0) {
|
||||
bot.logger.logPurple("验证码错误, 请重新输入")
|
||||
@ -395,7 +397,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
} else {
|
||||
this.captchaSectionId = 0//意味着已经提交验证码
|
||||
socket.sendPacket(
|
||||
OutgoingCaptchaSubmitPacket(
|
||||
SubmitCaptchaPacket(
|
||||
bot.qqAccount,
|
||||
token0825,
|
||||
code,
|
||||
@ -405,7 +407,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
}
|
||||
} else {
|
||||
socket.sendPacket(
|
||||
OutgoingCaptchaTransmissionRequestPacket(
|
||||
RequestCaptchaTransmissionPacket(
|
||||
bot.qqAccount,
|
||||
token0825,
|
||||
captchaSectionId++,
|
||||
@ -415,10 +417,10 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
}
|
||||
}
|
||||
|
||||
is ServerLoginResponseSuccessPacket -> {
|
||||
is LoginResponseSuccessPacket -> {
|
||||
this.sessionResponseDecryptionKey = packet.sessionResponseDecryptionKey
|
||||
socket.sendPacket(
|
||||
OutgoingSessionRequestPacket(
|
||||
RequestSessionPacket(
|
||||
bot.qqAccount,
|
||||
socket.serverIp,
|
||||
packet.token38,
|
||||
@ -429,11 +431,11 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
}
|
||||
|
||||
//是ClientPasswordSubmissionPacket之后服务器回复的可能之一
|
||||
is ServerLoginResponseKeyExchangePacket -> {
|
||||
is LoginResponseKeyExchangeResponsePacket -> {
|
||||
this.privateKey = packet.privateKeyUpdate
|
||||
|
||||
socket.sendPacket(
|
||||
OutgoingPasswordSubmissionPacket(
|
||||
SubmitPasswordPacket(
|
||||
bot = bot.qqAccount,
|
||||
password = bot.account.password,
|
||||
loginTime = loginTime,
|
||||
@ -447,7 +449,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
)
|
||||
}
|
||||
|
||||
is ServerSessionKeyResponsePacket -> {
|
||||
is SessionKeyResponsePacket -> {
|
||||
sessionKey = packet.sessionKey
|
||||
bot.logger.logPurple("sessionKey = ${sessionKey.toUHexString()}")
|
||||
|
||||
@ -485,11 +487,11 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
|
||||
|
||||
is ServerCaptchaPacket.Encrypted -> socket.distributePacket(packet.decrypt())
|
||||
is ServerLoginResponseCaptchaInitPacket.Encrypted -> socket.distributePacket(packet.decrypt())
|
||||
is ServerLoginResponseKeyExchangePacket.Encrypted -> socket.distributePacket(packet.decrypt(this.privateKey))
|
||||
is ServerLoginResponseSuccessPacket.Encrypted -> socket.distributePacket(packet.decrypt(this.privateKey))
|
||||
is ServerSessionKeyResponsePacket.Encrypted -> socket.distributePacket(packet.decrypt(this.sessionResponseDecryptionKey))
|
||||
is ServerTouchResponsePacket.Encrypted -> socket.distributePacket(packet.decrypt())
|
||||
is LoginResponseCaptchaInitPacket.Encrypted -> socket.distributePacket(packet.decrypt())
|
||||
is LoginResponseKeyExchangeResponsePacket.Encrypted -> socket.distributePacket(packet.decrypt(this.privateKey))
|
||||
is LoginResponseSuccessPacket.Encrypted -> socket.distributePacket(packet.decrypt(this.privateKey))
|
||||
is SessionKeyResponsePacket.Encrypted -> socket.distributePacket(packet.decrypt(this.sessionResponseDecryptionKey))
|
||||
is TouchResponsePacket.Encrypted -> socket.distributePacket(packet.decrypt())
|
||||
|
||||
is UnknownServerPacket.Encrypted -> socket.distributePacket(packet.decrypt(sessionKey))
|
||||
else -> {
|
||||
|
@ -15,6 +15,7 @@ import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.RequestSKeyPacket
|
||||
import net.mamoe.mirai.network.qqAccount
|
||||
import net.mamoe.mirai.utils.log
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
* 动作: 获取好友列表, 点赞, 踢人等.
|
||||
@ -23,6 +24,9 @@ import net.mamoe.mirai.utils.log
|
||||
* @author Him188moe
|
||||
*/
|
||||
class ActionPacketHandler(session: BotSession) : PacketHandler(session) {
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = session.NetworkScope.coroutineContext
|
||||
|
||||
companion object Key : PacketHandler.Key<ActionPacketHandler>
|
||||
|
||||
|
||||
@ -66,15 +70,15 @@ class ActionPacketHandler(session: BotSession) : PacketHandler(session) {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun requestSKey() = with(session) {
|
||||
withContext(NetworkScope.coroutineContext) {
|
||||
private suspend fun requestSKey() = with(session) {
|
||||
withContext(coroutineContext) {
|
||||
socket.sendPacket(RequestSKeyPacket())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
suspend fun requestAccountInfo() = with(session) {
|
||||
withContext(NetworkScope.coroutineContext) {
|
||||
withContext(coroutineContext) {
|
||||
socket.sendPacket(RequestAccountInfoPacket(qqAccount, sessionKey))
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.mamoe.mirai.network.protocol.tim.handler
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import net.mamoe.mirai.network.BotSession
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
|
||||
import kotlin.reflect.KClass
|
||||
@ -9,7 +10,7 @@ import kotlin.reflect.KClass
|
||||
*/
|
||||
abstract class PacketHandler(
|
||||
val session: BotSession
|
||||
) {
|
||||
) : CoroutineScope {
|
||||
abstract suspend fun onPacketReceived(packet: ServerPacket)
|
||||
|
||||
interface Key<T : PacketHandler>
|
||||
@ -19,18 +20,18 @@ abstract class PacketHandler(
|
||||
}
|
||||
}
|
||||
|
||||
class PacketHandlerNode<T : PacketHandler>(
|
||||
internal class PacketHandlerNode<T : PacketHandler>(
|
||||
val clazz: KClass<T>,
|
||||
val instance: T,
|
||||
val key: PacketHandler.Key<T>
|
||||
)
|
||||
|
||||
fun <T : PacketHandler> T.asNode(key: PacketHandler.Key<T>): PacketHandlerNode<T> {
|
||||
internal fun <T : PacketHandler> T.asNode(key: PacketHandler.Key<T>): PacketHandlerNode<T> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return PacketHandlerNode(this::class as KClass<T>, this, key)
|
||||
}
|
||||
|
||||
open class PacketHandlerList : MutableList<PacketHandlerNode<*>> by mutableListOf() {
|
||||
internal open class PacketHandlerList : MutableList<PacketHandlerNode<*>> by mutableListOf() {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
operator fun <T : PacketHandler> get(key: PacketHandler.Key<T>): T = this.first { it.key === key }.instance as T
|
||||
}
|
||||
|
@ -6,9 +6,9 @@ import kotlinx.io.core.BytePacketBuilder
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.writeUByte
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import net.mamoe.mirai.utils.encryptAndWrite
|
||||
import net.mamoe.mirai.utils.writeHex
|
||||
import net.mamoe.mirai.utils.writeQQ
|
||||
import net.mamoe.mirai.utils.io.encryptAndWrite
|
||||
import net.mamoe.mirai.utils.io.writeHex
|
||||
import net.mamoe.mirai.utils.io.writeQQ
|
||||
|
||||
/**
|
||||
* 获取升级天数等.
|
||||
|
@ -5,9 +5,9 @@ package net.mamoe.mirai.network.protocol.tim.packet
|
||||
import kotlinx.io.core.BytePacketBuilder
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import net.mamoe.mirai.utils.encryptAndWrite
|
||||
import net.mamoe.mirai.utils.writeHex
|
||||
import net.mamoe.mirai.utils.writeQQ
|
||||
import net.mamoe.mirai.utils.io.encryptAndWrite
|
||||
import net.mamoe.mirai.utils.io.writeHex
|
||||
import net.mamoe.mirai.utils.io.writeQQ
|
||||
|
||||
@PacketId(0x00_58u)
|
||||
class HeartbeatPacket(
|
||||
|
@ -5,7 +5,7 @@ package net.mamoe.mirai.network.protocol.tim.packet
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.io.core.*
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import net.mamoe.mirai.utils.writeHex
|
||||
import net.mamoe.mirai.utils.io.writeHex
|
||||
|
||||
/**
|
||||
* 发给服务器的数据包. 必须有 [PacketId] 注解或 `override` [id]. 否则将会抛出 [IllegalStateException]
|
||||
|
@ -4,8 +4,8 @@ package net.mamoe.mirai.network.protocol.tim.packet
|
||||
|
||||
import kotlinx.io.core.BytePacketBuilder
|
||||
import kotlinx.io.core.writeFully
|
||||
import net.mamoe.mirai.utils.encryptAndWrite
|
||||
import net.mamoe.mirai.utils.writeQQ
|
||||
import net.mamoe.mirai.utils.io.encryptAndWrite
|
||||
import net.mamoe.mirai.utils.io.writeQQ
|
||||
|
||||
class OutgoingRawPacket(
|
||||
override val id: UShort,
|
||||
|
@ -4,11 +4,14 @@ package net.mamoe.mirai.network.protocol.tim.packet
|
||||
|
||||
import kotlinx.io.core.*
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.GroupInternalId
|
||||
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
|
||||
import net.mamoe.mirai.utils.ExternalImage
|
||||
import net.mamoe.mirai.utils.hexToBytes
|
||||
import net.mamoe.mirai.utils.httpPostGroupImage
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.readUnsignedVarInt
|
||||
|
||||
|
||||
suspend fun Group.uploadImage(
|
||||
@ -19,7 +22,7 @@ suspend fun Group.uploadImage(
|
||||
if (it.uKey != null) {
|
||||
httpPostGroupImage(
|
||||
botAccount = bot.qqAccount,
|
||||
groupNumber = internalId,
|
||||
groupInternalId = internalId,
|
||||
imageInput = image.input,
|
||||
inputSize = image.inputSize,
|
||||
uKeyHex = it.uKey!!.toUHexString("")
|
||||
@ -35,7 +38,7 @@ suspend fun Group.uploadImage(
|
||||
@PacketVersion(date = "2019.10.20", timVersion = "2.3.2.21173")
|
||||
class GroupImageIdRequestPacket(
|
||||
private val bot: UInt,
|
||||
private val groupId: UInt,
|
||||
private val groupInternalId: GroupInternalId,
|
||||
private val image: ExternalImage,
|
||||
private val sessionKey: ByteArray
|
||||
) : OutgoingPacket() {
|
||||
@ -146,7 +149,7 @@ class GroupImageIdRequestPacket(
|
||||
writeHex("01 12 03 98 01 01 10 01 1A")
|
||||
|
||||
writeUVarintLVPacket(lengthOffset = { it + 1 }) {
|
||||
writeTUVarint(0x08u, groupId)
|
||||
writeTUVarint(0x08u, groupInternalId.value)
|
||||
writeTUVarint(0x10u, bot)
|
||||
writeTV(0x1800u)
|
||||
|
||||
|
@ -8,9 +8,9 @@ import kotlinx.io.core.discardExact
|
||||
import kotlinx.io.core.readUShort
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.*
|
||||
import net.mamoe.mirai.utils.encryptAndWrite
|
||||
import net.mamoe.mirai.utils.writeHex
|
||||
import net.mamoe.mirai.utils.writeQQ
|
||||
import net.mamoe.mirai.utils.io.encryptAndWrite
|
||||
import net.mamoe.mirai.utils.io.writeHex
|
||||
import net.mamoe.mirai.utils.io.writeQQ
|
||||
|
||||
/**
|
||||
* 向服务器检查是否可添加某人为好友
|
||||
|
@ -12,8 +12,8 @@ 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.ResponsePacket
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.io.toUHexString
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.md5
|
||||
|
||||
fun main() {
|
||||
println("牛逼".toMessage().toChain().toPacket(true).readBytes().toUHexString())
|
||||
|
@ -4,29 +4,30 @@ package net.mamoe.mirai.network.protocol.tim.packet.action
|
||||
|
||||
import kotlinx.io.core.BytePacketBuilder
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import net.mamoe.mirai.contact.GroupInternalId
|
||||
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.OutgoingPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.PacketId
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.ResponsePacket
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
|
||||
|
||||
@PacketId(0x00_02u)
|
||||
class SendGroupMessagePacket(
|
||||
private val botQQ: UInt,
|
||||
private val groupId: UInt,//不是 number
|
||||
private val sessionKey: ByteArray,
|
||||
private val message: MessageChain
|
||||
private val botQQ: UInt,
|
||||
private val groupInternalId: GroupInternalId,
|
||||
private val sessionKey: ByteArray,
|
||||
private val message: MessageChain
|
||||
) : OutgoingPacket() {
|
||||
override fun encode(builder: BytePacketBuilder) = with(builder) {
|
||||
this.writeQQ(botQQ)
|
||||
this.writeHex(TIMProtocol.fixVer2)
|
||||
writeQQ(botQQ)
|
||||
writeHex(TIMProtocol.fixVer2)
|
||||
|
||||
this.encryptAndWrite(sessionKey) {
|
||||
encryptAndWrite(sessionKey) {
|
||||
writeByte(0x2A)
|
||||
writeGroup(groupId)
|
||||
writeGroup(groupInternalId)
|
||||
|
||||
writeShortLVPacket {
|
||||
writeHex("00 01 01")
|
||||
|
@ -26,7 +26,7 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventP
|
||||
* 发送方权限.
|
||||
*/
|
||||
lateinit var senderPermission: SenderPermission
|
||||
lateinit var message: MessageChain
|
||||
var message: MessageChain by Delegates.notNull()
|
||||
|
||||
override fun decode() = with(input) {
|
||||
discardExact(31)
|
||||
@ -95,7 +95,7 @@ class ServerFriendMessageEventPacket(input: ByteReadPacket, eventIdentity: Event
|
||||
*/
|
||||
var isPrevious: Boolean = false
|
||||
|
||||
lateinit var message: MessageChain
|
||||
var message: MessageChain by Delegates.notNull()
|
||||
|
||||
//来自自己发送给自己
|
||||
//00 00 00 20 00 05 00 02 00 06 00 06 00 04 00 01 01 07 00 09 00 06 03 E9 20 02 EB 94 00 0A 00 04 01 00 00 00 0C 17 76 E4 B8 DD 76 E4 B8 DD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B A6 D2 5D A3 2A 3F 00 00 5D A3 2A 3F 01 00 00 00 00 4D 53 47 00 00 00 00 00 5D A3 2A 3F 0C 8A 59 3D 00 00 00 00 0A 00 86 02 00 06 E5 AE 8B E4 BD 93 00 00 01 00 06 01 00 03 31 32 33 19 00 1F 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 0E 00 0E 01 00 04 00 00 00 00 0A 00 04 00 00 00 00
|
||||
|
@ -8,10 +8,9 @@ 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
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.toByteArray
|
||||
|
||||
/**
|
||||
* 事件的识别 ID. 在 [事件确认包][ServerEventPacket.ResponsePacket] 中被使用.
|
||||
|
@ -6,25 +6,21 @@ 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.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
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
|
||||
/**
|
||||
* 客户端请求验证码图片数据的第几部分
|
||||
*/
|
||||
@PacketId(0x00_BAu)
|
||||
class OutgoingCaptchaTransmissionRequestPacket(
|
||||
private val qq: UInt,
|
||||
private val token0825: ByteArray,
|
||||
private val verificationSequence: Int,
|
||||
private val token00BA: ByteArray
|
||||
class RequestCaptchaTransmissionPacket(
|
||||
private val bot: UInt,
|
||||
private val token0825: ByteArray,
|
||||
private val verificationSequence: Int,
|
||||
private val token00BA: ByteArray
|
||||
) : OutgoingPacket() {
|
||||
@Tested
|
||||
override fun encode(builder: BytePacketBuilder) = with(builder) {
|
||||
this.writeQQ(qq)
|
||||
this.writeQQ(bot)
|
||||
this.writeHex(TIMProtocol.fixVer)
|
||||
this.writeHex(TIMProtocol.key00BA)
|
||||
this.encryptAndWrite(TIMProtocol.key00BA) {
|
||||
@ -48,18 +44,18 @@ class OutgoingCaptchaTransmissionRequestPacket(
|
||||
* 提交验证码
|
||||
*/
|
||||
@PacketId(0x00_BAu)
|
||||
class OutgoingCaptchaSubmitPacket(
|
||||
private val qq: UInt,
|
||||
private val token0825: ByteArray,
|
||||
private val captcha: String,
|
||||
private val verificationToken: IoBuffer
|
||||
class SubmitCaptchaPacket(
|
||||
private val bot: UInt,
|
||||
private val token0825: ByteArray,
|
||||
private val captcha: String,
|
||||
private val verificationToken: IoBuffer
|
||||
) : OutgoingPacket() {
|
||||
init {
|
||||
require(captcha.length == 4) { "captcha.length must == 4" }
|
||||
}
|
||||
|
||||
override fun encode(builder: BytePacketBuilder) = with(builder) {
|
||||
this.writeQQ(qq)
|
||||
this.writeQQ(bot)
|
||||
this.writeHex(TIMProtocol.fixVer)
|
||||
this.writeHex(TIMProtocol.key00BA)
|
||||
this.encryptAndWrite(TIMProtocol.key00BA) {
|
||||
@ -114,7 +110,7 @@ class OutgoingCaptchaRefreshPacket(
|
||||
* @author Him188moe
|
||||
*/
|
||||
@PacketId(0x00_BAu)
|
||||
open class ServerCaptchaTransmissionPacket(input: ByteReadPacket) : ServerCaptchaPacket(input) {
|
||||
open class CaptchaTransmissionResponsePacket(input: ByteReadPacket) : ServerCaptchaPacket(input) {
|
||||
|
||||
lateinit var captchaSectionN: IoBuffer
|
||||
lateinit var verificationToken: IoBuffer//56bytes
|
||||
@ -141,7 +137,7 @@ open class ServerCaptchaTransmissionPacket(input: ByteReadPacket) : ServerCaptch
|
||||
/*
|
||||
fun main() {
|
||||
val data = "13 00 05 01 00 00 01 23 00 38 59 32 29 5A 3E 3D 2D FC F5 22 EB 9E 2D FB 9C 4F AA 06 C8 32 3D F0 3C 2C 2B BA 8D 05 C4 9B C1 74 3B 70 F1 99 90 BB 6E 3E 6F 74 48 97 D3 61 B7 04 C0 A3 F1 DF 40 A4 DC 2B 00 A2 01 2D BB BB E8 FE B8 AF B3 6F 39 7C EA E2 5B 91 BE DB 59 38 CF 58 BC F2 88 F1 09 CF 92 E9 F7 FB 13 76 C5 68 29 23 3F 8E 43 16 2E 50 D7 FA 4D C1 F7 67 EF 27 FB C6 F1 A7 25 A4 BC 45 39 3A EA B2 A5 38 02 FF 4B C9 FF EB BD 89 E5 5D B9 4A 2A BE 5F 52 F1 EB 09 29 CB 3E 66 CF EF 97 89 47 BB 6B E0 7B 4A 3E A1 BC 3F FB F2 0A 83 CB E3 EA B9 43 E1 26 88 03 0B A7 E0 B2 AD 7F 83 CC DA 74 85 83 72 08 EC D2 F9 95 05 15 05 96 F7 1C FF 00 82 C3 90 22 A4 BA 90 D5 00 00 00 00 49 45 4E 44 AE 42 60 82 03 00 00 28 EA 32 5A 85 C8 D2 73 B3 40 39 77 85 65 98 00 FE 03 A2 A5 95 B4 2F E6 79 7A DE 5A 03 10 C8 3D BF 6D 3D 8B 51 84 C2 6D 49 00 10 92 AA 69 FB C6 3D 60 5A 7A A4 AC 7A B0 71 00 36".hexToBytes()
|
||||
ServerCaptchaTransmissionPacket(data.toReadPacket(), data.size, "00 BA 31 01".hexToBytes()).let {
|
||||
CaptchaTransmissionResponsePacket(data.toReadPacket(), data.size, "00 BA 31 01".hexToBytes()).let {
|
||||
it.dataDecode()
|
||||
println(it.toString())
|
||||
}
|
||||
@ -153,7 +149,7 @@ fun main() {
|
||||
* @author Him188moe
|
||||
*/
|
||||
@PacketId(0x00_BAu)
|
||||
class ServerCaptchaCorrectPacket(input: ByteReadPacket) : ServerCaptchaPacket(input) {
|
||||
class CaptchaCorrectPacket(input: ByteReadPacket) : ServerCaptchaPacket(input) {
|
||||
lateinit var token00BA: ByteArray//56 bytes
|
||||
|
||||
override fun decode() = with(input) {
|
||||
@ -172,9 +168,9 @@ abstract class ServerCaptchaPacket(input: ByteReadPacket) : ServerPacket(input)
|
||||
|
||||
return when (data.size) {
|
||||
66,
|
||||
95 -> ServerCaptchaCorrectPacket(data.toReadPacket())
|
||||
95 -> CaptchaCorrectPacket(data.toReadPacket())
|
||||
//66 -> ServerCaptchaUnknownPacket(data.toReadPacket())
|
||||
else -> ServerCaptchaTransmissionPacket(data.toReadPacket())
|
||||
else -> CaptchaTransmissionResponsePacket(data.toReadPacket())
|
||||
}.applySequence(sequenceId)
|
||||
}
|
||||
}
|
@ -8,9 +8,9 @@ import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
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
|
||||
import net.mamoe.mirai.utils.writeHex
|
||||
import net.mamoe.mirai.utils.writeQQ
|
||||
import net.mamoe.mirai.utils.io.encryptAndWrite
|
||||
import net.mamoe.mirai.utils.io.writeHex
|
||||
import net.mamoe.mirai.utils.io.writeQQ
|
||||
|
||||
/**
|
||||
* 改变在线状态: "我在线上", "隐身" 等
|
||||
|
@ -8,14 +8,17 @@ import kotlinx.io.core.writeFully
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.PacketId
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.TEA
|
||||
import net.mamoe.mirai.utils.hexToBytes
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.writeCRC32
|
||||
|
||||
|
||||
/**
|
||||
* 提交密码
|
||||
*/
|
||||
@PacketId(0x08_36u)
|
||||
class OutgoingPasswordSubmissionPacket constructor(
|
||||
class SubmitPasswordPacket constructor(
|
||||
private val bot: UInt,
|
||||
private val password: String,
|
||||
private val loginTime: Int,
|
||||
|
@ -1,4 +1,4 @@
|
||||
@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS", "EXPERIMENTAL_API_USAGE")
|
||||
@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS", "EXPERIMENTAL_API_USAGE", "FunctionName")
|
||||
|
||||
package net.mamoe.mirai.network.protocol.tim.packet.login
|
||||
|
||||
@ -11,13 +11,7 @@ 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
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
|
||||
fun BotSession.RequestSKeyPacket() = RequestSKeyPacket(qqAccount, sessionKey)
|
||||
|
||||
@ -27,11 +21,11 @@ fun BotSession.RequestSKeyPacket() = RequestSKeyPacket(qqAccount, sessionKey)
|
||||
*/
|
||||
@PacketId(0x00_1Du)
|
||||
class RequestSKeyPacket(
|
||||
private val qq: UInt,
|
||||
private val sessionKey: ByteArray
|
||||
private val bot: UInt,
|
||||
private val sessionKey: ByteArray
|
||||
) : OutgoingPacket() {
|
||||
override fun encode(builder: BytePacketBuilder) = with(builder) {
|
||||
writeQQ(qq)
|
||||
writeQQ(bot)
|
||||
writeHex(TIMProtocol.fixVer2)
|
||||
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")
|
||||
|
@ -16,13 +16,13 @@ import kotlin.properties.Delegates
|
||||
sealed class ServerLoginResponsePacket(input: ByteReadPacket) : ServerPacket(input)
|
||||
|
||||
@PacketId(0x08_36u)
|
||||
class ServerLoginResponseFailedPacket(val loginResult: LoginResult, input: ByteReadPacket) : ServerLoginResponsePacket(input)
|
||||
class LoginResponseFailedPacket(val loginResult: LoginResult, input: ByteReadPacket) : ServerLoginResponsePacket(input)
|
||||
|
||||
/**
|
||||
* 服务器进行加密后返回 privateKey
|
||||
*/
|
||||
@PacketId(0x08_36u)
|
||||
class ServerLoginResponseKeyExchangePacket(input: ByteReadPacket) : ServerLoginResponsePacket(input) {
|
||||
class LoginResponseKeyExchangeResponsePacket(input: ByteReadPacket) : ServerLoginResponsePacket(input) {
|
||||
lateinit var tlv0006: IoBuffer//120bytes
|
||||
var tokenUnknown: ByteArray? = null
|
||||
|
||||
@ -47,7 +47,8 @@ class ServerLoginResponseKeyExchangePacket(input: ByteReadPacket) : ServerLoginR
|
||||
@PacketId(0x08_36u)
|
||||
class Encrypted(input: ByteReadPacket) : ServerPacket(input) {
|
||||
@Tested
|
||||
fun decrypt(privateKey: ByteArray): ServerLoginResponseKeyExchangePacket = ServerLoginResponseKeyExchangePacket(this.decryptBy(TIMProtocol.shareKey, privateKey)).applySequence(sequenceId)
|
||||
fun decrypt(privateKey: ByteArray): LoginResponseKeyExchangeResponsePacket =
|
||||
LoginResponseKeyExchangeResponsePacket(this.decryptBy(TIMProtocol.shareKey, privateKey)).applySequence(sequenceId)
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +61,7 @@ enum class Gender(val id: Boolean) {
|
||||
* @author NaturalHG
|
||||
*/
|
||||
@PacketId(0x08_36u)
|
||||
class ServerLoginResponseSuccessPacket(input: ByteReadPacket) : ServerLoginResponsePacket(input) {
|
||||
class LoginResponseSuccessPacket(input: ByteReadPacket) : ServerLoginResponsePacket(input) {
|
||||
lateinit var sessionResponseDecryptionKey: IoBuffer//16 bytes|
|
||||
|
||||
lateinit var token38: IoBuffer//56
|
||||
@ -116,7 +117,7 @@ class ServerLoginResponseSuccessPacket(input: ByteReadPacket) : ServerLoginRespo
|
||||
|
||||
@PacketId(0x08_36u)
|
||||
class Encrypted(input: ByteReadPacket) : ServerPacket(input) {
|
||||
fun decrypt(privateKey: ByteArray): ServerLoginResponseSuccessPacket = ServerLoginResponseSuccessPacket(this.decryptBy(TIMProtocol.shareKey, privateKey)).applySequence(sequenceId)
|
||||
fun decrypt(privateKey: ByteArray): LoginResponseSuccessPacket = LoginResponseSuccessPacket(this.decryptBy(TIMProtocol.shareKey, privateKey)).applySequence(sequenceId)
|
||||
}
|
||||
|
||||
}
|
||||
@ -127,7 +128,7 @@ class ServerLoginResponseSuccessPacket(input: ByteReadPacket) : ServerLoginRespo
|
||||
* @author Him188moe
|
||||
*/
|
||||
@PacketId(0x08_36u)
|
||||
class ServerLoginResponseCaptchaInitPacket(input: ByteReadPacket) : ServerLoginResponsePacket(input) {
|
||||
class LoginResponseCaptchaInitPacket(input: ByteReadPacket) : ServerLoginResponsePacket(input) {
|
||||
|
||||
lateinit var captchaPart1: IoBuffer
|
||||
lateinit var token00BA: ByteArray
|
||||
@ -152,6 +153,6 @@ class ServerLoginResponseCaptchaInitPacket(input: ByteReadPacket) : ServerLoginR
|
||||
|
||||
@PacketId(0x08_36u)
|
||||
class Encrypted(input: ByteReadPacket) : ServerPacket(input) {
|
||||
fun decrypt(): ServerLoginResponseCaptchaInitPacket = ServerLoginResponseCaptchaInitPacket(decryptAsByteArray(TIMProtocol.shareKey).toReadPacket()).applySequence(sequenceId)
|
||||
fun decrypt(): LoginResponseCaptchaInitPacket = LoginResponseCaptchaInitPacket(decryptAsByteArray(TIMProtocol.shareKey).toReadPacket()).applySequence(sequenceId)
|
||||
}
|
||||
}
|
@ -5,11 +5,12 @@ 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.io.readIoBuffer
|
||||
import net.mamoe.mirai.utils.Tested
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.localIpAddress
|
||||
|
||||
@PacketId(0x08_28u)
|
||||
class OutgoingSessionRequestPacket(
|
||||
class RequestSessionPacket(
|
||||
private val bot: UInt,
|
||||
private val serverIp: String,
|
||||
private val token38: IoBuffer,
|
||||
@ -61,7 +62,7 @@ class OutgoingSessionRequestPacket(
|
||||
|
||||
|
||||
@PacketId(0x08_28u)
|
||||
class ServerSessionKeyResponsePacket(input: ByteReadPacket) : ServerPacket(input) {
|
||||
class SessionKeyResponsePacket(input: ByteReadPacket) : ServerPacket(input) {
|
||||
lateinit var sessionKey: ByteArray
|
||||
lateinit var tlv0105: ByteReadPacket
|
||||
|
||||
@ -111,7 +112,7 @@ Discarded(11) =41 01 00 02 03 3C 01 03 00 00 86
|
||||
|
||||
@PacketId(0x08_28u)
|
||||
class Encrypted(input: ByteReadPacket) : ServerPacket(input) {
|
||||
fun decrypt(sessionResponseDecryptionKey: IoBuffer): ServerSessionKeyResponsePacket =
|
||||
ServerSessionKeyResponsePacket(decryptBy(sessionResponseDecryptionKey)).applySequence(sequenceId)
|
||||
fun decrypt(sessionResponseDecryptionKey: IoBuffer): SessionKeyResponsePacket =
|
||||
SessionKeyResponsePacket(decryptBy(sessionResponseDecryptionKey)).applySequence(sequenceId)
|
||||
}
|
||||
}
|
@ -8,20 +8,21 @@ import kotlinx.io.core.discardExact
|
||||
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
|
||||
import net.mamoe.mirai.utils.hexToBytes
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
|
||||
/**
|
||||
* The packet received when logging in, used to redirect server address
|
||||
*
|
||||
* @see OutgoingTouchRedirectionPacket
|
||||
* @see OutgoingPasswordSubmissionPacket
|
||||
* @see SubmitPasswordPacket
|
||||
*
|
||||
* @author Him188moe
|
||||
*/
|
||||
@Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
|
||||
@PacketId(0x08_25u)
|
||||
class ServerTouchResponsePacket(input: ByteReadPacket) : ServerPacket(input) {
|
||||
class TouchResponsePacket(input: ByteReadPacket) : ServerPacket(input) {
|
||||
var serverIP: String? = null
|
||||
|
||||
var loginTime: Int = 0
|
||||
@ -51,7 +52,7 @@ class ServerTouchResponsePacket(input: ByteReadPacket) : ServerPacket(input) {
|
||||
|
||||
@PacketId(0x08_25u)
|
||||
class Encrypted(input: ByteReadPacket) : ServerPacket(input) {
|
||||
fun decrypt(): ServerTouchResponsePacket = ServerTouchResponsePacket(decryptBy(TIMProtocol.touchKey.hexToBytes())).applySequence(sequenceId)
|
||||
fun decrypt(): TouchResponsePacket = TouchResponsePacket(decryptBy(TIMProtocol.touchKey.hexToBytes())).applySequence(sequenceId)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,37 +2,39 @@ package net.mamoe.mirai.utils
|
||||
|
||||
import com.soywiz.klock.TimeSpan
|
||||
import com.soywiz.klock.seconds
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.ServerTouchResponsePacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.TouchResponsePacket
|
||||
import kotlin.jvm.JvmField
|
||||
import kotlin.jvm.JvmOverloads
|
||||
|
||||
/**
|
||||
* 网络配置
|
||||
*/
|
||||
class BotNetworkConfiguration {
|
||||
class BotNetworkConfiguration @JvmOverloads constructor(
|
||||
/**
|
||||
* 等待 [ServerTouchResponsePacket] 的时间
|
||||
* 等待 [TouchResponsePacket] 的时间
|
||||
*/
|
||||
var touchTimeout: TimeSpan = 2.seconds
|
||||
|
||||
var touchTimeout: TimeSpan = 2.seconds,
|
||||
/**
|
||||
* 是否使用随机的设备名.
|
||||
* 使用随机可以降低被封禁的风险, 但可能导致每次登录都需要输入验证码
|
||||
* 当一台设备只登录少量账号时, 将此项设置为 `true` 可能更好.
|
||||
*/
|
||||
var randomDeviceName: Boolean = false
|
||||
|
||||
var randomDeviceName: Boolean = false,
|
||||
/**
|
||||
* 心跳周期. 过长会导致被服务器断开连接.
|
||||
*/
|
||||
var heartbeatPeriod: TimeSpan = 60.seconds
|
||||
|
||||
var heartbeatPeriod: TimeSpan = 60.seconds,
|
||||
/**
|
||||
* 每次心跳时等待结果的时间.
|
||||
* 一旦心跳超时, 整个网络服务将会重启 (将消耗约 1s). 除正在进行的任务 (如图片上传) 会被中断外, 事件和插件均不受影响.
|
||||
*/
|
||||
var heartbeatTimeout: TimeSpan = 2.seconds
|
||||
) {
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 默认的配置实例
|
||||
*/
|
||||
@JvmField
|
||||
val Default = BotNetworkConfiguration()
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.http.URLProtocol
|
||||
import io.ktor.http.userAgent
|
||||
import kotlinx.io.core.Input
|
||||
import net.mamoe.mirai.contact.GroupInternalId
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
@ -72,7 +73,7 @@ suspend fun httpPostFriendImage(
|
||||
@Suppress("DuplicatedCode")
|
||||
suspend fun httpPostGroupImage(
|
||||
botAccount: UInt,
|
||||
groupNumber: UInt,
|
||||
groupInternalId: GroupInternalId,
|
||||
uKeyHex: String,
|
||||
imageInput: Input,
|
||||
inputSize: Long
|
||||
@ -80,7 +81,7 @@ suspend fun httpPostGroupImage(
|
||||
url {
|
||||
parameters["htcmd"] = "0x6ff0071"
|
||||
parameters["uin"] = botAccount.toLong().toString()
|
||||
parameters["groupcode"] = groupNumber.toLong().toString()
|
||||
parameters["groupcode"] = groupInternalId.value.toLong().toString()
|
||||
}
|
||||
} as HttpStatusCode).value.also { println(it) } == 200
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
@file:JvmName("IterableUtil")
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
package net.mamoe.mirai.utils.internal
|
||||
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
|
@ -33,18 +33,19 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket {
|
||||
|
||||
discardExact(7)//4 for qq number, 3 for 0x00 0x00 0x00. 但更可能是应该 discard 8
|
||||
return when (id.toUInt()) {
|
||||
0x08_25u -> ServerTouchResponsePacket.Encrypted(this)
|
||||
0x08_25u -> TouchResponsePacket.Encrypted(this)
|
||||
0x08_36u -> {
|
||||
//todo 不要用size分析
|
||||
when (size) {
|
||||
271, 207 -> return ServerLoginResponseKeyExchangePacket.Encrypted(this).applySequence(sequenceId)
|
||||
871 -> return ServerLoginResponseCaptchaInitPacket.Encrypted(this).applySequence(sequenceId)
|
||||
271, 207 -> return LoginResponseKeyExchangeResponsePacket.Encrypted(this).applySequence(sequenceId)
|
||||
871 -> return LoginResponseCaptchaInitPacket.Encrypted(this).applySequence(sequenceId)
|
||||
}
|
||||
|
||||
if (size > 700) return ServerLoginResponseSuccessPacket.Encrypted(this).applySequence(sequenceId)
|
||||
if (size > 700) return LoginResponseSuccessPacket.Encrypted(this).applySequence(sequenceId)
|
||||
|
||||
println("登录包size=$size")
|
||||
return ServerLoginResponseFailedPacket(when (size) {
|
||||
return LoginResponseFailedPacket(
|
||||
when (size) {
|
||||
135 -> {//包数据错误. 目前怀疑是 tlv0006
|
||||
this.readRemainingBytes().cutTail(1).decryptBy(TIMProtocol.shareKey).read {
|
||||
discardExact(51)
|
||||
@ -70,7 +71,7 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket {
|
||||
else -> throw IllegalArgumentException(bytes.size.toString())*/
|
||||
}, this).applySequence(sequenceId)
|
||||
}
|
||||
0x08_28u -> ServerSessionKeyResponsePacket.Encrypted(this)
|
||||
0x08_28u -> SessionKeyResponsePacket.Encrypted(this)
|
||||
|
||||
0x00_ECu -> ServerLoginSuccessPacket(this)
|
||||
0x00_BAu -> ServerCaptchaPacket.Encrypted(this)
|
||||
|
@ -1,9 +1,12 @@
|
||||
@file:Suppress("EXPERIMENTAL_API_USAGE")
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
package net.mamoe.mirai.utils.io
|
||||
|
||||
import kotlinx.io.core.*
|
||||
import net.mamoe.mirai.contact.GroupId
|
||||
import net.mamoe.mirai.contact.GroupInternalId
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import net.mamoe.mirai.utils.*
|
||||
import kotlin.random.Random
|
||||
import kotlin.random.nextInt
|
||||
|
||||
@ -14,9 +17,8 @@ fun BytePacketBuilder.writeRandom(length: Int) = repeat(length) { this.writeByte
|
||||
|
||||
fun BytePacketBuilder.writeQQ(qq: Long) = this.writeUInt(qq.toUInt())
|
||||
fun BytePacketBuilder.writeQQ(qq: UInt) = this.writeUInt(qq)
|
||||
|
||||
fun BytePacketBuilder.writeGroup(groupIdOrGroupNumber: Long) = this.writeUInt(groupIdOrGroupNumber.toUInt())
|
||||
fun BytePacketBuilder.writeGroup(groupIdOrGroupNumber: UInt) = this.writeUInt(groupIdOrGroupNumber)
|
||||
fun BytePacketBuilder.writeGroup(groupId: GroupId) = this.writeUInt(groupId.value)
|
||||
fun BytePacketBuilder.writeGroup(groupInternalId: GroupInternalId) = this.writeUInt(groupInternalId.value)
|
||||
|
||||
fun BytePacketBuilder.writeShortLVByteArray(byteArray: ByteArray) {
|
||||
this.writeShort(byteArray.size.toShort())
|
||||
@ -98,7 +100,9 @@ fun BytePacketBuilder.writeTByteArray(tag: UByte, value: UByteArray) {
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.encryptAndWrite(key: IoBuffer, encoder: BytePacketBuilder.() -> Unit) = encryptAndWrite(key.readBytes(), encoder)
|
||||
fun BytePacketBuilder.encryptAndWrite(key: ByteArray, encoder: BytePacketBuilder.() -> Unit) = writeFully(TEA.encrypt(BytePacketBuilder().apply(encoder).use { it.build().readBytes() }, key))
|
||||
fun BytePacketBuilder.encryptAndWrite(key: ByteArray, encoder: BytePacketBuilder.() -> Unit) = writeFully(TEA.encrypt(BytePacketBuilder().apply(encoder).use {
|
||||
it.build().readBytes()
|
||||
}, key))
|
||||
fun BytePacketBuilder.encryptAndWrite(keyHex: String, encoder: BytePacketBuilder.() -> Unit) = encryptAndWrite(keyHex.hexToBytes(), encoder)
|
||||
|
||||
fun BytePacketBuilder.writeTLV0006(qq: UInt, password: String, loginTime: Int, loginIP: String, privateKey: ByteArray) {
|
||||
|
@ -75,7 +75,7 @@ internal actual fun HttpRequestBuilder.configureBody(
|
||||
override val contentType: ContentType = ContentType.Image.GIF
|
||||
override val contentLength: Long = inputSize
|
||||
|
||||
override suspend fun writeTo(channel: ByteWriteChannel) {
|
||||
override suspend fun writeTo(channel: ByteWriteChannel) {//不知道为什么这个 channel 在 common 找不到...
|
||||
val buffer = byteArrayOf(1)
|
||||
while (!input.endOfInput) {
|
||||
input.readFully(buffer)
|
||||
|
@ -1,5 +1,7 @@
|
||||
@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS")
|
||||
|
||||
import net.mamoe.mirai.contact.groupId
|
||||
import net.mamoe.mirai.contact.toInternalId
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.GroupImageIdRequestPacket
|
||||
import net.mamoe.mirai.utils.hexToBytes
|
||||
import net.mamoe.mirai.utils.io.readRemainingBytes
|
||||
@ -15,9 +17,9 @@ fun main() = println({
|
||||
|
||||
// File("C:\\Users\\Him18\\Desktop\\test2.jpg").writeBytes(image.fileData.readBytes())
|
||||
GroupImageIdRequestPacket(
|
||||
1994701021u,
|
||||
580266363u,
|
||||
image,
|
||||
sessionKey
|
||||
1994701021u,
|
||||
580266363u.groupId().toInternalId(),
|
||||
image,
|
||||
sessionKey
|
||||
).packet.readRemainingBytes().toUHexString()
|
||||
}())
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
package demo1
|
||||
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import net.mamoe.mirai.Bot
|
||||
@ -40,7 +39,7 @@ private fun readTestAccount(): BotAccount? {
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
suspend fun main() = coroutineScope {
|
||||
suspend fun main() {
|
||||
val bot = Bot(
|
||||
readTestAccount() ?: BotAccount(//填写你的账号
|
||||
id = 1994701121u,
|
||||
@ -58,7 +57,7 @@ suspend fun main() = coroutineScope {
|
||||
}
|
||||
|
||||
subscribeAlways<GroupMessageEvent> {
|
||||
if (it.message eq "复读" && it.group.internalId == 580266363u) {
|
||||
if (it.message eq "复读" && it.group.internalId.value == 580266363u) {
|
||||
it.reply(it.message)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user