Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Mirai
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Mirai
Commits
bd9cf3bf
Commit
bd9cf3bf
authored
Nov 06, 2019
by
Him188
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Redesign packets
parent
6f498554
Changes
60
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
60 changed files
with
1519 additions
and
1476 deletions
+1519
-1476
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/MiraiEnvironment.kt
...rc/androidMain/kotlin/net/mamoe/mirai/MiraiEnvironment.kt
+3
-0
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/event/EventDispatcher.kt
...droidMain/kotlin/net/mamoe/mirai/event/EventDispatcher.kt
+7
-0
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/protocol/tim/NetworkDispatcher.kt
...net/mamoe/mirai/network/protocol/tim/NetworkDispatcher.kt
+12
-0
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformLogger.kt
...ndroidMain/kotlin/net/mamoe/mirai/utils/PlatformLogger.kt
+51
-0
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsAndroid.kt
...Main/kotlin/net/mamoe/mirai/utils/PlatformUtilsAndroid.kt
+100
-0
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SolveCaptchaAndroid.kt
...dMain/kotlin/net/mamoe/mirai/utils/SolveCaptchaAndroid.kt
+12
-0
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/io/PlatformDatagramChannelAndroid.kt
...et/mamoe/mirai/utils/io/PlatformDatagramChannelAndroid.kt
+47
-0
mirai-core/src/androidMain/res/AndroidManifest.xml
mirai-core/src/androidMain/res/AndroidManifest.xml
+10
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
.../src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
+2
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/FriendEvents.kt
...nMain/kotlin/net.mamoe.mirai/event/events/FriendEvents.kt
+6
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PacketEvents.kt
...nMain/kotlin/net.mamoe.mirai/event/events/PacketEvents.kt
+2
-3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt
...nMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt
+2
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt
...c/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt
+14
-10
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt
....mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt
+92
-88
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/ActionPacketHandler.kt
...mirai/network/protocol/tim/handler/ActionPacketHandler.kt
+5
-10
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/DataPacketSocketAdapter.kt
...i/network/protocol/tim/handler/DataPacketSocketAdapter.kt
+2
-6
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/EventPacketHandler.kt
....mirai/network/protocol/tim/handler/EventPacketHandler.kt
+14
-21
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/PacketHandler.kt
...mamoe.mirai/network/protocol/tim/handler/PacketHandler.kt
+2
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/TemporaryPacketHandler.kt
...ai/network/protocol/tim/handler/TemporaryPacketHandler.kt
+5
-5
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Annotations.kt
...et.mamoe.mirai/network/protocol/tim/packet/Annotations.kt
+3
-3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Decrypters.kt
...net.mamoe.mirai/network/protocol/tim/packet/Decrypters.kt
+52
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/FriendOnlineStatusChanged.kt
.../network/protocol/tim/packet/FriendOnlineStatusChanged.kt
+22
-17
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/GradeInfo.kt
.../net.mamoe.mirai/network/protocol/tim/packet/GradeInfo.kt
+7
-5
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Heartbeat.kt
.../net.mamoe.mirai/network/protocol/tim/packet/Heartbeat.kt
+10
-6
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/OutgoingPacket.kt
...mamoe.mirai/network/protocol/tim/packet/OutgoingPacket.kt
+15
-29
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/OutgoingRawPacket.kt
...oe.mirai/network/protocol/tim/packet/OutgoingRawPacket.kt
+0
-24
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Packet.kt
...lin/net.mamoe.mirai/network/protocol/tim/packet/Packet.kt
+173
-36
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Response.kt
...n/net.mamoe.mirai/network/protocol/tim/packet/Response.kt
+0
-17
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/ResponsePacket.kt
...mamoe.mirai/network/protocol/tim/packet/ResponsePacket.kt
+0
-27
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/ServerPacket.kt
...t.mamoe.mirai/network/protocol/tim/packet/ServerPacket.kt
+12
-60
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UnknownServerPacket.kt
....mirai/network/protocol/tim/packet/UnknownServerPacket.kt
+0
-25
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/AddContact.kt
...oe.mirai/network/protocol/tim/packet/action/AddContact.kt
+115
-65
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/AddFriendResult.kt
...rai/network/protocol/tim/packet/action/AddFriendResult.kt
+0
-23
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/Profile.kt
...mamoe.mirai/network/protocol/tim/packet/action/Profile.kt
+71
-68
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/SendFriendMessagePacket.kt
...ork/protocol/tim/packet/action/SendFriendMessagePacket.kt
+44
-47
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/SendGroupMessagePacket.kt
...work/protocol/tim/packet/action/SendGroupMessagePacket.kt
+6
-6
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/UploadImage.kt
...e.mirai/network/protocol/tim/packet/action/UploadImage.kt
+41
-43
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/AndroidOnlineEventPackets.kt
...rk/protocol/tim/packet/event/AndroidOnlineEventPackets.kt
+0
-14
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/GroupEventPackets.kt
...ai/network/protocol/tim/packet/event/GroupEventPackets.kt
+0
-94
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/MessageEventPackets.kt
.../network/protocol/tim/packet/event/MessageEventPackets.kt
+0
-133
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/ServerEventPackets.kt
...i/network/protocol/tim/packet/event/ServerEventPackets.kt
+196
-98
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/Captcha.kt
....mamoe.mirai/network/protocol/tim/packet/login/Captcha.kt
+73
-96
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/ChangeOnlineStatusPacket.kt
...ork/protocol/tim/packet/login/ChangeOnlineStatusPacket.kt
+9
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/PasswordSubmission.kt
...i/network/protocol/tim/packet/login/PasswordSubmission.kt
+172
-16
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/SKey.kt
...net.mamoe.mirai/network/protocol/tim/packet/login/SKey.kt
+13
-13
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/ServerLoginResponse.kt
.../network/protocol/tim/packet/login/ServerLoginResponse.kt
+0
-153
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/ServerLoginSuccessPacket.kt
...ork/protocol/tim/packet/login/ServerLoginSuccessPacket.kt
+0
-16
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/Session.kt
....mamoe.mirai/network/protocol/tim/packet/login/Session.kt
+25
-37
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/Touch.kt
...et.mamoe.mirai/network/protocol/tim/packet/login/Touch.kt
+39
-71
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotNetworkConfiguration.kt
...n/kotlin/net.mamoe.mirai/utils/BotNetworkConfiguration.kt
+1
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
.../commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/OnlineStatus.kt
...c/commonMain/kotlin/net.mamoe.mirai/utils/OnlineStatus.kt
+11
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/TEA.kt
...i-core/src/commonMain/kotlin/net.mamoe.mirai/utils/TEA.kt
+3
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt
.../commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt
+0
-68
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/OutputUtils.kt
...commonMain/kotlin/net.mamoe.mirai/utils/io/OutputUtils.kt
+7
-2
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/EventDispatcher.kt
...c/jvmMain/kotlin/net/mamoe/mirai/event/EventDispatcher.kt
+3
-2
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/CaptchaResolverJvm.kt
...vmMain/kotlin/net/mamoe/mirai/utils/CaptchaResolverJvm.kt
+3
-1
mirai-demos/mirai-demo-gentleman/build.gradle
mirai-demos/mirai-demo-gentleman/build.gradle
+2
-3
mirai-demos/mirai-demo-gentleman/lib/ExImageGallery.jar
mirai-demos/mirai-demo-gentleman/lib/ExImageGallery.jar
+0
-0
mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt
...rai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt
+2
-2
No files found.
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/MiraiEnvironment.kt
0 → 100644
View file @
bd9cf3bf
package
net.mamoe.mirai
actual
object
MiraiEnvironment
\ No newline at end of file
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/event/EventDispatcher.kt
0 → 100644
View file @
bd9cf3bf
package
net.mamoe.mirai.event
import
kotlinx.coroutines.CoroutineDispatcher
import
kotlinx.coroutines.asCoroutineDispatcher
import
java.util.concurrent.Executors
internal
actual
val
EventDispatcher
:
CoroutineDispatcher
=
Executors
.
newFixedThreadPool
(
2
).
asCoroutineDispatcher
()
\ No newline at end of file
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/network/protocol/tim/NetworkDispatcher.kt
0 → 100644
View file @
bd9cf3bf
package
net.mamoe.mirai.network.protocol.tim
import
kotlinx.coroutines.CoroutineDispatcher
import
kotlinx.coroutines.asCoroutineDispatcher
import
java.util.concurrent.Executors
/**
* 包处理协程调度器.
*
* JVM: 独立的 4 thread 调度器
*/
actual
val
NetworkDispatcher
:
CoroutineDispatcher
=
Executors
.
newFixedThreadPool
(
4
).
asCoroutineDispatcher
()
\ No newline at end of file
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformLogger.kt
0 → 100644
View file @
bd9cf3bf
package
net.mamoe.mirai.utils
import
android.util.Log
actual
typealias
PlatformLogger
=
AndroidLogger
/**
* Android 平台的默认的日志记录器, 使用 [Log]
* 不应该直接构造这个类的实例. 需使用 [DefaultLogger]
*/
open
class
AndroidLogger
internal
constructor
(
override
val
identity
:
String
?)
:
MiraiLoggerPlatformBase
()
{
override
fun
verbose0
(
any
:
Any
?)
{
Log
.
v
(
identity
,
any
.
toString
())
}
override
fun
verbose0
(
message
:
String
?,
e
:
Throwable
?)
{
Log
.
v
(
identity
,
message
.
toString
(),
e
)
}
override
fun
debug0
(
any
:
Any
?)
{
Log
.
d
(
identity
,
any
.
toString
())
}
override
fun
debug0
(
message
:
String
?,
e
:
Throwable
?)
{
Log
.
d
(
identity
,
message
.
toString
(),
e
)
}
override
fun
info0
(
any
:
Any
?)
{
Log
.
i
(
identity
,
any
.
toString
())
}
override
fun
info0
(
message
:
String
?,
e
:
Throwable
?)
{
Log
.
i
(
identity
,
message
.
toString
(),
e
)
}
override
fun
warning0
(
any
:
Any
?)
{
Log
.
w
(
identity
,
any
.
toString
())
}
override
fun
warning0
(
message
:
String
?,
e
:
Throwable
?)
{
Log
.
w
(
identity
,
message
.
toString
(),
e
)
}
override
fun
error0
(
any
:
Any
?)
{
Log
.
e
(
identity
,
any
.
toString
())
}
override
fun
error0
(
message
:
String
?,
e
:
Throwable
?)
{
Log
.
e
(
identity
,
message
.
toString
(),
e
)
}
}
\ No newline at end of file
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsAndroid.kt
0 → 100644
View file @
bd9cf3bf
package
net.mamoe.mirai.utils
import
io.ktor.client.HttpClient
import
io.ktor.client.engine.cio.CIO
import
io.ktor.client.request.HttpRequestBuilder
import
io.ktor.http.ContentType
import
io.ktor.http.content.OutgoingContent
import
io.ktor.util.KtorExperimentalAPI
import
kotlinx.coroutines.io.ByteWriteChannel
import
kotlinx.io.core.Input
import
java.io.DataInput
import
java.io.EOFException
import
java.io.InputStream
import
java.net.InetAddress
import
java.security.MessageDigest
import
java.util.zip.CRC32
/**
* 设备名
*/
actual
val
deviceName
:
String
get
()
=
InetAddress
.
getLocalHost
().
hostName
/**
* Ktor HttpClient. 不同平台使用不同引擎.
*/
@KtorExperimentalAPI
internal
actual
val
httpClient
:
HttpClient
get
()
=
HttpClient
(
CIO
)
/**
* Localhost 解析
*/
actual
fun
localIpAddress
():
String
=
InetAddress
.
getLocalHost
().
hostAddress
internal
actual
fun
HttpRequestBuilder
.
configureBody
(
inputSize
:
Long
,
input
:
Input
)
{
body
=
object
:
OutgoingContent
.
WriteChannelContent
()
{
override
val
contentType
:
ContentType
=
ContentType
.
Image
.
PNG
override
val
contentLength
:
Long
=
inputSize
override
suspend
fun
writeTo
(
channel
:
ByteWriteChannel
)
{
//不知道为什么这个 channel 在 common 找不到...
val
buffer
=
byteArrayOf
(
1
)
repeat
(
contentLength
.
toInt
())
{
input
.
readFully
(
buffer
,
0
,
1
)
channel
.
writeFully
(
buffer
,
0
,
1
)
}
}
}
}
/**
* MD5 算法
*
* @return 16 bytes
*/
actual
fun
md5
(
byteArray
:
ByteArray
):
ByteArray
=
MessageDigest
.
getInstance
(
"MD5"
).
digest
(
byteArray
)
fun
InputStream
.
md5
():
ByteArray
{
val
digest
=
MessageDigest
.
getInstance
(
"md5"
)
digest
.
reset
()
this
.
readInSequence
{
digest
.
update
(
it
.
toByte
())
}
return
digest
.
digest
()
}
fun
DataInput
.
md5
():
ByteArray
{
val
digest
=
MessageDigest
.
getInstance
(
"md5"
)
digest
.
reset
()
val
buffer
=
byteArrayOf
(
1
)
while
(
true
)
{
try
{
this
.
readFully
(
buffer
)
}
catch
(
e
:
EOFException
)
{
break
}
digest
.
update
(
buffer
[
0
])
}
return
digest
.
digest
()
}
private
inline
fun
InputStream
.
readInSequence
(
block
:
(
Int
)
->
Unit
)
{
var
read
:
Int
while
(
this
.
read
().
also
{
read
=
it
}
!=
-
1
)
{
block
(
read
)
}
}
/**
* CRC32 算法
*/
actual
fun
crc32
(
key
:
ByteArray
):
Int
=
CRC32
().
apply
{
update
(
key
)
}.
value
.
toInt
()
/**
* hostname 解析 ipv4
*/
actual
fun
solveIpAddress
(
hostname
:
String
):
String
=
InetAddress
.
getByName
(
hostname
).
hostAddress
\ No newline at end of file
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SolveCaptchaAndroid.kt
0 → 100644
View file @
bd9cf3bf
package
net.mamoe.mirai.utils
import
kotlinx.io.core.IoBuffer
/**
* 让用户处理验证码
*
* @return 用户输入得到的验证码. 非 null 时一定 `length==4`.
*/
internal
actual
suspend
fun
solveCaptcha
(
captchaBuffer
:
IoBuffer
):
String
?
{
TODO
(
"Unsupported yet"
)
}
\ No newline at end of file
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/io/PlatformDatagramChannelAndroid.kt
0 → 100644
View file @
bd9cf3bf
package
net.mamoe.mirai.utils.io
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.withContext
import
kotlinx.io.core.Closeable
import
kotlinx.io.core.IoBuffer
import
kotlinx.io.nio.read
import
java.net.InetSocketAddress
import
java.nio.channels.DatagramChannel
import
java.nio.channels.ReadableByteChannel
/**
* 多平台适配的 DatagramChannel.
*/
actual
class
PlatformDatagramChannel
actual
constructor
(
serverHost
:
String
,
serverPort
:
Short
)
:
Closeable
{
private
val
serverAddress
:
InetSocketAddress
=
InetSocketAddress
(
serverHost
,
serverPort
.
toInt
())
private
val
channel
:
DatagramChannel
=
DatagramChannel
.
open
().
connect
(
serverAddress
)
@Throws
(
ReadPacketInternalException
::
class
)
actual
suspend
fun
read
(
buffer
:
IoBuffer
)
=
withContext
(
Dispatchers
.
IO
)
{
try
{
(
channel
as
ReadableByteChannel
).
read
(
buffer
)
}
catch
(
e
:
Throwable
)
{
throw
ReadPacketInternalException
(
e
)
}
}
@Throws
(
SendPacketInternalException
::
class
)
actual
suspend
fun
send
(
buffer
:
IoBuffer
)
=
withContext
(
Dispatchers
.
IO
)
{
buffer
.
readDirect
{
try
{
channel
.
send
(
it
,
serverAddress
)
}
catch
(
e
:
Throwable
)
{
throw
SendPacketInternalException
(
e
)
}
}
}
override
fun
close
()
{
channel
.
close
()
}
actual
val
isOpen
:
Boolean
get
()
=
channel
.
isOpen
}
actual
typealias
ClosedChannelException
=
java
.
nio
.
channels
.
ClosedChannelException
\ No newline at end of file
mirai-core/src/androidMain/res/AndroidManifest.xml
0 → 100644
View file @
bd9cf3bf
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android=
"http://schemas.android.com/apk/res/android"
package=
"net.mamoe.mirai"
>
<application
android:allowBackup=
"true"
android:supportsRtl=
"true"
>
</application>
</manifest>
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
View file @
bd9cf3bf
...
@@ -11,6 +11,7 @@ import net.mamoe.mirai.message.singleChain
...
@@ -11,6 +11,7 @@ import net.mamoe.mirai.message.singleChain
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.protocol.tim.handler.EventPacketHandler
import
net.mamoe.mirai.network.protocol.tim.handler.EventPacketHandler
import
net.mamoe.mirai.network.protocol.tim.packet.action.RequestProfileDetailsPacket
import
net.mamoe.mirai.network.protocol.tim.packet.action.RequestProfileDetailsPacket
import
net.mamoe.mirai.network.protocol.tim.packet.action.RequestProfileDetailsResponse
import
net.mamoe.mirai.qqAccount
import
net.mamoe.mirai.qqAccount
import
net.mamoe.mirai.utils.SuspendLazy
import
net.mamoe.mirai.utils.SuspendLazy
import
net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
import
net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
...
@@ -129,7 +130,7 @@ open class QQ internal constructor(bot: Bot, id: UInt) : Contact(bot, id) {
...
@@ -129,7 +130,7 @@ open class QQ internal constructor(bot: Bot, id: UInt) : Contact(bot, id) {
*/
*/
suspend
fun
updateProfile
():
Profile
=
bot
.
withSession
{
suspend
fun
updateProfile
():
Profile
=
bot
.
withSession
{
RequestProfileDetailsPacket
(
bot
.
qqAccount
,
id
,
sessionKey
)
RequestProfileDetailsPacket
(
bot
.
qqAccount
,
id
,
sessionKey
)
.
sendAndExpect
<
RequestProfileDetails
Packet
.
Response
,
Profile
>
{
it
.
profile
}
.
sendAndExpect
<
RequestProfileDetailsResponse
,
Profile
>
{
it
.
profile
}
.
await
().
let
{
.
await
().
let
{
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
if
((
::
profile
as
SuspendLazy
<
Profile
>).
isInitialized
())
{
if
((
::
profile
as
SuspendLazy
<
Profile
>).
isInitialized
())
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/FriendEvents.kt
View file @
bd9cf3bf
...
@@ -34,4 +34,9 @@ class FriendConversationInitializedEvent(bot: Bot, sender: QQ) : FriendEvent(bot
...
@@ -34,4 +34,9 @@ class FriendConversationInitializedEvent(bot: Bot, sender: QQ) : FriendEvent(bot
/**
/**
* 好友在线状态改变事件
* 好友在线状态改变事件
*/
*/
class
FriendOnlineStatusChangedEvent
(
bot
:
Bot
,
sender
:
QQ
,
val
newStatus
:
OnlineStatus
)
:
FriendEvent
(
bot
,
sender
)
class
FriendOnlineStatusChangedEvent
(
bot
:
Bot
,
sender
:
QQ
,
val
newStatus
:
OnlineStatus
)
:
FriendEvent
(
bot
,
sender
)
\ No newline at end of file
/**
* 机器人账号被 [sender] 删除好友
*/
class
DeletedByFriendEvent
(
bot
:
Bot
,
qq
:
QQ
)
:
FriendEvent
(
bot
,
qq
)
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PacketEvents.kt
View file @
bd9cf3bf
...
@@ -4,7 +4,6 @@ import net.mamoe.mirai.Bot
...
@@ -4,7 +4,6 @@ import net.mamoe.mirai.Bot
import
net.mamoe.mirai.event.Cancellable
import
net.mamoe.mirai.event.Cancellable
import
net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
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.Packet
import
net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
/* Abstract */
/* Abstract */
...
@@ -43,10 +42,10 @@ class BeforePacketSendEvent(bot: Bot, packet: OutgoingPacket) : OutgoingPacketEv
...
@@ -43,10 +42,10 @@ class BeforePacketSendEvent(bot: Bot, packet: OutgoingPacket) : OutgoingPacketEv
/**
/**
* 来自服务器的数据包的相关事件
* 来自服务器的数据包的相关事件
*/
*/
sealed
class
ServerPacketEvent
<
P
:
Server
Packet
>(
bot
:
Bot
,
packet
:
P
)
:
PacketEvent
<
P
>(
bot
,
packet
)
sealed
class
ServerPacketEvent
<
P
:
Packet
>(
bot
:
Bot
,
packet
:
P
)
:
PacketEvent
<
P
>(
bot
,
packet
)
/**
/**
* 服务器数据包接收事件. 此时包已经解密完成.
* 服务器数据包接收事件. 此时包已经解密完成.
*/
*/
class
ServerPacketReceivedEvent
<
P
:
Server
Packet
>(
bot
:
Bot
,
packet
:
P
)
:
ServerPacketEvent
<
P
>(
bot
,
packet
),
class
ServerPacketReceivedEvent
<
P
:
Packet
>(
bot
:
Bot
,
packet
:
P
)
:
ServerPacketEvent
<
P
>(
bot
,
packet
),
Cancellable
Cancellable
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt
View file @
bd9cf3bf
...
@@ -4,14 +4,13 @@ import kotlinx.coroutines.CancellationException
...
@@ -4,14 +4,13 @@ import kotlinx.coroutines.CancellationException
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.Job
import
kotlinx.coroutines.Job
import
kotlinx.coroutines.cancelChildren
import
kotlinx.coroutines.cancelChildren
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.BotSocketAdapter
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.TIMBotNetworkHandler.LoginHandler
import
net.mamoe.mirai.network.protocol.tim.handler.*
import
net.mamoe.mirai.network.protocol.tim.handler.*
import
net.mamoe.mirai.network.protocol.tim.packet.HeartbeatPacket
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.OutgoingPacket
import
net.mamoe.mirai.network.protocol.tim.packet.Packet
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.event.ServerEventPacket
import
net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import
net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import
net.mamoe.mirai.network.protocol.tim.packet.login.RequestSKeyPacket
import
net.mamoe.mirai.network.protocol.tim.packet.login.RequestSKeyPacket
import
net.mamoe.mirai.utils.BotNetworkConfiguration
import
net.mamoe.mirai.utils.BotNetworkConfiguration
...
@@ -48,6 +47,7 @@ import net.mamoe.mirai.utils.io.PlatformDatagramChannel
...
@@ -48,6 +47,7 @@ import net.mamoe.mirai.utils.io.PlatformDatagramChannel
@Suppress
(
"PropertyName"
)
@Suppress
(
"PropertyName"
)
interface
BotNetworkHandler
<
Socket
:
DataPacketSocketAdapter
>
:
CoroutineScope
{
interface
BotNetworkHandler
<
Socket
:
DataPacketSocketAdapter
>
:
CoroutineScope
{
val
socket
:
Socket
val
socket
:
Socket
val
bot
:
Bot
/**
/**
* 得到 [PacketHandler].
* 得到 [PacketHandler].
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt
View file @
bd9cf3bf
...
@@ -11,7 +11,8 @@ import net.mamoe.mirai.network.protocol.tim.handler.ActionPacketHandler
...
@@ -11,7 +11,8 @@ 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.DataPacketSocketAdapter
import
net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler
import
net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler
import
net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
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.Packet
import
net.mamoe.mirai.network.protocol.tim.packet.SessionKey
import
net.mamoe.mirai.utils.getGTK
import
net.mamoe.mirai.utils.getGTK
import
kotlin.coroutines.coroutineContext
import
kotlin.coroutines.coroutineContext
...
@@ -21,7 +22,7 @@ import kotlin.coroutines.coroutineContext
...
@@ -21,7 +22,7 @@ import kotlin.coroutines.coroutineContext
@Suppress
(
"FunctionName"
,
"NOTHING_TO_INLINE"
)
@Suppress
(
"FunctionName"
,
"NOTHING_TO_INLINE"
)
internal
inline
fun
TIMBotNetworkHandler
.
BotSession
(
internal
inline
fun
TIMBotNetworkHandler
.
BotSession
(
bot
:
Bot
,
bot
:
Bot
,
sessionKey
:
ByteArra
y
,
sessionKey
:
SessionKe
y
,
socket
:
DataPacketSocketAdapter
socket
:
DataPacketSocketAdapter
)
=
BotSession
(
bot
,
sessionKey
,
socket
,
this
)
)
=
BotSession
(
bot
,
sessionKey
,
socket
,
this
)
...
@@ -33,7 +34,7 @@ internal inline fun TIMBotNetworkHandler.BotSession(
...
@@ -33,7 +34,7 @@ internal inline fun TIMBotNetworkHandler.BotSession(
*/
*/
class
BotSession
(
class
BotSession
(
val
bot
:
Bot
,
val
bot
:
Bot
,
val
sessionKey
:
ByteArra
y
,
val
sessionKey
:
SessionKe
y
,
val
socket
:
DataPacketSocketAdapter
,
val
socket
:
DataPacketSocketAdapter
,
val
NetworkScope
:
CoroutineScope
val
NetworkScope
:
CoroutineScope
)
{
)
{
...
@@ -79,7 +80,10 @@ class BotSession(
...
@@ -79,7 +80,10 @@ class BotSession(
*
*
* @see Bot.withSession 转换接收器 (receiver, 即 `this` 的指向) 为 [BotSession]
* @see Bot.withSession 转换接收器 (receiver, 即 `this` 的指向) 为 [BotSession]
*/
*/
suspend
inline
fun
<
reified
P
:
ServerPacket
,
R
>
OutgoingPacket
.
sendAndExpect
(
checkSequence
:
Boolean
=
true
,
noinline
handler
:
suspend
(
P
)
->
R
):
CompletableDeferred
<
R
>
{
suspend
inline
fun
<
reified
P
:
Packet
,
R
>
OutgoingPacket
.
sendAndExpect
(
checkSequence
:
Boolean
=
true
,
noinline
handler
:
suspend
(
P
)
->
R
):
CompletableDeferred
<
R
>
{
val
deferred
:
CompletableDeferred
<
R
>
=
CompletableDeferred
(
coroutineContext
[
Job
])
val
deferred
:
CompletableDeferred
<
R
>
=
CompletableDeferred
(
coroutineContext
[
Job
])
bot
.
network
.
addHandler
(
TemporaryPacketHandler
(
P
::
class
,
deferred
,
this
@BotSession
,
checkSequence
,
coroutineContext
+
deferred
).
also
{
bot
.
network
.
addHandler
(
TemporaryPacketHandler
(
P
::
class
,
deferred
,
this
@BotSession
,
checkSequence
,
coroutineContext
+
deferred
).
also
{
it
.
toSend
(
this
)
it
.
toSend
(
this
)
...
@@ -92,13 +96,13 @@ class BotSession(
...
@@ -92,13 +96,13 @@ class BotSession(
* 发送一个数据包, 并期待接受一个特定的 [ServerPacket][P].
* 发送一个数据包, 并期待接受一个特定的 [ServerPacket][P].
* 您将能从本函数的返回值 [CompletableDeferred] 接收到所期待的 [P]
* 您将能从本函数的返回值 [CompletableDeferred] 接收到所期待的 [P]
*/
*/
suspend
inline
fun
<
reified
P
:
ServerPacket
>
OutgoingPacket
.
sendAndExpect
(
checkSequence
:
Boolean
=
true
):
CompletableDeferred
<
P
>
=
sendAndExpect
<
P
,
P
>(
checkSequence
)
{
it
}
suspend
inline
fun
<
reified
P
:
Packet
>
OutgoingPacket
.
sendAndExpect
(
checkSequence
:
Boolean
=
true
):
CompletableDeferred
<
P
>
=
sendAndExpect
<
P
,
P
>(
checkSequence
)
{
it
}
suspend
inline
fun
OutgoingPacket
.
send
()
=
socket
.
sendPacket
(
this
)
suspend
inline
fun
OutgoingPacket
.
send
()
=
socket
.
sendPacket
(
this
)
}
}
suspend
inline
fun
BotSession
.
distributePacket
(
packet
:
ServerPacket
)
=
this
.
socket
.
distributePacket
(
packet
)
inline
val
BotSession
.
isOpen
:
Boolean
get
()
=
socket
.
isOpen
inline
val
BotSession
.
isOpen
:
Boolean
get
()
=
socket
.
isOpen
inline
val
BotSession
.
qqAccount
:
UInt
get
()
=
bot
.
account
.
id
inline
val
BotSession
.
qqAccount
:
UInt
get
()
=
bot
.
account
.
id
...
@@ -106,22 +110,22 @@ inline val BotSession.qqAccount: UInt get() = bot.account.id
...
@@ -106,22 +110,22 @@ inline val BotSession.qqAccount: UInt get() = bot.account.id
* 取得 [BotNetworkHandler] 的 [BotSession].
* 取得 [BotNetworkHandler] 的 [BotSession].
* 实际上是一个捷径.
* 实际上是一个捷径.
*/
*/
val
BotNetworkHandler
<*>.
session
get
()
=
this
[
ActionPacketHandler
].
session
val
BotNetworkHandler
<*>.
session
:
BotSession
get
()
=
this
[
ActionPacketHandler
].
session
/**
/**
* 取得 [BotNetworkHandler] 的 sessionKey.
* 取得 [BotNetworkHandler] 的 sessionKey.
* 实际上是一个捷径.
* 实际上是一个捷径.
*/
*/
inline
val
BotNetworkHandler
<*>.
sessionKey
get
()
=
this
.
session
.
sessionKey
inline
val
BotNetworkHandler
<*>.
sessionKey
:
SessionKey
get
()
=
this
.
session
.
sessionKey
/**
/**
* 取得 [Bot] 的 [BotSession].
* 取得 [Bot] 的 [BotSession].
* 实际上是一个捷径.
* 实际上是一个捷径.
*/
*/
inline
val
Bot
.
session
get
()
=
this
.
network
.
session
inline
val
Bot
.
session
:
BotSession
get
()
=
this
.
network
.
session
/**
/**
* 取得 [Bot] 的 `sessionKey`.
* 取得 [Bot] 的 `sessionKey`.
* 实际上是一个捷径.
* 实际上是一个捷径.
*/
*/
inline
val
Bot
.
sessionKey
get
()
=
this
.
session
.
sessionKey
inline
val
Bot
.
sessionKey
:
SessionKey
get
()
=
this
.
session
.
sessionKey
\ No newline at end of file
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt
View file @
bd9cf3bf
This diff is collapsed.
Click to expand it.
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/ActionPacketHandler.kt
View file @
bd9cf3bf
...
@@ -8,11 +8,10 @@ import kotlinx.coroutines.launch
...
@@ -8,11 +8,10 @@ import kotlinx.coroutines.launch
import
kotlinx.coroutines.withContext
import
kotlinx.coroutines.withContext
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.isOpen
import
net.mamoe.mirai.network.isOpen
import
net.mamoe.mirai.network.protocol.tim.packet.Packet
import
net.mamoe.mirai.network.protocol.tim.packet.RequestAccountInfoPacket
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.event.ServerEventPacket
import
net.mamoe.mirai.network.protocol.tim.packet.login.RequestSKeyPacket
import
net.mamoe.mirai.network.protocol.tim.packet.login.RequestSKeyPacket
import
net.mamoe.mirai.network.protocol.tim.packet.login.SKey
import
net.mamoe.mirai.network.qqAccount
import
net.mamoe.mirai.network.qqAccount
/**
/**
...
@@ -29,10 +28,10 @@ class ActionPacketHandler(session: BotSession) : PacketHandler(session) {
...
@@ -29,10 +28,10 @@ class ActionPacketHandler(session: BotSession) : PacketHandler(session) {
@ExperimentalStdlibApi
@ExperimentalStdlibApi
override
suspend
fun
onPacketReceived
(
packet
:
Server
Packet
):
Unit
=
with
(
session
)
{
override
suspend
fun
onPacketReceived
(
packet
:
Packet
):
Unit
=
with
(
session
)
{
when
(
packet
)
{
when
(
packet
)
{
is
RequestSKeyPacket
.
Response
->
{
is
SKey
->
{
sKey
=
packet
.
sKey
sKey
=
packet
.
delegate
cookies
=
"uin=o$qqAccount;skey=$sKey;"
cookies
=
"uin=o$qqAccount;skey=$sKey;"
...
@@ -50,10 +49,6 @@ class ActionPacketHandler(session: BotSession) : PacketHandler(session) {
...
@@ -50,10 +49,6 @@ class ActionPacketHandler(session: BotSession) : PacketHandler(session) {
}
}
}
}
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
->
{
else
->
{
}
}
}
}
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/DataPacketSocketAdapter.kt
View file @
bd9cf3bf
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
)
package
net.mamoe.mirai.network.protocol.tim.handler
package
net.mamoe.mirai.network.protocol.tim.handler
import
kotlinx.io.core.Closeable
import
kotlinx.io.core.Closeable
...
@@ -6,7 +8,6 @@ import net.mamoe.mirai.event.events.ServerPacketReceivedEvent
...
@@ -6,7 +8,6 @@ import net.mamoe.mirai.event.events.ServerPacketReceivedEvent
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import
net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import
net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import
net.mamoe.mirai.utils.io.PlatformDatagramChannel
import
net.mamoe.mirai.utils.io.PlatformDatagramChannel
/**
/**
...
@@ -35,11 +36,6 @@ interface DataPacketSocketAdapter : Closeable {
...
@@ -35,11 +36,6 @@ interface DataPacketSocketAdapter : Closeable {
*/
*/
val
isOpen
:
Boolean
val
isOpen
:
Boolean
/**
* 分发数据包给 [PacketHandler]
*/
suspend
fun
distributePacket
(
packet
:
ServerPacket
)
/**
/**
* 发送一个数据包(非异步).
* 发送一个数据包(非异步).
*
*
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/EventPacketHandler.kt
View file @
bd9cf3bf
...
@@ -10,13 +10,12 @@ import net.mamoe.mirai.getGroup
...
@@ -10,13 +10,12 @@ import net.mamoe.mirai.getGroup
import
net.mamoe.mirai.getQQ
import
net.mamoe.mirai.getQQ
import
net.mamoe.mirai.message.MessageChain
import
net.mamoe.mirai.message.MessageChain
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.
distribute
Packet
import
net.mamoe.mirai.network.
protocol.tim.packet.Event
Packet
import
net.mamoe.mirai.network.protocol.tim.packet.Friend
OnlineStatusChangedPacket
import
net.mamoe.mirai.network.protocol.tim.packet.Friend
StatusChanged
import
net.mamoe.mirai.network.protocol.tim.packet.
Server
Packet
import
net.mamoe.mirai.network.protocol.tim.packet.Packet
import
net.mamoe.mirai.network.protocol.tim.packet.action.FriendImageIdRequestPacket
import
net.mamoe.mirai.network.protocol.tim.packet.action.FriendImageIdRequestPacket
import
net.mamoe.mirai.network.protocol.tim.packet.action.SendFriendMessagePacket
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.action.SendGroupMessagePacket
import
net.mamoe.mirai.network.protocol.tim.packet.event.*
import
net.mamoe.mirai.network.qqAccount
import
net.mamoe.mirai.network.qqAccount
/**
/**
...
@@ -28,35 +27,29 @@ import net.mamoe.mirai.network.qqAccount
...
@@ -28,35 +27,29 @@ import net.mamoe.mirai.network.qqAccount
class
EventPacketHandler
(
session
:
BotSession
)
:
PacketHandler
(
session
)
{
class
EventPacketHandler
(
session
:
BotSession
)
:
PacketHandler
(
session
)
{
companion
object
Key
:
PacketHandler
.
Key
<
EventPacketHandler
>
companion
object
Key
:
PacketHandler
.
Key
<
EventPacketHandler
>
override
suspend
fun
onPacketReceived
(
packet
:
Server
Packet
):
Unit
=
with
(
session
)
{
override
suspend
fun
onPacketReceived
(
packet
:
Packet
):
Unit
=
with
(
session
)
{
when
(
packet
)
{
when
(
packet
)
{
is
ServerGroupUploadFileEventPacket
->
{
is
EventPacket
.
FriendMessage
->
{
//todo
if
(!
packet
.
isPrevious
)
FriendMessageEvent
(
bot
,
bot
.
getQQ
(
packet
.
qq
),
packet
.
message
)
else
null
}
}
is
FriendMessageEventPacket
->
{
is
EventPacket
.
GroupMessage
->
{
if
(!
packet
.
isPrevious
)
FriendMessageEvent
(
bot
,
bot
.
getQQ
(
packet
.
qq
),
packet
.
message
).
broadcast
()
}
is
GroupMessageEventPacket
->
{
if
(
packet
.
qq
==
bot
.
account
.
id
)
return
if
(
packet
.
qq
==
bot
.
account
.
id
)
return
GroupMessageEvent
(
GroupMessageEvent
(
bot
,
bot
.
getGroup
(
GroupId
(
packet
.
groupNumber
)),
bot
.
getQQ
(
packet
.
qq
),
packet
.
message
,
packet
.
senderPermission
,
packet
.
senderName
bot
,
bot
.
getGroup
(
GroupId
(
packet
.
groupNumber
)),
bot
.
getQQ
(
packet
.
qq
),
packet
.
message
,
packet
.
senderPermission
,
packet
.
senderName
)
.
broadcast
()
)
}
}
is
FriendConversationInitializedEventPacket
->
FriendConversationInitializedEvent
(
bot
,
bot
.
getQQ
(
packet
.
qq
)).
broadcast
(
)
is
EventPacket
.
FriendConversationInitialize
->
FriendConversationInitializedEvent
(
bot
,
bot
.
getQQ
(
packet
.
qq
)
)
is
Friend
OnlineStatusChangedPacket
->
FriendOnlineStatusChangedEvent
(
bot
,
bot
.
getQQ
(
packet
.
qq
),
packet
.
status
).
broadcast
(
)
is
Friend
StatusChanged
->
FriendOnlineStatusChangedEvent
(
bot
,
bot
.
getQQ
(
packet
.
qq
),
packet
.
status
)
is
FriendImageIdRequestPacket
.
Response
->
packet
.
imageId
?.
let
{
FriendImageIdObtainedEvent
(
bot
,
it
)
}
is
FriendImageIdRequestPacket
.
Response
->
packet
.
imageId
?.
let
{
FriendImageIdObtainedEvent
(
bot
,
it
)
}
is
GroupMemberPermissionChangedEventPacket
->
MemberPermissionChangedEvent
(
is
EventPacket
.
MemberPermissionChange
->
bot
,
bot
.
getGroup
(
packet
.
groupId
.
groupId
()),
bot
.
getQQ
(
packet
.
qq
),
packet
.
kind
MemberPermissionChangedEvent
(
bot
,
bot
.
getGroup
(
packet
.
groupId
.
groupId
()),
bot
.
getQQ
(
packet
.
qq
),
packet
.
kind
)
).
broadcast
()
is
FriendOnlineStatusChangedPacket
.
Encrypted
->
distributePacket
(
packet
.
decrypt
(
sessionKey
))
else
->
null
}
}
?.
broadcast
()
}
}
suspend
fun
sendFriendMessage
(
qq
:
QQ
,
message
:
MessageChain
)
{
suspend
fun
sendFriendMessage
(
qq
:
QQ
,
message
:
MessageChain
)
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/PacketHandler.kt
View file @
bd9cf3bf
package
net.mamoe.mirai.network.protocol.tim.handler
package
net.mamoe.mirai.network.protocol.tim.handler
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.protocol.tim.packet.
Server
Packet
import
net.mamoe.mirai.network.protocol.tim.packet.Packet
/**
/**
* 数据包(接受/发送)处理器
* 数据包(接受/发送)处理器
...
@@ -9,7 +9,7 @@ import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
...
@@ -9,7 +9,7 @@ import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
abstract
class
PacketHandler
(
abstract
class
PacketHandler
(
val
session
:
BotSession
val
session
:
BotSession
)
{
)
{
abstract
suspend
fun
onPacketReceived
(
packet
:
Server
Packet
)
abstract
suspend
fun
onPacketReceived
(
packet
:
Packet
)
interface
Key
<
T
:
PacketHandler
>
interface
Key
<
T
:
PacketHandler
>
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/TemporaryPacketHandler.kt
View file @
bd9cf3bf
...
@@ -6,7 +6,7 @@ import kotlinx.coroutines.CompletableDeferred
...
@@ -6,7 +6,7 @@ import kotlinx.coroutines.CompletableDeferred
import
kotlinx.coroutines.withContext
import
kotlinx.coroutines.withContext
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import
net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import
net.mamoe.mirai.network.protocol.tim.packet.
Server
Packet
import
net.mamoe.mirai.network.protocol.tim.packet.Packet
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.CoroutineContext
import
kotlin.reflect.KClass
import
kotlin.reflect.KClass
...
@@ -23,7 +23,7 @@ import kotlin.reflect.KClass
...
@@ -23,7 +23,7 @@ import kotlin.reflect.KClass
*
*
* @see BotSession.sendAndExpect
* @see BotSession.sendAndExpect
*/
*/
class
TemporaryPacketHandler
<
P
:
Server
Packet
,
R
>(
class
TemporaryPacketHandler
<
P
:
Packet
,
R
>(
private
val
expectationClass
:
KClass
<
P
>,
private
val
expectationClass
:
KClass
<
P
>,
private
val
deferred
:
CompletableDeferred
<
R
>,
private
val
deferred
:
CompletableDeferred
<
R
>,
private
val
fromSession
:
BotSession
,
private
val
fromSession
:
BotSession
,
...
@@ -54,10 +54,10 @@ class TemporaryPacketHandler<P : ServerPacket, R>(
...
@@ -54,10 +54,10 @@ class TemporaryPacketHandler<P : ServerPacket, R>(
session
.
socket
.
sendPacket
(
toSend
)
session
.
socket
.
sendPacket
(
toSend
)
}
}
internal
fun
filter
(
session
:
BotSession
,
packet
:
ServerPacke
t
):
Boolean
=
internal
fun
filter
(
session
:
BotSession
,
packet
:
Packet
,
sequenceId
:
UShor
t
):
Boolean
=
expectationClass
.
isInstance
(
packet
)
&&
session
===
this
.
fromSession
&&
if
(
checkSequence
)
packet
.
sequenceId
==
toSend
.
sequenceId
else
true
expectationClass
.
isInstance
(
packet
)
&&
session
===
this
.
fromSession
&&
if
(
checkSequence
)
sequenceId
==
toSend
.
sequenceId
else
true
internal
suspend
fun
doReceiveWithoutExceptions
(
packet
:
Server
Packet
)
{
internal
suspend
fun
doReceiveWithoutExceptions
(
packet
:
Packet
)
{
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
val
ret
=
try
{
val
ret
=
try
{
withContext
(
callerContext
)
{
withContext
(
callerContext
)
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Annotations.kt
View file @
bd9cf3bf
...
@@ -7,7 +7,7 @@ import kotlin.reflect.KClass
...
@@ -7,7 +7,7 @@ import kotlin.reflect.KClass
/**
/**
* 包 ID. 除特殊外, [
OutgoingPacketBuilder
] 都需要这个注解来指定包 ID.
* 包 ID. 除特殊外, [
PacketFactory
] 都需要这个注解来指定包 ID.
*/
*/
@MustBeDocumented
@MustBeDocumented
@Retention
(
AnnotationRetention
.
RUNTIME
)
@Retention
(
AnnotationRetention
.
RUNTIME
)
...
@@ -21,7 +21,7 @@ inline val AnnotatedId.value: UShort get() = id.value
...
@@ -21,7 +21,7 @@ inline val AnnotatedId.value: UShort get() = id.value
/**
/**
* 标记这个包对应的事件.
* 标记这个包对应的事件.
* 这个注解应该被标记在 [
Server
Packet] 上
* 这个注解应该被标记在 [Packet] 上
*/
*/
@MustBeDocumented
@MustBeDocumented
@Retention
(
AnnotationRetention
.
BINARY
)
@Retention
(
AnnotationRetention
.
BINARY
)
...
@@ -34,7 +34,7 @@ annotation class CorrespondingEvent(
...
@@ -34,7 +34,7 @@ annotation class CorrespondingEvent(
* 版本信息
* 版本信息
*/
*/
@MustBeDocumented
@MustBeDocumented
@Target
(
AnnotationTarget
.
FUNCTION
,
AnnotationTarget
.
CLASS
)
@Target
(
AnnotationTarget
.
FUNCTION
,
AnnotationTarget
.
CLASS
,
AnnotationTarget
.
PROPERTY
)
@Retention
(
AnnotationRetention
.
BINARY
)
@Retention
(
AnnotationRetention
.
BINARY
)
internal
annotation
class
PacketVersion
(
val
date
:
String
,
val
timVersion
:
String
)
internal
annotation
class
PacketVersion
(
val
date
:
String
,
val
timVersion
:
String
)
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Decrypters.kt
0 → 100644
View file @
bd9cf3bf
package
net.mamoe.mirai.network.protocol.tim.packet
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.IoBuffer
/**
* 会话密匙
*/
inline
class
SessionKey
(
override
val
value
:
ByteArray
)
:
DecrypterByteArray
{
companion
object
Type
:
DecrypterType
<
SessionKey
>
}
/**
* [ByteArray] 解密器
*/
interface
DecrypterByteArray
:
Decrypter
{
val
value
:
ByteArray
override
fun
decrypt
(
packet
:
ByteReadPacket
):
ByteReadPacket
=
packet
.
decryptBy
(
value
)
}
/**
* [IoBuffer] 解密器
*/
interface
DecrypterIoBuffer
:
Decrypter
{
val
value
:
IoBuffer
override
fun
decrypt
(
packet
:
ByteReadPacket
):
ByteReadPacket
=
packet
.
decryptBy
(
value
)
}
/**
* 连接在一起的解密器
*/
inline
class
LinkedDecrypter
(
inline
val
block
:
(
ByteReadPacket
)
->
ByteReadPacket
)
:
Decrypter
{
override
fun
decrypt
(
packet
:
ByteReadPacket
):
ByteReadPacket
=
block
(
packet
)
}
object
NoDecrypter
:
Decrypter
,
DecrypterType
<
NoDecrypter
>
{
override
fun
decrypt
(
packet
:
ByteReadPacket
):
ByteReadPacket
=
packet
}
/**
* 解密器
*/
interface
Decrypter
{
fun
decrypt
(
packet
:
ByteReadPacket
):
ByteReadPacket
/**
* 连接后将会先用 this 解密, 再用 [another] 解密
*/
operator
fun
plus
(
another
:
Decrypter
):
Decrypter
=
LinkedDecrypter
{
another
.
decrypt
(
this
.
decrypt
(
it
))
}
}
interface
DecrypterType
<
D
:
Decrypter
>
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/FriendOnlineStatusChanged.kt
View file @
bd9cf3bf
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
,
"EXPERIMENTAL_UNSIGNED_LITERALS"
)
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
,
"EXPERIMENTAL_UNSIGNED_LITERALS"
,
"JoinDeclarationAndAssignment"
)
package
net.mamoe.mirai.network.protocol.tim.packet
package
net.mamoe.mirai.network.protocol.tim.packet
...
@@ -6,30 +6,35 @@ import kotlinx.io.core.ByteReadPacket
...
@@ -6,30 +6,35 @@ import kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.discardExact
import
kotlinx.io.core.discardExact
import
kotlinx.io.core.readUByte
import
kotlinx.io.core.readUByte
import
kotlinx.io.core.readUInt
import
kotlinx.io.core.readUInt
import
net.mamoe.mirai.event.events.FriendOnlineStatusChangedEvent
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.utils.OnlineStatus
import
net.mamoe.mirai.utils.OnlineStatus
import
kotlin.properties.Delegates
@CorrespondingEvent
(
FriendOnlineStatusChangedEvent
::
class
)
abstract
class
FriendStatusChanged
:
Packet
{
abstract
val
qq
:
UInt
abstract
val
status
:
OnlineStatus
}
/**
/**
* 好友在线状态改变
* 好友在线状态改变
*/
*/
@AnnotatedId
(
KnownPacketId
.
SEND_FRIEND_MESSAGE
)
@AnnotatedId
(
KnownPacketId
.
FRIEND_ONLINE_STATUS_CHANGE
)
class
FriendOnlineStatusChangedPacket
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
object
FriendOnlineStatusChangedPacket
:
SessionPacketFactory
<
FriendStatusChanged
>()
{
var
qq
:
UInt
by
Delegates
.
notNull
()
lateinit
var
status
:
OnlineStatus
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
FriendStatusChanged
=
object
:
FriendStatusChanged
()
{
override
val
qq
:
UInt
override
val
status
:
OnlineStatus
override
fun
decode
()
=
with
(
input
)
{
init
{
qq
=
readUInt
()
qq
=
readUInt
()
discardExact
(
8
)
discardExact
(
8
)
val
id
=
readUByte
()
val
id
=
readUByte
()
status
=
OnlineStatus
.
ofId
(
id
)
?:
error
(
"Unknown online status id $id"
)
status
=
OnlineStatus
.
ofId
(
id
)
?:
error
(
"Unknown online status id $id"
)
}
}
}
//在线 XX XX XX XX 01 00 00 00 00 00 00 00 0A 15 E3 10 00 01 2E 01 00 00 00 00 00 00 00 00 00 00 00 13 08 02 C2 76 E4 B8 DD 00 00 00 00 00 00 00 00 00 00 00
//在线 XX XX XX XX 01 00 00 00 00 00 00 00 0A 15 E3 10 00 01 2E 01 00 00 00 00 00 00 00 00 00 00 00 13 08 02 C2 76 E4 B8 DD 00 00 00 00 00 00 00 00 00 00 00
//忙碌 XX XX XX XX 01 00 00 00 00 00 00 00 32 15 E3 10 00 01 2E 01 00 00 00 00 00 00 00 00 00 00 00 13 08 02 C2 76 E4 B8 DD 00 00 00 00 00 00 00 00 00 00 00
//忙碌 XX XX XX XX 01 00 00 00 00 00 00 00 32 15 E3 10 00 01 2E 01 00 00 00 00 00 00 00 00 00 00 00 13 08 02 C2 76 E4 B8 DD 00 00 00 00 00 00 00 00 00 00 00
@AnnotatedId
(
KnownPacketId
.
SEND_FRIEND_MESSAGE
)
class
Encrypted
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
fun
decrypt
(
sessionKey
:
ByteArray
):
FriendOnlineStatusChangedPacket
=
FriendOnlineStatusChangedPacket
(
this
.
decryptBy
(
sessionKey
)).
applySequence
(
sequenceId
)
}
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/GradeInfo.kt
View file @
bd9cf3bf
...
@@ -4,6 +4,7 @@ package net.mamoe.mirai.network.protocol.tim.packet
...
@@ -4,6 +4,7 @@ package net.mamoe.mirai.network.protocol.tim.packet
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.writeUByte
import
kotlinx.io.core.writeUByte
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.utils.io.encryptAndWrite
import
net.mamoe.mirai.utils.io.encryptAndWrite
import
net.mamoe.mirai.utils.io.writeHex
import
net.mamoe.mirai.utils.io.writeHex
...
@@ -15,11 +16,11 @@ import net.mamoe.mirai.utils.io.writeQQ
...
@@ -15,11 +16,11 @@ import net.mamoe.mirai.utils.io.writeQQ
* @author Him188moe
* @author Him188moe
*/
*/
@AnnotatedId
(
KnownPacketId
.
ACCOUNT_INFO
)
@AnnotatedId
(
KnownPacketId
.
ACCOUNT_INFO
)
object
RequestAccountInfoPacket
:
OutgoingPacketBuilder
{
object
RequestAccountInfoPacket
:
SessionPacketFactory
<
RequestAccountInfoPacket
.
Response
>()
{
operator
fun
invoke
(
operator
fun
invoke
(
qq
:
UInt
,
qq
:
UInt
,
sessionKey
:
ByteArra
y
sessionKey
:
SessionKe
y
)
=
buildOutgoingPacket
{
)
:
OutgoingPacket
=
buildOutgoingPacket
{
writeQQ
(
qq
)
writeQQ
(
qq
)
writeHex
(
TIMProtocol
.
fixVer2
)
writeHex
(
TIMProtocol
.
fixVer2
)
encryptAndWrite
(
sessionKey
)
{
encryptAndWrite
(
sessionKey
)
{
...
@@ -29,10 +30,11 @@ object RequestAccountInfoPacket : OutgoingPacketBuilder {
...
@@ -29,10 +30,11 @@ object RequestAccountInfoPacket : OutgoingPacketBuilder {
}
}
}
}
@AnnotatedId
(
KnownPacketId
.
ACCOUNT_INFO
)
object
Response
:
Packet
{
class
Response
(
input
:
ByteReadPacket
)
:
ResponsePacket
(
input
)
{
//等级
//等级
//升级剩余活跃天数
//升级剩余活跃天数
//ignored
//ignored
}
}
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
Response
=
Response
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Heartbeat.kt
View file @
bd9cf3bf
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
package
net.mamoe.mirai.network.protocol.tim.packet
package
net.mamoe.mirai.network.protocol.tim.packet
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.ByteReadPacket
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.utils.io.encryptAndWrite
import
net.mamoe.mirai.utils.io.encryptAndWrite
import
net.mamoe.mirai.utils.io.writeHex
import
net.mamoe.mirai.utils.io.writeHex
...
@@ -10,10 +11,10 @@ import net.mamoe.mirai.utils.io.writeQQ
...
@@ -10,10 +11,10 @@ import net.mamoe.mirai.utils.io.writeQQ
@NoLog
@NoLog
@AnnotatedId
(
KnownPacketId
.
HEARTBEAT
)
@AnnotatedId
(
KnownPacketId
.
HEARTBEAT
)
object
HeartbeatPacket
:
OutgoingPacketBuilder
{
object
HeartbeatPacket
:
SessionPacketFactory
<
HeartbeatPacketResponse
>()
{
operator
fun
invoke
(
operator
fun
invoke
(
bot
:
UInt
,
bot
:
UInt
,
sessionKey
:
ByteArra
y
sessionKey
:
SessionKe
y
):
OutgoingPacket
=
buildOutgoingPacket
{
):
OutgoingPacket
=
buildOutgoingPacket
{
writeQQ
(
bot
)
writeQQ
(
bot
)
writeHex
(
TIMProtocol
.
fixVer
)
writeHex
(
TIMProtocol
.
fixVer
)
...
@@ -22,7 +23,10 @@ object HeartbeatPacket : OutgoingPacketBuilder {
...
@@ -22,7 +23,10 @@ object HeartbeatPacket : OutgoingPacketBuilder {
}
}
}
}
@NoLog
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
HeartbeatPacketResponse
=
@AnnotatedId
(
KnownPacketId
.
HEARTBEAT
)
HeartbeatPacketResponse
class
Response
(
input
:
ByteReadPacket
)
:
ResponsePacket
(
input
)
}
}
\ No newline at end of file
@NoLog
@AnnotatedId
(
KnownPacketId
.
HEARTBEAT
)
object
HeartbeatPacketResponse
:
Packet
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/OutgoingPacket.kt
View file @
bd9cf3bf
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
,
"EXPERIMENTAL_UNSIGNED_LITERALS"
)
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
,
"EXPERIMENTAL_UNSIGNED_LITERALS"
,
"unused"
,
"MemberVisibilityCanBePrivate"
)
package
net.mamoe.mirai.network.protocol.tim.packet
package
net.mamoe.mirai.network.protocol.tim.packet
import
kotlinx.atomicfu.atomic
import
kotlinx.io.core.BytePacketBuilder
import
kotlinx.io.core.BytePacketBuilder
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.use
import
kotlinx.io.core.use
...
@@ -18,8 +17,8 @@ import kotlin.jvm.JvmOverloads
...
@@ -18,8 +17,8 @@ import kotlin.jvm.JvmOverloads
*/
*/
class
OutgoingPacket
(
class
OutgoingPacket
(
name
:
String
?,
name
:
String
?,
override
val
packetId
:
PacketId
,
val
packetId
:
PacketId
,
override
val
sequenceId
:
UShort
,
val
sequenceId
:
UShort
,
internal
val
delegate
:
ByteReadPacket
internal
val
delegate
:
ByteReadPacket
)
:
Packet
{
)
:
Packet
{
private
val
name
:
String
by
lazy
{
private
val
name
:
String
by
lazy
{
...
@@ -31,28 +30,15 @@ class OutgoingPacket(
...
@@ -31,28 +30,15 @@ class OutgoingPacket(
constructor
(
annotation
:
AnnotatedId
,
sequenceId
:
UShort
,
delegate
:
ByteReadPacket
)
:
constructor
(
annotation
:
AnnotatedId
,
sequenceId
:
UShort
,
delegate
:
ByteReadPacket
)
:
this
(
annotation
.
toString
(),
annotation
.
id
,
sequenceId
,
delegate
)
this
(
annotation
.
toString
(),
annotation
.
id
,
sequenceId
,
delegate
)
override
fun
toString
():
String
=
packetToString
(
name
)
override
fun
toString
():
String
=
packetToString
(
packetId
.
value
,
sequenceId
,
name
)
}
}
/**
/**
*
发给服务器的数据包的构建器
.
*
登录完成建立 session 之后发出的包
.
*
应由一个 `object` 实现, 且实现 `operator fun invoke`
*
均使用 sessionKey 加密
*/
*/
interface
OutgoingPacketBuilder
{
abstract
class
SessionPacketFactory
<
out
TPacket
:
Packet
>
:
PacketFactory
<
TPacket
,
SessionKey
>(
SessionKey
)
{
/**
final
override
fun
decrypt
(
input
:
ByteReadPacket
,
decrypter
:
SessionKey
):
ByteReadPacket
=
decrypter
.
decrypt
(
input
)
* 2 Ubyte.
* 默认为读取注解 [AnnotatedId]
*/
val
annotatedId
:
AnnotatedId
get
()
=
(
this
::
class
.
annotations
.
firstOrNull
{
it
is
AnnotatedId
}
as
?
AnnotatedId
)
?:
error
(
"Annotation AnnotatedId not found"
)
companion
object
{
private
val
sequenceIdInternal
=
atomic
(
1
)
@PublishedApi
internal
fun
atomicNextSequenceId
():
UShort
=
sequenceIdInternal
.
getAndIncrement
().
toUShort
()
}
}
}
/**
/**
...
@@ -61,10 +47,10 @@ interface OutgoingPacketBuilder {
...
@@ -61,10 +47,10 @@ interface OutgoingPacketBuilder {
* 若不提供参数 [id], 则会通过注解 [AnnotatedId] 获取 id.
* 若不提供参数 [id], 则会通过注解 [AnnotatedId] 获取 id.
*/
*/
@JvmOverloads
@JvmOverloads
fun
OutgoingPacketBuilder
.
buildOutgoingPacket
(
fun
PacketFactory
<*,
*>
.
buildOutgoingPacket
(
name
:
String
?
=
null
,
name
:
String
?
=
null
,
id
:
PacketId
=
this
.
annotatedId
.
id
,
id
:
PacketId
=
this
.
id
,
sequenceId
:
UShort
=
OutgoingPacketBuilder
.
atomicNextSequenceId
(),
sequenceId
:
UShort
=
PacketFactory
.
atomicNextSequenceId
(),
headerSizeHint
:
Int
=
0
,
headerSizeHint
:
Int
=
0
,
block
:
BytePacketBuilder
.()
->
Unit
block
:
BytePacketBuilder
.()
->
Unit
):
OutgoingPacket
{
):
OutgoingPacket
{
...
@@ -88,12 +74,12 @@ fun OutgoingPacketBuilder.buildOutgoingPacket(
...
@@ -88,12 +74,12 @@ fun OutgoingPacketBuilder.buildOutgoingPacket(
* 若不提供参数 [id], 则会通过注解 [AnnotatedId] 获取 id.
* 若不提供参数 [id], 则会通过注解 [AnnotatedId] 获取 id.
*/
*/
@JvmOverloads
@JvmOverloads
fun
OutgoingPacketBuilder
.
buildSessionPacket
(
fun
PacketFactory
<*,
*>
.
buildSessionPacket
(
bot
:
UInt
,
bot
:
UInt
,
sessionKey
:
ByteArra
y
,
sessionKey
:
SessionKe
y
,
name
:
String
?
=
null
,
name
:
String
?
=
null
,
id
:
PacketId
=
this
.
annotatedId
.
id
,
id
:
PacketId
=
this
.
id
,
sequenceId
:
UShort
=
OutgoingPacketBuilder
.
atomicNextSequenceId
(),
sequenceId
:
UShort
=
PacketFactory
.
atomicNextSequenceId
(),
headerSizeHint
:
Int
=
0
,
headerSizeHint
:
Int
=
0
,
block
:
BytePacketBuilder
.()
->
Unit
block
:
BytePacketBuilder
.()
->
Unit
):
OutgoingPacket
=
buildOutgoingPacket
(
name
,
id
,
sequenceId
,
headerSizeHint
)
{
):
OutgoingPacket
=
buildOutgoingPacket
(
name
,
id
,
sequenceId
,
headerSizeHint
)
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/OutgoingRawPacket.kt
deleted
100644 → 0
View file @
6f498554
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
)
package
net.mamoe.mirai.network.protocol.tim.packet
import
kotlinx.io.core.writeFully
import
net.mamoe.mirai.utils.io.encryptAndWrite
import
net.mamoe.mirai.utils.io.writeQQ
object
OutgoingRawPacket
:
OutgoingPacketBuilder
{
operator
fun
invoke
(
id
:
PacketId
,
bot
:
UInt
,
version
:
ByteArray
,
sessionKey
:
ByteArray
,
data
:
ByteArray
):
OutgoingPacket
=
buildOutgoingPacket
(
id
=
id
)
{
writeQQ
(
bot
)
writeFully
(
version
)
encryptAndWrite
(
sessionKey
)
{
writeFully
(
data
)
}
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Packet.kt
View file @
bd9cf3bf
This diff is collapsed.
Click to expand it.
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Response.kt
deleted
100644 → 0
View file @
6f498554
package
net.mamoe.mirai.network.protocol.tim.packet
import
kotlin.reflect.KClass
/**
* 标记一个 [OutgoingPacket] 的服务器回复包.
* 在这个包发送时将会记录回复包信息.
* 收到回复包时将解密为指定的包
*
*
* // TODO: 2019/10/27 暂未实现. 计划中
*/
@Retention
(
AnnotationRetention
.
RUNTIME
)
@Target
(
AnnotationTarget
.
CLASS
)
annotation
class
Response
(
val
responseClass
:
KClass
<
out
ResponsePacket
>
)
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/ResponsePacket.kt
deleted
100644 → 0
View file @
6f498554
package
net.mamoe.mirai.network.protocol.tim.packet
import
kotlinx.io.core.ByteReadPacket
/**
* 返回包.
* 在登录完成后, 任意一个 [OutgoingPacket] 发送后服务器都会给返回包. 则一个 [OutgoingPacket] 一定对应一个 [ResponsePacket]
* 它们都使用 sessionKey 解密.
* 它们都必须有一个公开的仅有一个 [ByteReadPacket] 参数的构造器.
*
* 注意: 需要指定 ID, 通过 [AnnotatedId].
*/
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
)
}
}
}
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/ServerPacket.kt
View file @
bd9cf3bf
...
@@ -3,78 +3,30 @@
...
@@ -3,78 +3,30 @@
package
net.mamoe.mirai.network.protocol.tim.packet
package
net.mamoe.mirai.network.protocol.tim.packet
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.Closeable
import
kotlinx.io.core.IoBuffer
import
kotlinx.io.core.IoBuffer
import
kotlinx.io.core.readBytes
import
kotlinx.io.pool.useInstance
import
kotlinx.io.pool.useInstance
import
net.mamoe.mirai.utils.decryptBy
import
net.mamoe.mirai.utils.decryptBy
import
net.mamoe.mirai.utils.io.ByteArrayPool
import
net.mamoe.mirai.utils.io.ByteArrayPool
import
net.mamoe.mirai.utils.io.hexToBytes
import
net.mamoe.mirai.utils.io.hexToBytes
import
net.mamoe.mirai.utils.io.parseServerPacket
import
net.mamoe.mirai.utils.io.toReadPacket
import
kotlin.properties.Delegates
/**
fun
ByteReadPacket
.
decryptBy
(
key
:
ByteArray
):
ByteReadPacket
=
decryptAsByteArray
(
key
)
{
data
->
ByteReadPacket
(
data
,
0
)
}
* 来自服务器的数据包
fun
ByteReadPacket
.
decryptBy
(
key
:
IoBuffer
):
ByteReadPacket
=
decryptAsByteArray
(
key
)
{
data
->
ByteReadPacket
(
data
,
0
)
}
*
fun
ByteReadPacket
.
decryptBy
(
keyHex
:
String
):
ByteReadPacket
=
decryptBy
(
keyHex
.
hexToBytes
())
* @see parseServerPacket 解析包种类
*/
abstract
class
ServerPacket
(
val
input
:
ByteReadPacket
)
:
Packet
,
Closeable
{
override
val
packetId
:
PacketId
by
lazy
{
(
this
::
class
.
annotations
.
firstOrNull
{
it
is
AnnotatedId
}
as
?
AnnotatedId
)
?.
id
?:
error
(
"Annotation AnnotatedId not found"
)
}
override
var
sequenceId
:
UShort
by
Delegates
.
notNull
()
inline
fun
<
R
>
ByteReadPacket
.
decryptAsByteArray
(
key
:
ByteArray
,
consumer
:
(
ByteArray
)
->
R
):
R
=
open
fun
decode
()
{
}
override
fun
close
()
=
this
.
input
.
close
()
override
fun
toString
():
String
=
this
.
packetToString
()
fun
<
S
:
ServerPacket
>
S
.
applySequence
()
=
this
.
applySequence
(
this
@ServerPacket
.
sequenceId
)
}
fun
<
S
:
ServerPacket
>
S
.
applySequence
(
sequenceId
:
UShort
):
S
{
this
.
sequenceId
=
sequenceId
return
this
}
fun
ServerPacket
.
decryptBy
(
key
:
ByteArray
):
ByteReadPacket
=
decryptAsByteArray
(
key
)
{
data
->
ByteReadPacket
(
data
,
0
)
}
fun
ServerPacket
.
decryptBy
(
key
:
IoBuffer
):
ByteReadPacket
=
decryptAsByteArray
(
key
)
{
data
->
ByteReadPacket
(
data
,
0
)
}
fun
ServerPacket
.
decryptBy
(
keyHex
:
String
):
ByteReadPacket
=
this
.
decryptBy
(
keyHex
.
hexToBytes
())
fun
ServerPacket
.
decryptBy
(
key1
:
ByteArray
,
key2
:
ByteArray
):
ByteReadPacket
=
this
.
decryptAsByteArray
(
key1
)
{
data
->
data
.
decryptBy
(
key2
).
toReadPacket
()
}
fun
ServerPacket
.
decryptBy
(
key1
:
String
,
key2
:
ByteArray
):
ByteReadPacket
=
this
.
decryptBy
(
key1
.
hexToBytes
(),
key2
)
fun
ServerPacket
.
decryptBy
(
key1
:
String
,
key2
:
IoBuffer
):
ByteReadPacket
=
this
.
decryptBy
(
key1
.
hexToBytes
(),
key2
.
readBytes
())
fun
ServerPacket
.
decryptBy
(
key1
:
ByteArray
,
key2
:
String
):
ByteReadPacket
=
this
.
decryptBy
(
key1
,
key2
.
hexToBytes
())
fun
ServerPacket
.
decryptBy
(
keyHex1
:
String
,
keyHex2
:
String
):
ByteReadPacket
=
this
.
decryptBy
(
keyHex1
.
hexToBytes
(),
keyHex2
.
hexToBytes
())
inline
fun
<
R
>
ServerPacket
.
decryptAsByteArray
(
key
:
ByteArray
,
consumer
:
(
ByteArray
)
->
R
):
R
=
ByteArrayPool
.
useInstance
{
ByteArrayPool
.
useInstance
{
val
length
=
input
.
remaining
.
toInt
()
-
1
val
length
=
remaining
.
toInt
()
input
.
readFully
(
it
,
0
,
length
)
readFully
(
it
,
0
,
length
)
consumer
(
it
.
decryptBy
(
key
,
length
))
consumer
(
it
.
decryptBy
(
key
,
length
))
}.
also
{
input
.
close
()
}
}.
also
{
close
()
}
inline
fun
<
R
>
Server
Packet
.
decryptAsByteArray
(
keyHex
:
String
,
consumer
:
(
ByteArray
)
->
R
):
R
=
inline
fun
<
R
>
ByteRead
Packet
.
decryptAsByteArray
(
keyHex
:
String
,
consumer
:
(
ByteArray
)
->
R
):
R
=
this
.
decryptAsByteArray
(
keyHex
.
hexToBytes
(),
consumer
)
this
.
decryptAsByteArray
(
keyHex
.
hexToBytes
(),
consumer
)
inline
fun
<
R
>
Server
Packet
.
decryptAsByteArray
(
key
:
IoBuffer
,
consumer
:
(
ByteArray
)
->
R
):
R
=
inline
fun
<
R
>
ByteRead
Packet
.
decryptAsByteArray
(
key
:
IoBuffer
,
consumer
:
(
ByteArray
)
->
R
):
R
=
ByteArrayPool
.
useInstance
{
ByteArrayPool
.
useInstance
{
val
length
=
input
.
remaining
.
toInt
()
-
1
val
length
=
remaining
.
toInt
()
input
.
readFully
(
it
,
0
,
length
)
readFully
(
it
,
0
,
length
)
consumer
(
it
.
decryptBy
(
key
,
length
))
consumer
(
it
.
decryptBy
(
key
,
length
))
}.
also
{
input
.
close
()
}
}.
also
{
close
()
}
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UnknownServerPacket.kt
View file @
bd9cf3bf
...
@@ -2,31 +2,6 @@
...
@@ -2,31 +2,6 @@
package
net.mamoe.mirai.network.protocol.tim.packet
package
net.mamoe.mirai.network.protocol.tim.packet
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.readBytes
import
net.mamoe.mirai.utils.MiraiLogger
import
net.mamoe.mirai.utils.io.toUHexString
class
UnknownServerPacket
(
input
:
ByteReadPacket
,
override
val
packetId
:
PacketId
,
override
var
sequenceId
:
UShort
)
:
ServerPacket
(
input
)
{
override
fun
decode
()
{
val
raw
=
this
.
input
.
readBytes
()
MiraiLogger
.
debug
(
"UnknownServerPacket data: "
+
raw
.
toUHexString
())
}
class
Encrypted
(
input
:
ByteReadPacket
,
override
val
packetId
:
PacketId
,
override
var
sequenceId
:
UShort
)
:
ServerPacket
(
input
)
{
fun
decrypt
(
sessionKey
:
ByteArray
):
UnknownServerPacket
=
UnknownServerPacket
(
this
.
decryptBy
(
sessionKey
),
this
.
packetId
,
this
.
sequenceId
)
}
}
/*
/*
ID: 00 17
ID: 00 17
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/AddContact.kt
View file @
bd9cf3bf
...
@@ -4,66 +4,108 @@ package net.mamoe.mirai.network.protocol.tim.packet.action
...
@@ -4,66 +4,108 @@ package net.mamoe.mirai.network.protocol.tim.packet.action
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.discardExact
import
kotlinx.io.core.discardExact
import
kotlinx.io.core.readUInt
import
kotlinx.io.core.readUShort
import
kotlinx.io.core.readUShort
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.utils.io.encryptAndWrite
import
net.mamoe.mirai.network.protocol.tim.packet.action.CanAddFriendResponse.State
import
net.mamoe.mirai.utils.io.writeHex
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.io.writeQQ
import
kotlin.properties.Delegates
// 01BC 曾用名查询. 查到的是这个人的
// 发送 00 00
// 3E 03 3F A2 //bot
// 59 17 3E 05 //目标
//
// 接受: 00 00 00 03
// [00 00 00 0C] E6 A5 BC E4 B8 8A E5 B0 8F E7 99 BD
// [00 00 00 10] 68 69 6D 31 38 38 E7 9A 84 E5 B0 8F 64 69 63 6B
// [00 00 00 0F] E4 B8 B6 E6 9A 97 E8 A3 94 E5 89 91 E9 AD 94
/**
/**
*
向服务器检查是否可添加某人为好友
*
查询某人与机器人账号有关的曾用名 (备注).
*
*
* @author Him188moe
* 曾用名可能是:
* - 昵称
* - 共同群内的群名片
*/
*/
@Response
(
CanAddFriendPacket
.
Response
::
class
)
@PacketVersion
(
date
=
"2019.11.02"
,
timVersion
=
"2.3.2.21173"
)
@AnnotatedId
(
KnownPacketId
.
CAN_ADD_FRIEND
)
object
QueryPreviousNamePacket
:
SessionPacketFactory
<
QueryPreviousNameResponse
>()
{
object
CanAddFriendPacket
:
OutgoingPacketBuilder
{
operator
fun
invoke
(
operator
fun
invoke
(
bot
:
UInt
,
bot
:
UInt
,
qq
:
UInt
,
sessionKey
:
SessionKey
,
sessionKey
:
ByteArray
target
:
UInt
):
OutgoingPacket
=
buildOutgoingPacket
{
):
OutgoingPacket
=
buildSessionPacket
(
bot
,
sessionKey
)
{
writeZero
(
2
)
writeQQ
(
bot
)
writeQQ
(
bot
)
writeHex
(
TIMProtocol
.
fixVer2
)
writeQQ
(
target
)
encryptAndWrite
(
sessionKey
)
{
writeQQ
(
qq
)
}
}
}
@AnnotatedId
(
KnownPacketId
.
CAN_ADD_FRIEND
)
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
QueryPreviousNameResponse
=
class
Response
(
input
:
ByteReadPacket
)
:
ResponsePacket
(
input
)
{
QueryPreviousNameResponse
().
apply
{
lateinit
var
state
:
State
names
=
Array
(
readUInt
().
toInt
())
{
discardExact
(
2
)
enum
class
State
{
readUShortLVString
()
/**
}
* 已经添加
*/
ALREADY_ADDED
,
/**
* 需要验证信息
*/
REQUIRE_VERIFICATION
,
/**
* 不需要验证信息
*/
NOT_REQUIRE_VERIFICATION
,
/**
* 对方拒绝添加
*/
FAILED
,
}
}
}
class
QueryPreviousNameResponse
:
Packet
{
lateinit
var
names
:
Array
<
String
>
}
// 需要验证消息
// 0065 发送 03 07 57 37 E8
// 0065 接受 03 07 57 37 E8 10 40 00 00 10 14 20 00 00 00 00 00 00 00 01 00 00 00 00 00
/**
* 添加好友结果
*
* @author Him188moe
*/
enum
class
AddFriendResult
{
/**
* 等待对方处理
*/
WAITING_FOR_AGREEMENT
,
/**
* 和对方已经是好友了
*/
ALREADY_ADDED
,
/**
* 对方设置为不添加好友等
*/
FAILED
,
}
override
fun
decode
()
=
with
(
input
)
{
/**
//需要验证信息 00 23 24 8B 00 01
* 向服务器检查是否可添加某人为好友
*
* @author Him188moe
*/
@AnnotatedId
(
KnownPacketId
.
CAN_ADD_FRIEND
)
object
CanAddFriendPacket
:
SessionPacketFactory
<
CanAddFriendResponse
>()
{
operator
fun
invoke
(
bot
:
UInt
,
qq
:
UInt
,
sessionKey
:
SessionKey
):
OutgoingPacket
=
buildSessionPacket
(
bot
,
sessionKey
)
{
writeQQ
(
qq
)
}
if
(
input
.
remaining
>
20
)
{
//todo check
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
CanAddFriendResponse
=
CanAddFriendResponse
().
apply
{
if
(
remaining
>
20
)
{
//todo check
state
=
State
.
ALREADY_ADDED
state
=
State
.
ALREADY_ADDED
return
return
@
apply
}
}
discardExact
(
4
)
//对方qq号
qq
=
readUInt
()
state
=
when
(
val
state
=
readUShort
().
toUInt
())
{
state
=
when
(
val
state
=
readUShort
().
toUInt
())
{
0
x00u
->
State
.
NOT_REQUIRE_VERIFICATION
0
x00u
->
State
.
NOT_REQUIRE_VERIFICATION
0
x01u
->
State
.
REQUIRE_VERIFICATION
//需要验证信息
0
x01u
->
State
.
REQUIRE_VERIFICATION
//需要验证信息
...
@@ -74,18 +116,43 @@ object CanAddFriendPacket : OutgoingPacketBuilder {
...
@@ -74,18 +116,43 @@ object CanAddFriendPacket : OutgoingPacketBuilder {
else
->
throw
IllegalStateException
(
state
.
toString
())
else
->
throw
IllegalStateException
(
state
.
toString
())
}
}
}
}
}
class
CanAddFriendResponse
:
Packet
{
var
qq
:
UInt
by
Delegates
.
notNull
()
lateinit
var
state
:
State
enum
class
State
{
/**
* 已经添加
*/
ALREADY_ADDED
,
/**
* 需要验证信息
*/
REQUIRE_VERIFICATION
,
/**
* 不需要验证信息
*/
NOT_REQUIRE_VERIFICATION
,
/**
* 对方拒绝添加
*/
FAILED
,
}
}
}
}
/**
/**
* 请求添加好友
* 请求添加好友
*/
*/
@AnnotatedId
(
KnownPacketId
.
CAN_ADD_FRIEND
)
@AnnotatedId
(
KnownPacketId
.
CAN_ADD_FRIEND
)
object
AddFriendPacket
:
OutgoingPacketBuilder
{
object
AddFriendPacket
:
SessionPacketFactory
<
AddFriendPacket
.
AddFriendResponse
>()
{
operator
fun
invoke
(
operator
fun
invoke
(
bot
:
UInt
,
bot
:
UInt
,
qq
:
UInt
,
qq
:
UInt
,
sessionKey
:
ByteArra
y
sessionKey
:
SessionKe
y
):
OutgoingPacket
=
buildOutgoingPacket
{
):
OutgoingPacket
=
buildOutgoingPacket
{
writeQQ
(
bot
)
writeQQ
(
bot
)
writeHex
(
TIMProtocol
.
fixVer2
)
writeHex
(
TIMProtocol
.
fixVer2
)
...
@@ -94,28 +161,11 @@ object AddFriendPacket : OutgoingPacketBuilder {
...
@@ -94,28 +161,11 @@ object AddFriendPacket : OutgoingPacketBuilder {
writeQQ
(
qq
)
writeQQ
(
qq
)
}
}
}
}
}
/**
class
AddFriendResponse
:
Packet
* 添加好友/群的回复
*/
abstract
class
ServerAddContactResponsePacket
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
class
Raw
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
override
fun
decode
()
{
}
fun
distribute
():
ServerAddContactResponsePacket
{
TODO
()
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
AddFriendResponse
{
}
TODO
()
class
Encrypted
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
fun
decrypt
(
sessionKey
:
ByteArray
):
Raw
=
Raw
(
decryptBy
(
sessionKey
))
}
}
}
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/AddFriendResult.kt
deleted
100644 → 0
View file @
6f498554
package
net.mamoe.mirai.network.protocol.tim.packet.action
/**
* 添加好友结果
*
* @author Him188moe
*/
enum
class
AddFriendResult
{
/**
* 等待对方处理
*/
WAITING_FOR_AGREEMENT
,
/**
* 和对方已经是好友了
*/
ALREADY_ADDED
,
/**
* 对方设置为不添加好友等
*/
FAILED
,
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/Profile.kt
View file @
bd9cf3bf
This diff is collapsed.
Click to expand it.
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/SendFriendMessagePacket.kt
View file @
bd9cf3bf
...
@@ -5,6 +5,7 @@ package net.mamoe.mirai.network.protocol.tim.packet.action
...
@@ -5,6 +5,7 @@ package net.mamoe.mirai.network.protocol.tim.packet.action
import
kotlinx.io.core.*
import
kotlinx.io.core.*
import
net.mamoe.mirai.message.MessageChain
import
net.mamoe.mirai.message.MessageChain
import
net.mamoe.mirai.message.internal.toPacket
import
net.mamoe.mirai.message.internal.toPacket
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.io.*
...
@@ -12,62 +13,58 @@ import net.mamoe.mirai.utils.md5
...
@@ -12,62 +13,58 @@ import net.mamoe.mirai.utils.md5
@AnnotatedId
(
KnownPacketId
.
SEND_FRIEND_MESSAGE
)
@AnnotatedId
(
KnownPacketId
.
SEND_FRIEND_MESSAGE
)
@PacketVersion
(
date
=
"2019.10.19"
,
timVersion
=
"2.3.2.21173"
)
@PacketVersion
(
date
=
"2019.10.19"
,
timVersion
=
"2.3.2.21173"
)
object
SendFriendMessagePacket
:
OutgoingPacketBuilder
{
object
SendFriendMessagePacket
:
SessionPacketFactory
<
SendFriendMessagePacket
.
Response
>()
{
operator
fun
invoke
(
operator
fun
invoke
(
botQQ
:
UInt
,
botQQ
:
UInt
,
targetQQ
:
UInt
,
targetQQ
:
UInt
,
sessionKey
:
ByteArra
y
,
sessionKey
:
SessionKe
y
,
message
:
MessageChain
message
:
MessageChain
):
OutgoingPacket
=
build
OutgoingPacket
{
):
OutgoingPacket
=
build
SessionPacket
(
botQQ
,
sessionKey
)
{
writeQQ
(
botQQ
)
writeQQ
(
botQQ
)
writeHex
(
TIMProtocol
.
version0x02
)
writeQQ
(
targetQQ
)
writeHex
(
"00 00 00 08 00 01 00 04 00 00 00 00"
)
encryptAndWrite
(
sessionKey
)
{
writeHex
(
"38 03"
)
writeQQ
(
botQQ
)
writeQQ
(
botQQ
)
writeQQ
(
targetQQ
)
writeQQ
(
targetQQ
)
writeHex
(
"00 00 00 08 00 01 00 04 00 00 00 00"
)
writeFully
(
md5
(
buildPacket
{
writeQQ
(
targetQQ
);
writeFully
(
sessionKey
)
}.
readBytes
()))
writeHex
(
"38 03"
)
writeHex
(
"00 0B"
)
writeQQ
(
botQQ
)
writeRandom
(
2
)
writeQQ
(
targetQQ
)
writeTime
()
writeFully
(
md5
(
buildPacket
{
writeQQ
(
targetQQ
);
writeFully
(
sessionKey
)
}.
readBytes
()))
writeHex
(
writeHex
(
"00 0B"
)
"01 1D"
+
writeRandom
(
2
)
" 00 00 00 00"
writeTime
()
)
writeHex
(
"01 1D"
+
" 00 00 00 00"
)
//消息过多要分包发送
//消息过多要分包发送
//如果只有一个
//如果只有一个
writeByte
(
0
x01
)
writeByte
(
0
x01
)
writeByte
(
0
)
//第几个包
writeByte
(
0
)
//第几个包
writeUByte
(
0
x00u
)
writeUByte
(
0
x00u
)
//如果大于一个,
//如果大于一个,
//writeByte(0x02)//数量
//writeByte(0x02)//数量
//writeByte(0)//第几个包
//writeByte(0)//第几个包
//writeByte(0x91)//why?
//writeByte(0x91)//why?
writeHex
(
"00 01 4D 53 47 00 00 00 00 00"
)
writeHex
(
"00 01 4D 53 47 00 00 00 00 00"
)
writeTime
()
writeTime
()
writeRandom
(
4
)
writeRandom
(
4
)
writeHex
(
"00 00 00 00 0C 00 86"
)
writeHex
(
"00 00 00 00 0C 00 86"
)
writeHex
(
TIMProtocol
.
messageConstNewest
)
writeHex
(
TIMProtocol
.
messageConstNewest
)
writeZero
(
2
)
writeZero
(
2
)
writePacket
(
message
.
toPacket
(
false
))
writePacket
(
message
.
toPacket
(
false
))
/*
/*
//Plain text
//Plain text
val bytes = event.toPacket()
val bytes = event.toPacket()
it.writeByte(0x01)
it.writeByte(0x01)
it.writeShort(bytes.size + 3)
it.writeShort(bytes.size + 3)
it.writeByte(0x01)
it.writeByte(0x01)
it.writeShort(bytes.size)
it.writeShort(bytes.size)
it.write(bytes)*/
it.write(bytes)*/
}
}
}
@AnnotatedId
(
KnownPacketId
.
SEND_FRIEND_MESSAGE
)
object
Response
:
Packet
class
Response
(
input
:
ByteReadPacket
)
:
ResponsePacket
(
input
)
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
Response
=
Response
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/SendGroupMessagePacket.kt
View file @
bd9cf3bf
...
@@ -6,17 +6,16 @@ import kotlinx.io.core.ByteReadPacket
...
@@ -6,17 +6,16 @@ import kotlinx.io.core.ByteReadPacket
import
net.mamoe.mirai.contact.GroupInternalId
import
net.mamoe.mirai.contact.GroupInternalId
import
net.mamoe.mirai.message.MessageChain
import
net.mamoe.mirai.message.MessageChain
import
net.mamoe.mirai.message.internal.toPacket
import
net.mamoe.mirai.message.internal.toPacket
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.io.*
object
SendGroupMessagePacket
:
SessionPacketFactory
<
SendGroupMessagePacket
.
Response
>()
{
@AnnotatedId
(
KnownPacketId
.
SEND_GROUP_MESSAGE
)
object
SendGroupMessagePacket
:
OutgoingPacketBuilder
{
operator
fun
invoke
(
operator
fun
invoke
(
botQQ
:
UInt
,
botQQ
:
UInt
,
groupInternalId
:
GroupInternalId
,
groupInternalId
:
GroupInternalId
,
sessionKey
:
ByteArra
y
,
sessionKey
:
SessionKe
y
,
message
:
MessageChain
message
:
MessageChain
):
OutgoingPacket
=
buildOutgoingPacket
{
):
OutgoingPacket
=
buildOutgoingPacket
{
writeQQ
(
botQQ
)
writeQQ
(
botQQ
)
...
@@ -46,6 +45,7 @@ object SendGroupMessagePacket : OutgoingPacketBuilder {
...
@@ -46,6 +45,7 @@ object SendGroupMessagePacket : OutgoingPacketBuilder {
}
}
}
}
@AnnotatedId
(
KnownPacketId
.
SEND_GROUP_MESSAGE
)
object
Response
:
Packet
class
Response
(
input
:
ByteReadPacket
)
:
ResponsePacket
(
input
)
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
Response
=
Response
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/action/UploadImage.kt
View file @
bd9cf3bf
...
@@ -12,7 +12,7 @@ import kotlinx.io.core.*
...
@@ -12,7 +12,7 @@ import kotlinx.io.core.*
import
net.mamoe.mirai.contact.*
import
net.mamoe.mirai.contact.*
import
net.mamoe.mirai.event.events.FriendImageIdObtainedEvent
import
net.mamoe.mirai.event.events.FriendImageIdObtainedEvent
import
net.mamoe.mirai.message.ImageId
import
net.mamoe.mirai.message.ImageId
import
net.mamoe.mirai.network.
protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.
BotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.network.protocol.tim.packet.action.FriendImageIdRequestPacket.Response.State.*
import
net.mamoe.mirai.network.protocol.tim.packet.action.FriendImageIdRequestPacket.Response.State.*
import
net.mamoe.mirai.network.qqAccount
import
net.mamoe.mirai.network.qqAccount
...
@@ -126,18 +126,19 @@ internal suspend inline fun HttpClient.postImage(
...
@@ -126,18 +126,19 @@ internal suspend inline fun HttpClient.postImage(
imageInput
.
close
()
imageInput
.
close
()
}
}
/*
/**
/**
* 似乎没有必要. 服务器的返回永远都是 01 00 00 00 02 00 00
* 似乎没有必要. 服务器的返回永远都是 01 00 00 00 02 00 00
*/
*/
@Deprecated("Useless packet")
@Deprecated("Useless packet")
@AnnotatedId(KnownPacketId.SUBMIT_IMAGE_FILE_NAME)
@AnnotatedId(KnownPacketId.SUBMIT_IMAGE_FILE_NAME)
@PacketVersion(date = "2019.10.26", timVersion = "2.3.2.21173")
@PacketVersion(date = "2019.10.26", timVersion = "2.3.2.21173")
object
SubmitImageFilenamePacket
:
OutgoingPacketBuilder
{
object SubmitImageFilenamePacket :
PacketFactory
{
operator fun invoke(
operator fun invoke(
bot: UInt,
bot: UInt,
target: UInt,
target: UInt,
filename: String,
filename: String,
sessionKey
:
ByteArra
y
sessionKey:
SessionKe
y
): OutgoingPacket = buildOutgoingPacket {
): OutgoingPacket = buildOutgoingPacket {
writeQQ(bot)
writeQQ(bot)
writeHex(TIMProtocol.fixVer2)//?
writeHex(TIMProtocol.fixVer2)//?
...
@@ -166,9 +167,8 @@ object SubmitImageFilenamePacket : OutgoingPacketBuilder {
...
@@ -166,9 +167,8 @@ object SubmitImageFilenamePacket : OutgoingPacketBuilder {
//解密body=01 3E 03 3F A2 7C BC D3 C1 00 00 27 1C 00 0A 00 01 00 01 00 30 55 73 65 72 44 61 74 61 43 75 73 74 6F 6D 46 61 63 65 3A 31 5C 29 37 42 53 4B 48 32 44 35 54 51 28 5A 35 7D 35 24 56 5D 32 35 49 4E 2E 6A 70 67 00 00 03 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 2F 02
//解密body=01 3E 03 3F A2 7C BC D3 C1 00 00 27 1C 00 0A 00 01 00 01 00 30 55 73 65 72 44 61 74 61 43 75 73 74 6F 6D 46 61 63 65 3A 31 5C 29 37 42 53 4B 48 32 44 35 54 51 28 5A 35 7D 35 24 56 5D 32 35 49 4E 2E 6A 70 67 00 00 03 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 2F 02
}
}
@AnnotatedId
(
KnownPacketId
.
SUBMIT_IMAGE_FILE_NAME
)
@PacketVersion(date = "2019.10.19", timVersion = "2.3.2.21173")
@PacketVersion(date = "2019.10.19", timVersion = "2.3.2.21173")
class
Response
(
input
:
ByteReadPacket
)
:
ResponsePacket
(
input
)
{
class Response {
override fun decode() = with(input) {
override fun decode() = with(input) {
require(readBytes().contentEquals(expecting))
require(readBytes().contentEquals(expecting))
}
}
...
@@ -177,7 +177,7 @@ object SubmitImageFilenamePacket : OutgoingPacketBuilder {
...
@@ -177,7 +177,7 @@ object SubmitImageFilenamePacket : OutgoingPacketBuilder {
private val expecting = byteArrayOf(0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00)
private val expecting = byteArrayOf(0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00)
}
}
}
}
}
}
*/
/**
/**
...
@@ -188,10 +188,10 @@ object SubmitImageFilenamePacket : OutgoingPacketBuilder {
...
@@ -188,10 +188,10 @@ object SubmitImageFilenamePacket : OutgoingPacketBuilder {
*/
*/
@AnnotatedId
(
KnownPacketId
.
FRIEND_IMAGE_ID
)
@AnnotatedId
(
KnownPacketId
.
FRIEND_IMAGE_ID
)
@PacketVersion
(
date
=
"2019.10.26"
,
timVersion
=
"2.3.2.21173"
)
@PacketVersion
(
date
=
"2019.10.26"
,
timVersion
=
"2.3.2.21173"
)
object
FriendImageIdRequestPacket
:
OutgoingPacketBuilder
{
object
FriendImageIdRequestPacket
:
SessionPacketFactory
<
FriendImageIdRequestPacket
.
Response
>()
{
operator
fun
invoke
(
operator
fun
invoke
(
bot
:
UInt
,
bot
:
UInt
,
sessionKey
:
ByteArra
y
,
sessionKey
:
SessionKe
y
,
target
:
UInt
,
target
:
UInt
,
image
:
ExternalImage
image
:
ExternalImage
)
=
buildOutgoingPacket
{
)
=
buildOutgoingPacket
{
...
@@ -256,9 +256,8 @@ object FriendImageIdRequestPacket : OutgoingPacketBuilder {
...
@@ -256,9 +256,8 @@ object FriendImageIdRequestPacket : OutgoingPacketBuilder {
}
}
@CorrespondingEvent
(
FriendImageIdObtainedEvent
::
class
)
@CorrespondingEvent
(
FriendImageIdObtainedEvent
::
class
)
@AnnotatedId
(
KnownPacketId
.
FRIEND_IMAGE_ID
)
@PacketVersion
(
date
=
"2019.11.1"
,
timVersion
=
"2.3.2.21173"
)
@PacketVersion
(
date
=
"2019.11.1"
,
timVersion
=
"2.3.2.21173"
)
class
Response
(
input
:
ByteReadPacket
)
:
ResponsePacket
(
input
)
{
class
Response
:
Packet
{
/**
/**
* 访问 HTTP API 时需要使用的一个 key. 128 位
* 访问 HTTP API 时需要使用的一个 key. 128 位
*/
*/
...
@@ -285,29 +284,29 @@ object FriendImageIdRequestPacket : OutgoingPacketBuilder {
...
@@ -285,29 +284,29 @@ object FriendImageIdRequestPacket : OutgoingPacketBuilder {
*/
*/
OVER_FILE_SIZE_MAX
,
OVER_FILE_SIZE_MAX
,
}
}
}
override
fun
decode
()
=
with
(
input
)
{
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
Response
=
Response
().
apply
{
discardExact
(
6
)
discardExact
(
6
)
if
(
readUByte
()
!=
UByte
.
MIN_VALUE
)
{
if
(
readUByte
()
!=
UByte
.
MIN_VALUE
)
{
discardExact
(
60
)
discardExact
(
60
)
@Suppress
(
"ControlFlowWithEmptyBody"
)
@Suppress
(
"ControlFlowWithEmptyBody"
)
while
(
readUByte
().
toUInt
()
!=
0
x4Au
);
while
(
readUByte
().
toUInt
()
!=
0
x4Au
);
uKey
=
readBytes
(
readUnsignedVarInt
().
toInt
())
//128
uKey
=
readBytes
(
readUnsignedVarInt
().
toInt
())
//128
discardExact
(
1
)
//52, id
discardExact
(
1
)
//52, id
imageId
=
ImageId
(
readString
(
readUnsignedVarInt
().
toInt
()))
//37
imageId
=
ImageId
(
readString
(
readUnsignedVarInt
().
toInt
()))
//37
state
=
REQUIRE_UPLOAD
state
=
REQUIRE_UPLOAD
}
else
{
val
toDiscard
=
readUByte
().
toInt
()
-
37
if
(
toDiscard
<
0
)
{
state
=
OVER_FILE_SIZE_MAX
}
else
{
}
else
{
val
toDiscard
=
readUByte
().
toInt
()
-
37
discardExact
(
toDiscard
)
if
(
toDiscard
<
0
)
{
imageId
=
ImageId
(
readString
(
37
))
state
=
OVER_FILE_SIZE_MAX
state
=
ALREADY_EXISTS
}
else
{
discardExact
(
toDiscard
)
imageId
=
ImageId
(
readString
(
37
))
state
=
ALREADY_EXISTS
}
}
}
}
}
}
}
...
@@ -319,12 +318,12 @@ object FriendImageIdRequestPacket : OutgoingPacketBuilder {
...
@@ -319,12 +318,12 @@ object FriendImageIdRequestPacket : OutgoingPacketBuilder {
*/
*/
@AnnotatedId
(
KnownPacketId
.
GROUP_IMAGE_ID
)
@AnnotatedId
(
KnownPacketId
.
GROUP_IMAGE_ID
)
@PacketVersion
(
date
=
"2019.10.26"
,
timVersion
=
"2.3.2.21173"
)
@PacketVersion
(
date
=
"2019.10.26"
,
timVersion
=
"2.3.2.21173"
)
object
GroupImageIdRequestPacket
:
OutgoingPacketBuilder
{
object
GroupImageIdRequestPacket
:
SessionPacketFactory
<
GroupImageIdRequestPacket
.
Response
>()
{
operator
fun
invoke
(
operator
fun
invoke
(
bot
:
UInt
,
bot
:
UInt
,
groupInternalId
:
GroupInternalId
,
groupInternalId
:
GroupInternalId
,
image
:
ExternalImage
,
image
:
ExternalImage
,
sessionKey
:
ByteArra
y
sessionKey
:
SessionKe
y
)
=
buildOutgoingPacket
{
)
=
buildOutgoingPacket
{
writeQQ
(
bot
)
writeQQ
(
bot
)
writeHex
(
"04 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 00 00 00"
)
writeHex
(
"04 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 00 00 00"
)
...
@@ -379,9 +378,8 @@ object GroupImageIdRequestPacket : OutgoingPacketBuilder {
...
@@ -379,9 +378,8 @@ object GroupImageIdRequestPacket : OutgoingPacketBuilder {
private
val
value0x6A
:
UByteArray
=
ubyteArrayOf
(
0
x05u
,
0
x32u
,
0
x36u
,
0
x36u
,
0
x35u
,
0
x36u
)
private
val
value0x6A
:
UByteArray
=
ubyteArrayOf
(
0
x05u
,
0
x32u
,
0
x36u
,
0
x36u
,
0
x35u
,
0
x36u
)
@AnnotatedId
(
KnownPacketId
.
GROUP_IMAGE_ID
)
@PacketVersion
(
date
=
"2019.10.26"
,
timVersion
=
"2.3.2.21173"
)
@PacketVersion
(
date
=
"2019.10.26"
,
timVersion
=
"2.3.2.21173"
)
class
Response
(
input
:
ByteReadPacket
)
:
ResponsePacket
(
input
)
{
class
Response
:
Packet
{
lateinit
var
state
:
State
lateinit
var
state
:
State
/**
/**
...
@@ -403,19 +401,19 @@ object GroupImageIdRequestPacket : OutgoingPacketBuilder {
...
@@ -403,19 +401,19 @@ object GroupImageIdRequestPacket : OutgoingPacketBuilder {
*/
*/
OVER_FILE_SIZE_MAX
,
OVER_FILE_SIZE_MAX
,
}
}
}
override
fun
decode
():
Unit
=
with
(
input
)
{
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
Response
=
Response
().
apply
{
discardExact
(
6
)
//00 00 00 05 00 00
discardExact
(
6
)
//00 00 00 05 00 00
val
length
=
remaining
-
128
-
14
if
(
length
<
0
)
{
state
=
if
(
readUShort
().
toUInt
()
==
0
x0025u
)
State
.
OVER_FILE_SIZE_MAX
else
State
.
ALREADY_EXISTS
return
@
with
}
discardExact
(
length
)
val
length
=
remaining
-
128
-
14
uKey
=
readBytes
(
128
)
if
(
length
<
0
)
{
state
=
State
.
REQUIRE_UPLOAD
state
=
if
(
readUShort
().
toUInt
()
==
0
x0025u
)
Response
.
State
.
OVER_FILE_SIZE_MAX
else
Response
.
State
.
ALREADY_EXISTS
return
@
apply
}
}
discardExact
(
length
)
uKey
=
readBytes
(
128
)
state
=
Response
.
State
.
REQUIRE_UPLOAD
}
}
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/AndroidOnlineEventPackets.kt
deleted
100644 → 0
View file @
6f498554
package
net.mamoe.mirai.network.protocol.tim.packet.event
import
kotlinx.io.core.ByteReadPacket
/**
* Android 客户端上线
*/
class
ServerAndroidOnlineEventPacket
(
input
:
ByteReadPacket
,
eventIdentity
:
EventPacketIdentity
)
:
ServerEventPacket
(
input
,
eventIdentity
)
/**
* Android 客户端下线
*/
class
ServerAndroidOfflineEventPacket
(
input
:
ByteReadPacket
,
eventIdentity
:
EventPacketIdentity
)
:
ServerEventPacket
(
input
,
eventIdentity
)
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/GroupEventPackets.kt
deleted
100644 → 0
View file @
6f498554
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
,
"EXPERIMENTAL_UNSIGNED_LITERALS"
)
package
net.mamoe.mirai.network.protocol.tim.packet.event
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.discardExact
import
kotlinx.io.core.readUInt
import
net.mamoe.mirai.event.events.FriendConversationInitializedEvent
import
net.mamoe.mirai.event.events.MemberPermissionChangedEvent
import
net.mamoe.mirai.network.protocol.tim.packet.CorrespondingEvent
import
net.mamoe.mirai.network.protocol.tim.packet.PacketVersion
import
net.mamoe.mirai.utils.io.readString
import
kotlin.properties.Delegates
/**
* 群文件上传
*/
class
ServerGroupUploadFileEventPacket
(
input
:
ByteReadPacket
,
eventIdentity
:
EventPacketIdentity
)
:
ServerEventPacket
(
input
,
eventIdentity
)
{
private
lateinit
var
xmlMessage
:
String
override
fun
decode
()
{
this
.
input
.
discardExact
(
60
)
val
size
=
this
.
input
.
readShort
().
toInt
()
this
.
input
.
discardExact
(
3
)
xmlMessage
=
this
.
input
.
readString
(
size
)
}
//todo test
}
class
GroupMemberNickChangedEventPacket
(
input
:
ByteReadPacket
,
eventIdentity
:
EventPacketIdentity
)
:
ServerEventPacket
(
input
,
eventIdentity
)
{
private
val
groupId
:
UInt
get
()
=
eventIdentity
.
from
private
val
group
:
UInt
get
()
=
eventIdentity
.
from
override
fun
decode
()
{
// GroupId VarInt
// 00 00 00 08 00 0A 00 04 01 00 00 00 22 96 29 7B 01 01 00 00 F3 66 00 00 00 05 00 00 00 EE 00 00 00 05
// TODO ? 数据中没有哪个人的昵称改变了
}
}
/**
* 好友发起会话, 即在输入框输入了任意内容.
*/
@CorrespondingEvent
(
FriendConversationInitializedEvent
::
class
)
@PacketVersion
(
date
=
"2019.11.2"
,
timVersion
=
"2.3.2.21173"
)
class
FriendConversationInitializedEventPacket
(
input
:
ByteReadPacket
,
eventIdentity
:
EventPacketIdentity
)
:
ServerEventPacket
(
input
,
eventIdentity
)
{
var
qq
:
UInt
by
Delegates
.
notNull
()
// 00 00 00 00 3E 03 3F A2 00
override
fun
decode
()
=
with
(
input
)
{
discardExact
(
4
)
// 00 00 00 00
qq
=
readUInt
()
}
}
@CorrespondingEvent
(
MemberPermissionChangedEvent
::
class
)
@PacketVersion
(
date
=
"2019.11.2"
,
timVersion
=
"2.3.2.21173"
)
class
GroupMemberPermissionChangedEventPacket
internal
constructor
(
input
:
ByteReadPacket
,
eventIdentity
:
EventPacketIdentity
)
:
ServerEventPacket
(
input
,
eventIdentity
)
{
val
groupId
:
UInt
get
()
=
eventIdentity
.
from
var
qq
:
UInt
=
0
u
lateinit
var
kind
:
MemberPermissionChangedEvent
.
Kind
override
fun
decode
():
Unit
=
with
(
input
)
{
// 群里一个人变成管理员:
// 00 00 00 08 00 0A 00 04 01 00 00 00 22 96 29 7B 01 01 76 E4 B8 DD 01
// 取消管理员
// 00 00 00 08 00 0A 00 04 01 00 00 00 22 96 29 7B 01 00 76 E4 B8 DD 00
discardExact
(
remaining
-
5
)
qq
=
readUInt
()
kind
=
when
(
readByte
().
toInt
())
{
0
x00
->
MemberPermissionChangedEvent
.
Kind
.
NO_LONGER_OPERATOR
0
x01
->
MemberPermissionChangedEvent
.
Kind
.
BECOME_OPERATOR
else
->
{
error
(
"Could not determine permission change kind"
)
}
}
}
}
class
ServerGroupUnknownChangedEventPacket
(
input
:
ByteReadPacket
,
eventIdentity
:
EventPacketIdentity
)
:
ServerEventPacket
(
input
,
eventIdentity
)
{
override
fun
decode
()
=
with
(
input
)
{
//00 00 00 08 00 0A 00 04 01 00 00 00 22 96 29 7B 01 01 00 00 F3 55 00 00 00 05 00 00 00 E9 00 00 00 05
//00 00 00 08 00 0A 00 04 01 00 00 00 22 96 29 7B 01 01 00 00 F3 56 00 00 00 05 00 00 00 EA 00 00 00 05
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/MessageEventPackets.kt
deleted
100644 → 0
View file @
6f498554
@
file
:
Suppress
(
"EXPERIMENTAL_UNSIGNED_LITERALS"
,
"EXPERIMENTAL_API_USAGE"
)
package
net.mamoe.mirai.network.protocol.tim.packet.event
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.discardExact
import
kotlinx.io.core.readUInt
import
net.mamoe.mirai.message.MessageChain
import
net.mamoe.mirai.message.NullMessageChain
import
net.mamoe.mirai.message.internal.readMessageChain
import
net.mamoe.mirai.network.protocol.tim.packet.PacketVersion
import
net.mamoe.mirai.utils.MiraiLogger
import
net.mamoe.mirai.utils.io.printTLVMap
import
net.mamoe.mirai.utils.io.read
import
net.mamoe.mirai.utils.io.readTLVMap
import
net.mamoe.mirai.utils.io.readUShortLVByteArray
import
kotlin.properties.Delegates
enum
class
SenderPermission
{
OWNER
,
OPERATOR
,
MEMBER
;
}
@Suppress
(
"EXPERIMENTAL_API_USAGE"
)
@PacketVersion
(
date
=
"2019.11.2"
,
timVersion
=
"2.3.2.21173"
)
class
GroupMessageEventPacket
(
input
:
ByteReadPacket
,
eventIdentity
:
EventPacketIdentity
)
:
ServerEventPacket
(
input
,
eventIdentity
)
{
var
groupNumber
:
UInt
by
Delegates
.
notNull
()
var
qq
:
UInt
by
Delegates
.
notNull
()
lateinit
var
senderName
:
String
/**
* 发送方权限.
*/
lateinit
var
senderPermission
:
SenderPermission
var
message
:
MessageChain
=
NullMessageChain
override
fun
decode
()
=
with
(
input
)
{
discardExact
(
31
)
groupNumber
=
readUInt
()
discardExact
(
1
)
qq
=
readUInt
()
discardExact
(
48
)
readUShortLVByteArray
()
discardExact
(
2
)
//2个0x00
message
=
readMessageChain
()
val
map
=
readTLVMap
(
true
)
if
(
map
.
containsKey
(
18
u
))
{
map
.
getValue
(
18
u
).
read
{
val
tlv
=
readTLVMap
(
true
)
//tlv.printTLVMap("消息结尾 tag=18 的 TLV")
////群主的18: 05 00 04 00 00 00 03 08 00 04 00 00 00 04 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08
//群主的 子map= {5=00 00 00 03, 8=00 00 00 04, 1=48 69 6D 31 38 38 6D 6F 65, 3=04, 4=00 00 00 08}
//管理员 子map= {5=00 00 00 03, 8=00 00 00 04, 2=65 6F 6D 38 38 31 6D 69 48, 3=02, 4=00 00 00 10}
//群成员 子map= {5=00 00 00 03, 8=00 00 00 04, 2=65 6F 6D 38 38 31 6D 69 48, 3=02}
// 4=08, 群主
// 没有4, 群员
// 4=10, 管理员
senderPermission
=
when
(
tlv
.
takeIf
{
it
.
containsKey
(
0
x04u
)
}
?.
get
(
0
x04u
)
?.
getOrNull
(
3
)
?.
toUInt
())
{
null
->
SenderPermission
.
MEMBER
0
x08u
->
SenderPermission
.
OWNER
0
x10u
->
SenderPermission
.
OPERATOR
else
->
{
tlv
.
printTLVMap
(
"TLV(tag=18) Map"
)
MiraiLogger
.
warning
(
"Could not determine member permission, default permission MEMBER is being used"
)
SenderPermission
.
MEMBER
}
}
senderName
=
when
{
tlv
.
containsKey
(
0
x01u
)
->
kotlinx
.
io
.
core
.
String
(
tlv
.
getValue
(
0
x01u
))
//这个人的qq昵称
tlv
.
containsKey
(
0
x02u
)
->
kotlinx
.
io
.
core
.
String
(
tlv
.
getValue
(
0
x02u
))
//这个人的群名片
else
->
{
tlv
.
printTLVMap
(
"TLV(tag=18) Map"
)
MiraiLogger
.
warning
(
"Could not determine senderName"
)
"null"
}
}
}
}
}
}
//
//以前的消息: 00 00 00 25 00 08 00 02 00 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 58 2C 60 86 35 3A 30 B3 C7 63 4A 80 E7 CD 5B 64 00 0B 78 16 5D A3 0A FD 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 0A FD AB 77 16 02 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 04 01 00 01 36 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
//刚刚的消息: 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 11 F4 B2 F2 1A E7 1F C4 F1 3F 23 FB 74 80 42 64 00 0B 78 1A 5D A3 26 C1 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 26 C1 AA 34 08 42 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E4 BD A0 E5 A5 BD 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
class
FriendMessageEventPacket
(
input
:
ByteReadPacket
,
eventIdentity
:
EventPacketIdentity
)
:
ServerEventPacket
(
input
,
eventIdentity
)
{
val
qq
:
UInt
get
()
=
eventIdentity
.
from
/**
* 是否是在这次登录之前的消息, 即消息记录
*/
var
isPrevious
:
Boolean
=
false
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
override
fun
decode
()
=
with
(
input
)
{
input
.
discardExact
(
2
)
val
l1
=
readShort
()
discardExact
(
1
)
//0x00
isPrevious
=
readByte
().
toInt
()
==
0
x08
discardExact
(
l1
.
toInt
()
-
2
)
//java.io.EOFException: Only 49 bytes were discarded of 69 requested
//抖动窗口消息
discardExact
(
69
)
readUShortLVByteArray
()
//font
discardExact
(
2
)
//2个0x00
message
=
readMessageChain
()
//val map: Map<Int, ByteArray> = readTLVMap(true).withDefault { byteArrayOf() }
//map.printTLVMap("readTLVMap")
//println("map.getValue(18)=" + map.getValue(18).toUHexString())
//19 00 38 01 00 35 AA 02 32 50 03 60 00 68 00 9A 01 29 08 09 20 BF 02 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 B8 03 00 C0 03 00 D0 03 00 E8 03 00 12 00 25 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08 05 00 04 00 00 00 01 08 00 04 00 00 00 01
/*
val offset = unknownLength0 + fontLength//57
event = MessageChain(PlainText(let {
val length = input.readShortAt(101 + offset)//
input.goto(103 + offset).readString(length.toInt())
}))*/
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/event/ServerEventPackets.kt
View file @
bd9cf3bf
This diff is collapsed.
Click to expand it.
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/Captcha.kt
View file @
bd9cf3bf
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
,
"EXPERIMENTAL_UNSIGNED_LITERALS"
)
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
,
"EXPERIMENTAL_UNSIGNED_LITERALS"
,
"unused"
,
"FunctionName"
)
package
net.mamoe.mirai.network.protocol.tim.packet.login
package
net.mamoe.mirai.network.protocol.tim.packet.login
import
kotlinx.io.core.*
import
kotlinx.io.core.*
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.io.*
/**
object
CaptchaKey
:
DecrypterByteArray
,
DecrypterType
<
CaptchaKey
>
{
* 客户端请求验证码图片数据的第几部分
override
val
value
:
ByteArray
=
TIMProtocol
.
key00BA
.
hexToBytes
(
withCache
=
false
)
*/
}
@AnnotatedId
(
KnownPacketId
.
CAPTCHA
)
@AnnotatedId
(
KnownPacketId
.
CAPTCHA
)
object
RequestCaptchaTransmissionPacket
:
OutgoingPacketBuilder
{
object
CaptchaPacket
:
PacketFactory
<
CaptchaPacket
.
CaptchaResponse
,
CaptchaKey
>(
CaptchaKey
)
{
operator
fun
invoke
(
/**
* 请求验证码传输
*/
fun
RequestTransmission
(
bot
:
UInt
,
bot
:
UInt
,
token0825
:
ByteArray
,
token0825
:
ByteArray
,
captchaSequence
:
Int
,
captchaSequence
:
Int
,
token00BA
:
ByteArray
token00BA
:
ByteArray
)
=
buildOutgoingPacket
{
)
:
OutgoingPacket
=
buildOutgoingPacket
{
writeQQ
(
bot
)
writeQQ
(
bot
)
writeHex
(
TIMProtocol
.
fixVer
)
writeHex
(
TIMProtocol
.
fixVer
)
writeHex
(
TIMProtocol
.
key00BA
)
writeHex
(
TIMProtocol
.
key00BA
)
...
@@ -36,19 +41,38 @@ object RequestCaptchaTransmissionPacket : OutgoingPacketBuilder {
...
@@ -36,19 +41,38 @@ object RequestCaptchaTransmissionPacket : OutgoingPacketBuilder {
writeHex
(
TIMProtocol
.
key00BAFix
)
writeHex
(
TIMProtocol
.
key00BAFix
)
}
}
}
}
}
/**
/**
* 提交验证码
* 刷新验证码
*/
*/
@AnnotatedId
(
KnownPacketId
.
CAPTCHA
)
fun
Refresh
(
object
SubmitCaptchaPacket
:
OutgoingPacketBuilder
{
bot
:
UInt
,
operator
fun
invoke
(
token0825
:
ByteArray
):
OutgoingPacket
=
buildOutgoingPacket
{
writeQQ
(
bot
)
writeHex
(
TIMProtocol
.
fixVer
)
writeHex
(
TIMProtocol
.
key00BA
)
encryptAndWrite
(
TIMProtocol
.
key00BA
)
{
writeHex
(
"00 02 00 00 08 04 01 E0"
)
writeHex
(
TIMProtocol
.
constantData2
)
writeHex
(
"00 00 38"
)
writeFully
(
token0825
)
writeHex
(
"01 03 00 19"
)
writeHex
(
TIMProtocol
.
publicKey
)
writeHex
(
"13 00 05 00 00 00 00 00 00 00 00 10"
)
writeHex
(
TIMProtocol
.
key00BAFix
)
}
}
/**
* 提交验证码
*/
fun
Submit
(
bot
:
UInt
,
bot
:
UInt
,
token0825
:
ByteArray
,
token0825
:
ByteArray
,
captcha
:
String
,
captcha
:
String
,
captchaToken
:
IoBuffer
captchaToken
:
IoBuffer
)
=
buildOutgoingPacket
{
)
:
OutgoingPacket
=
buildOutgoingPacket
{
require
(
captcha
.
length
==
4
)
{
"captcha.length must == 4"
}
require
(
captcha
.
length
==
4
)
{
"captcha.length must == 4"
}
writeQQ
(
bot
)
writeQQ
(
bot
)
writeHex
(
TIMProtocol
.
fixVer
)
writeHex
(
TIMProtocol
.
fixVer
)
...
@@ -72,99 +96,52 @@ object SubmitCaptchaPacket : OutgoingPacketBuilder {
...
@@ -72,99 +96,52 @@ object SubmitCaptchaPacket : OutgoingPacketBuilder {
writeHex
(
TIMProtocol
.
key00BAFix
)
//16
writeHex
(
TIMProtocol
.
key00BAFix
)
//16
}
}
}
}
}
/**
sealed
class
CaptchaResponse
:
Packet
{
* 刷新验证码
lateinit
var
token00BA
:
ByteArray
//56 bytes
*/
@AnnotatedId
(
KnownPacketId
.
CAPTCHA
)
class
Correct
:
CaptchaResponse
()
object
OutgoingCaptchaRefreshPacket
:
OutgoingPacketBuilder
{
operator
fun
invoke
(
class
Transmission
:
CaptchaResponse
()
{
qq
:
UInt
,
lateinit
var
captchaSectionN
:
IoBuffer
token0825
:
ByteArray
lateinit
var
captchaToken
:
IoBuffer
//56bytes
)
=
buildOutgoingPacket
{
var
transmissionCompleted
:
Boolean
=
false
//验证码是否已经传输完成
writeQQ
(
qq
)
writeHex
(
TIMProtocol
.
fixVer
)
writeHex
(
TIMProtocol
.
key00BA
)
encryptAndWrite
(
TIMProtocol
.
key00BA
)
{
writeHex
(
"00 02 00 00 08 04 01 E0"
)
writeHex
(
TIMProtocol
.
constantData2
)
writeHex
(
"00 00 38"
)
writeFully
(
token0825
)
writeHex
(
"01 03 00 19"
)
writeHex
(
TIMProtocol
.
publicKey
)
writeHex
(
"13 00 05 00 00 00 00 00 00 00 00 10"
)
writeHex
(
TIMProtocol
.
key00BAFix
)
}
}
}
}
}
/**
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
CaptchaResponse
=
* 服务器发送验证码图片文件一部分过来. 当验证码输入错误时, 服务器的返回也会是这个包.
when
(
val
id
=
readByte
().
toUInt
())
{
*
0
x14u
->
{
//00 05 00 00 00 00 00 00 38
* @author Him188moe
CaptchaResponse
.
Correct
().
apply
{
*/
discardExact
(
9
)
@AnnotatedId
(
KnownPacketId
.
CAPTCHA
)
token00BA
=
readBytes
(
56
)
open
class
CaptchaTransmissionResponsePacket
(
input
:
ByteReadPacket
)
:
ServerCaptchaPacket
(
input
)
{
}
lateinit
var
captchaSectionN
:
IoBuffer
}
lateinit
var
captchaToken
:
IoBuffer
//56bytes
0
x13u
->
{
var
transmissionCompleted
:
Boolean
=
false
//验证码是否已经传输完成
CaptchaResponse
.
Transmission
().
apply
{
lateinit
var
token00BA
:
ByteArray
//40 bytes
discardExact
(
9
)
captchaToken
=
readIoBuffer
(
56
)
override
fun
decode
()
=
with
(
input
)
{
val
length
=
readShort
()
input
.
discardExact
(
10
)
//13 00 05 01 00 00 01 23 00 38
captchaSectionN
=
readIoBuffer
(
length
)
captchaToken
=
readIoBuffer
(
56
)
val
length
=
readShort
()
discardExact
(
1
)
captchaSectionN
=
readIoBuffer
(
length
)
val
byte
=
readByte
().
toInt
()
transmissionCompleted
=
byte
==
0
discardExact
(
1
)
discardExact
(
remaining
-
56
-
2
)
val
byte
=
readByte
().
toInt
()
token00BA
=
readBytes
(
40
)
transmissionCompleted
=
byte
==
0
}
}
discardExact
(
remaining
-
56
-
2
)
else
->
error
(
"Unable to analyze RequestCaptchaTransmissionPacket, unknown id: $id"
)
token00BA
=
readBytes
(
40
)
}
}
}
}
/*
/*
fun main() {
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()
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()
CaptchaTransmissionResponsePacket(data.toReadPacket(), data.size, "00 BA 31 01".hexToBytes()).let {
Server
CaptchaTransmissionResponsePacket(data.toReadPacket(), data.size, "00 BA 31 01".hexToBytes()).let {
it.dataDecode()
it.dataDecode()
println(it.toString())
println(it.toString())
}
}
}*/
}*/
\ No newline at end of file
/**
* 验证码正确
*
* @author Him188moe
*/
@AnnotatedId
(
KnownPacketId
.
CAPTCHA
)
class
CaptchaCorrectPacket
(
input
:
ByteReadPacket
)
:
ServerCaptchaPacket
(
input
)
{
lateinit
var
token00BA
:
ByteArray
//56 bytes
override
fun
decode
()
=
with
(
input
)
{
discardExact
(
10
)
//14 00 05 00 00 00 00 00 00 38
token00BA
=
readBytes
(
56
)
}
}
@AnnotatedId
(
KnownPacketId
.
CAPTCHA
)
abstract
class
ServerCaptchaPacket
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
@AnnotatedId
(
KnownPacketId
.
CAPTCHA
)
class
Encrypted
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
fun
decrypt
():
ServerCaptchaPacket
{
return
this
.
decryptAsByteArray
(
TIMProtocol
.
key00BA
)
{
data
->
when
(
data
.
size
)
{
66
,
95
->
CaptchaCorrectPacket
(
data
.
toReadPacket
())
//66 -> ServerCaptchaUnknownPacket(data.toReadPacket())
else
->
CaptchaTransmissionResponsePacket
(
data
.
toReadPacket
())
}.
applySequence
(
sequenceId
)
}
}
}
}
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/ChangeOnlineStatusPacket.kt
View file @
bd9cf3bf
...
@@ -2,7 +2,9 @@
...
@@ -2,7 +2,9 @@
package
net.mamoe.mirai.network.protocol.tim.packet.login
package
net.mamoe.mirai.network.protocol.tim.packet.login
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.writeUByte
import
kotlinx.io.core.writeUByte
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.utils.OnlineStatus
import
net.mamoe.mirai.utils.OnlineStatus
...
@@ -14,10 +16,10 @@ import net.mamoe.mirai.utils.io.writeQQ
...
@@ -14,10 +16,10 @@ import net.mamoe.mirai.utils.io.writeQQ
* 改变在线状态: "我在线上", "隐身" 等
* 改变在线状态: "我在线上", "隐身" 等
*/
*/
@AnnotatedId
(
KnownPacketId
.
CHANGE_ONLINE_STATUS
)
@AnnotatedId
(
KnownPacketId
.
CHANGE_ONLINE_STATUS
)
object
ChangeOnlineStatusPacket
:
OutgoingPacketBuilder
{
object
ChangeOnlineStatusPacket
:
PacketFactory
<
ChangeOnlineStatusPacket
.
ChangeOnlineStatusResponse
,
NoDecrypter
>(
NoDecrypter
)
{
operator
fun
invoke
(
operator
fun
invoke
(
bot
:
UInt
,
bot
:
UInt
,
sessionKey
:
ByteArra
y
,
sessionKey
:
SessionKe
y
,
loginStatus
:
OnlineStatus
loginStatus
:
OnlineStatus
):
OutgoingPacket
=
buildOutgoingPacket
{
):
OutgoingPacket
=
buildOutgoingPacket
{
writeQQ
(
bot
)
writeQQ
(
bot
)
...
@@ -28,4 +30,9 @@ object ChangeOnlineStatusPacket : OutgoingPacketBuilder {
...
@@ -28,4 +30,9 @@ object ChangeOnlineStatusPacket : OutgoingPacketBuilder {
writeHex
(
"00 01 00 01 00 04 00 00 00 00"
)
writeHex
(
"00 01 00 01 00 04 00 00 00 00"
)
}
}
}
}
object
ChangeOnlineStatusResponse
:
Packet
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
ChangeOnlineStatusResponse
=
ChangeOnlineStatusResponse
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/PasswordSubmission.kt
View file @
bd9cf3bf
...
@@ -2,26 +2,52 @@
...
@@ -2,26 +2,52 @@
package
net.mamoe.mirai.network.protocol.tim.packet.login
package
net.mamoe.mirai.network.protocol.tim.packet.login
import
kotlinx.io.core.
BytePacketBuilder
import
kotlinx.io.core.
*
import
kotlinx.io.core.IoBuff
er
import
net.mamoe.mirai.contact.Gend
er
import
kotlinx.io.core.writeFully
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.utils.MiraiLogger
import
net.mamoe.mirai.utils.decryptBy
import
net.mamoe.mirai.utils.encryptBy
import
net.mamoe.mirai.utils.encryptBy
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.writeCRC32
import
net.mamoe.mirai.utils.writeCRC32
import
kotlin.properties.Delegates
object
ShareKey
:
DecrypterByteArray
,
DecrypterType
<
ShareKey
>
{
override
val
value
:
ByteArray
=
TIMProtocol
.
shareKey
.
hexToBytes
(
withCache
=
false
)
}
inline
class
PrivateKey
(
override
val
value
:
ByteArray
)
:
DecrypterByteArray
{
companion
object
Type
:
DecrypterType
<
PrivateKey
>
}
inline
class
SubmitPasswordResponseDecrypter
(
private
val
privateKey
:
PrivateKey
)
:
Decrypter
{
override
fun
decrypt
(
packet
:
ByteReadPacket
):
ByteReadPacket
{
var
decrypted
=
ShareKey
.
decrypt
(
packet
)
(
decrypted
.
remaining
).
let
{
if
(
it
.
toInt
()
%
8
==
0
&&
it
>=
16
)
{
decrypted
=
privateKey
.
decrypt
(
decrypted
)
}
}
// TODO: 2019/11/5 优化: 某些情况下并不需要这次解密. 根据长度判断会导致一些问题
return
decrypted
}
companion
object
Type
:
DecrypterType
<
SubmitPasswordResponseDecrypter
>
}
/**
/**
* 提交密码
* 提交密码
*/
*/
@AnnotatedId
(
KnownPacketId
.
LOGIN
)
@AnnotatedId
(
KnownPacketId
.
LOGIN
)
object
SubmitPasswordPacket
:
OutgoingPacketBuilder
{
object
SubmitPasswordPacket
:
PacketFactory
<
SubmitPasswordPacket
.
LoginResponse
,
SubmitPasswordResponseDecrypter
>(
SubmitPasswordResponseDecrypter
)
{
operator
fun
invoke
(
operator
fun
invoke
(
bot
:
UInt
,
bot
:
UInt
,
password
:
String
,
password
:
String
,
loginTime
:
Int
,
loginTime
:
Int
,
loginIP
:
String
,
loginIP
:
String
,
privateKey
:
ByteArra
y
,
privateKey
:
PrivateKe
y
,
token0825
:
ByteArray
,
token0825
:
ByteArray
,
token00BA
:
ByteArray
?
=
null
,
token00BA
:
ByteArray
?
=
null
,
randomDeviceName
:
Boolean
=
false
,
randomDeviceName
:
Boolean
=
false
,
...
@@ -29,38 +55,168 @@ object SubmitPasswordPacket : OutgoingPacketBuilder {
...
@@ -29,38 +55,168 @@ object SubmitPasswordPacket : OutgoingPacketBuilder {
):
OutgoingPacket
=
buildOutgoingPacket
{
):
OutgoingPacket
=
buildOutgoingPacket
{
writeQQ
(
bot
)
writeQQ
(
bot
)
writeHex
(
TIMProtocol
.
passwordSubmissionTLV1
)
writeHex
(
TIMProtocol
.
passwordSubmissionTLV1
)
writeShort
(
25
);
writeHex
(
TIMProtocol
.
publicKey
)
//=25
writeShort
(
25
)
writeHex
(
TIMProtocol
.
publicKey
)
//=25
writeZero
(
2
)
writeZero
(
2
)
writeShort
(
16
)
writeShort
(
16
);
writeHex
(
TIMProtocol
.
key0836
)
//=16
writeHex
(
TIMProtocol
.
key0836
)
//=16
//TODO shareKey 极大可能为 publicKey, key0836 计算得到
//TODO shareKey 极大可能为 publicKey, key0836 计算得到
encryptAndWrite
(
TIMProtocol
.
shareKey
)
{
encryptAndWrite
(
TIMProtocol
.
shareKey
)
{
writePart1
(
bot
,
password
,
loginTime
,
loginIP
,
privateKey
,
token0825
,
randomDeviceName
,
tlv0006
)
writePart1
(
bot
,
password
,
loginTime
,
loginIP
,
privateKey
,
token0825
,
randomDeviceName
,
tlv0006
)
if
(
token00BA
!=
null
)
{
if
(
token00BA
!=
null
)
{
writeHex
(
"01 10"
)
writeHex
(
"01 10"
)
writeHex
(
"00 3C"
)
writeHex
(
"00 3C"
)
writeHex
(
"00 01"
)
writeHex
(
"00 01"
)
writeHex
(
"00 38"
);
writeFully
(
token00BA
)
}
writePart2
()
}
}
sealed
class
LoginResponse
:
Packet
{
class
KeyExchange
:
LoginResponse
()
{
lateinit
var
tlv0006
:
IoBuffer
//120bytes
var
tokenUnknown
:
ByteArray
?
=
null
var
privateKeyUpdate
:
PrivateKey
?
=
null
//16bytes
}
class
CaptchaInit
:
LoginResponse
()
{
lateinit
var
captchaPart1
:
IoBuffer
lateinit
var
token00BA
:
ByteArray
var
unknownBoolean
:
Boolean
by
Delegates
.
notNull
()
}
class
Success
:
LoginResponse
()
{
var
sessionResponseDecryptionKey
:
SessionResponseDecryptionKey
by
Delegates
.
notNull
()
//16 bytes|
lateinit
var
token38
:
IoBuffer
//56
lateinit
var
token88
:
IoBuffer
//136
lateinit
var
encryptionKey
:
IoBuffer
//16
lateinit
var
nickname
:
String
var
age
:
Short
by
Delegates
.
notNull
()
lateinit
var
gender
:
Gender
}
writeHex
(
"00 38"
)
class
Failed
(
val
result
:
LoginResult
)
:
LoginResponse
()
writeFully
(
token00BA
)
}
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
LoginResponse
{
val
size
=
remaining
.
toInt
()
return
when
{
size
==
229
||
size
==
271
||
size
==
207
->
LoginResponse
.
KeyExchange
().
apply
{
discardExact
(
5
)
//01 00 1E 00 10
privateKeyUpdate
=
PrivateKey
(
readBytes
(
0
x10
))
discardExact
(
4
)
//00 06 00 78
tlv0006
=
readIoBuffer
(
0
x78
)
try
{
discardExact
(
8
)
//01 10 00 3C 00 01 00 38
tokenUnknown
=
readBytes
(
56
)
}
catch
(
e
:
EOFException
)
{
//什么都不做. 因为有的包就是没有这个数据.
}
}
}
writePart2
()
size
==
844
||
size
==
871
->
LoginResponse
.
CaptchaInit
().
apply
{
discardExact
(
78
)
//println(readRemainingBytes().toUHexString())
val
captchaLength
=
readShort
()
//2bytes
this
.
captchaPart1
=
readIoBuffer
(
captchaLength
)
discardExact
(
1
)
this
.
unknownBoolean
=
readByte
().
toInt
()
==
1
discardExact
(
remaining
-
60
)
this
.
token00BA
=
readBytes
(
40
)
}
size
>
650
->
LoginResponse
.
Success
().
apply
{
discardExact
(
7
)
//00 01 09 00 70 00 01
//FB 01 04 03 33
encryptionKey
=
readIoBuffer
(
16
)
//C6 72 C7 73 70 01 46 A2 11 88 AC E4 92 7B BF 90
discardExact
(
2
)
//00 38
token38
=
readIoBuffer
(
56
)
discardExact
(
60
)
//00 20 01 60 C5 A1 39 7A 12 8E BC 34 C3 56 70 E3 1A ED 20 67 ED A9 DB 06 C1 70 81 3C 01 69 0D FF 63 DA 00 00 01 03 00 14 00 01 00 10 60 C9 5D A7 45 70 04 7F 21 7D 84 50 5C 66 A5 C6
discardExact
(
when
(
readUByte
().
toUInt
())
{
0
x00u
->
when
(
readUByte
().
toUInt
())
{
0
x33u
->
28
else
->
null
}
0
x01u
->
when
(
readUByte
().
toUInt
())
{
0
x07u
->
0
0
x10u
->
64
else
->
null
}
else
->
null
}
?:
error
(
"Unknown length flag"
)
)
discardExact
(
23
+
3
)
//01 D3 00 01 00 16 00 00 00 01 00 00 00 64 00 00 0D DE 00 09 3A 80 00
discardExact
(
2
)
//00 02
sessionResponseDecryptionKey
=
SessionResponseDecryptionKey
(
readIoBuffer
(
16
))
discardExact
(
2
)
token88
=
readIoBuffer
(
136
)
discardExact
(
299
)
//2E 72 7A 50 41 54 5B 62 7D 47 5D 37 41 53 47 51 00 78 00 01 5D A2 DB 79 00 70 72 E7 D3 4E 6F D8 D1 DD F2 67 04 1D 23 4D E9 A7 AB 89 7A B7 E6 4B C0 79 60 3B 4F AA 31 C5 24 51 C1 4B 4F A4 32 74 BA FE 8E 06 DB 54 25 A2 56 91 E8 66 BB 23 29 EB F7 13 7B 94 1E AF B2 40 4E 69 5C 8C 35 04 D1 25 1F 60 93 F3 40 71 0B 61 60 F1 B6 A9 7A E8 B1 DA 0E 16 A2 F1 2D 69 5A 01 20 7A AB A7 37 68 D2 1A B0 4D 35 D1 E1 35 64 F6 90 2B 00 83 01 24 5B 4E 69 3D 45 54 6B 29 5E 73 23 2D 4E 42 3F 00 70 00 01 5D A2 DB 79 00 68 FD 10 8A 39 51 09 C6 69 CE 09 A4 52 8C 53 D3 B6 87 E1 7B 7E 4E 52 6D BA 9C C4 6E 6D DE 09 99 67 B4 BD 56 71 14 5A 54 01 68 1C 3C AA 0D 76 0B 86 5A C1 F1 BC 5E 0A ED E3 8C 57 86 35 D8 A5 F8 16 01 24 8B 57 56 8C A6 31 6F 65 73 03 DA ED 21 FA 6B 79 32 2B 09 01 E8 D2 D8 F0 7B F1 60 C2 7F 53 5D F6 53 50 8A 43 E2 23 2E 52 7B 60 39 56 67 2D 6A 23 43 4B 60 55 68 35 01 08 00 23 00 01 00 1F 00 17 02 5B
val
nickLength
=
readUByte
().
toInt
()
nickname
=
readString
(
nickLength
)
//后文
//00 05 00 04 00 00 00 01 01 15 00 10 49 83 5C D9 93 6C 8D FE 09 18 99 37 99 80 68 92
discardExact
(
4
)
//02 13 80 02
age
=
readShort
()
//00 05
discardExact
(
4
)
//00 04 00 00
discardExact
(
2
)
//00 01
gender
=
if
(
readBoolean
())
Gender
.
FEMALE
else
Gender
.
MALE
}
else
->
LoginResponse
.
Failed
(
when
(
size
)
{
135
->
{
//包数据错误. 目前怀疑是 tlv0006
this
.
readRemainingBytes
().
cutTail
(
1
).
decryptBy
(
TIMProtocol
.
shareKey
).
read
{
discardExact
(
51
)
MiraiLogger
.
error
(
"Internal error: "
+
readUShortLVString
())
//抱歉,请重新输入密码。
}
LoginResult
.
INTERNAL_ERROR
}
240
,
319
,
320
,
351
->
LoginResult
.
WRONG_PASSWORD
//135 -> LoginState.RETYPE_PASSWORD
63
->
LoginResult
.
BLOCKED
263
->
LoginResult
.
UNKNOWN_QQ_NUMBER
279
,
495
,
551
,
487
->
LoginResult
.
DEVICE_LOCK
343
,
359
->
LoginResult
.
TAKEN_BACK
else
->
{
MiraiLogger
.
error
(
"login response packet size = $size, data=${this.readRemainingBytes().toUHexString()}"
)
LoginResult
.
UNKNOWN
}
})
}
}
}
}
}
}
inline
class
SessionResponseDecryptionKey
(
private
val
delegate
:
IoBuffer
)
:
Decrypter
{
override
fun
decrypt
(
packet
:
ByteReadPacket
):
ByteReadPacket
=
packet
.
decryptBy
(
delegate
)
companion
object
Type
:
DecrypterType
<
SessionResponseDecryptionKey
>
}
private
fun
BytePacketBuilder
.
writePart1
(
private
fun
BytePacketBuilder
.
writePart1
(
qq
:
UInt
,
qq
:
UInt
,
password
:
String
,
password
:
String
,
loginTime
:
Int
,
loginTime
:
Int
,
loginIP
:
String
,
loginIP
:
String
,
privateKey
:
ByteArra
y
,
privateKey
:
PrivateKe
y
,
token0825
:
ByteArray
,
token0825
:
ByteArray
,
randomDeviceName
:
Boolean
,
randomDeviceName
:
Boolean
,
tlv0006
:
IoBuffer
?
=
null
tlv0006
:
IoBuffer
?
=
null
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/SKey.kt
View file @
bd9cf3bf
...
@@ -4,6 +4,7 @@ package net.mamoe.mirai.network.protocol.tim.packet.login
...
@@ -4,6 +4,7 @@ package net.mamoe.mirai.network.protocol.tim.packet.login
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.discardExact
import
kotlinx.io.core.discardExact
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.BotSession
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.network.protocol.tim.packet.*
...
@@ -17,10 +18,10 @@ fun BotSession.RequestSKeyPacket(): OutgoingPacket = RequestSKeyPacket(qqAccount
...
@@ -17,10 +18,10 @@ fun BotSession.RequestSKeyPacket(): OutgoingPacket = RequestSKeyPacket(qqAccount
* SKey 用于 http api
* SKey 用于 http api
*/
*/
@AnnotatedId
(
KnownPacketId
.
S_KEY
)
@AnnotatedId
(
KnownPacketId
.
S_KEY
)
object
RequestSKeyPacket
:
OutgoingPacketBuilder
{
object
RequestSKeyPacket
:
SessionPacketFactory
<
SKey
>()
{
operator
fun
invoke
(
operator
fun
invoke
(
bot
:
UInt
,
bot
:
UInt
,
sessionKey
:
ByteArra
y
sessionKey
:
SessionKe
y
):
OutgoingPacket
=
buildOutgoingPacket
{
):
OutgoingPacket
=
buildOutgoingPacket
{
writeQQ
(
bot
)
writeQQ
(
bot
)
writeHex
(
TIMProtocol
.
fixVer2
)
writeHex
(
TIMProtocol
.
fixVer2
)
...
@@ -29,16 +30,15 @@ object RequestSKeyPacket : OutgoingPacketBuilder {
...
@@ -29,16 +30,15 @@ object RequestSKeyPacket : OutgoingPacketBuilder {
}
}
}
}
@AnnotatedId
(
KnownPacketId
.
S_KEY
)
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
SKey
{
class
Response
(
input
:
ByteReadPacket
)
:
ResponsePacket
(
input
)
{
discardExact
(
4
)
lateinit
var
sKey
:
String
// TODO: 2019/11/2 这里
return
SKey
(
readString
(
10
)).
also
{
override
fun
decode
()
=
with
(
input
)
{
DebugLogger
.
warning
(
"SKey 包后面${readRemainingBytes().toUHexString()}"
)
discardExact
(
4
)
//debugDiscardExact(2)
sKey
=
this
.
readString
(
10
)
//16??
DebugLogger
.
warning
(
"SKey=$sKey"
)
DebugLogger
.
warning
(
"SKey 包后面${this.readRemainingBytes().toUHexString()}"
)
}
}
}
}
}
}
\ No newline at end of file
inline
class
SKey
(
val
delegate
:
String
)
:
Packet
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/ServerLoginResponse.kt
deleted
100644 → 0
View file @
6f498554
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
,
"EXPERIMENTAL_UNSIGNED_LITERALS"
)
package
net.mamoe.mirai.network.protocol.tim.packet.login
import
kotlinx.io.core.*
import
net.mamoe.mirai.contact.Gender
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.io.readBoolean
import
net.mamoe.mirai.utils.io.readIoBuffer
import
net.mamoe.mirai.utils.io.readString
import
kotlin.properties.Delegates
@AnnotatedId
(
KnownPacketId
.
LOGIN
)
sealed
class
ServerLoginResponsePacket
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
@AnnotatedId
(
KnownPacketId
.
LOGIN
)
class
LoginResponseFailedPacket
(
val
loginResult
:
LoginResult
,
input
:
ByteReadPacket
)
:
ServerLoginResponsePacket
(
input
)
/**
* 服务器进行加密后返回 privateKey
*/
@AnnotatedId
(
KnownPacketId
.
LOGIN
)
class
LoginResponseKeyExchangeResponsePacket
(
input
:
ByteReadPacket
)
:
ServerLoginResponsePacket
(
input
)
{
lateinit
var
tlv0006
:
IoBuffer
//120bytes
var
tokenUnknown
:
ByteArray
?
=
null
lateinit
var
privateKeyUpdate
:
ByteArray
//16bytes
@Tested
override
fun
decode
()
{
this
.
input
.
discardExact
(
5
)
//01 00 1E 00 10
privateKeyUpdate
=
this
.
input
.
readBytes
(
0
x10
)
this
.
input
.
discardExact
(
4
)
//00 06 00 78
tlv0006
=
this
.
input
.
readIoBuffer
(
0
x78
)
try
{
this
.
input
.
discardExact
(
8
)
//01 10 00 3C 00 01 00 38
tokenUnknown
=
this
.
input
.
readBytes
(
56
)
}
catch
(
e
:
EOFException
)
{
//什么都不做. 因为有的包就是没有这个数据.
}
}
@AnnotatedId
(
KnownPacketId
.
LOGIN
)
class
Encrypted
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
@Tested
fun
decrypt
(
privateKey
:
ByteArray
):
LoginResponseKeyExchangeResponsePacket
=
LoginResponseKeyExchangeResponsePacket
(
this
.
decryptBy
(
TIMProtocol
.
shareKey
,
privateKey
)).
applySequence
(
sequenceId
)
}
}
@AnnotatedId
(
KnownPacketId
.
LOGIN
)
class
LoginResponseSuccessPacket
(
input
:
ByteReadPacket
)
:
ServerLoginResponsePacket
(
input
)
{
lateinit
var
sessionResponseDecryptionKey
:
IoBuffer
//16 bytes|
lateinit
var
token38
:
IoBuffer
//56
lateinit
var
token88
:
IoBuffer
//136
lateinit
var
encryptionKey
:
IoBuffer
//16
lateinit
var
nickname
:
String
var
age
:
Short
by
Delegates
.
notNull
()
lateinit
var
gender
:
Gender
@Tested
override
fun
decode
()
=
with
(
input
)
{
discardExact
(
7
)
//00 01 09 00 70 00 01
encryptionKey
=
readIoBuffer
(
16
)
//C6 72 C7 73 70 01 46 A2 11 88 AC E4 92 7B BF 90
discardExact
(
2
)
//00 38
token38
=
readIoBuffer
(
56
)
discardExact
(
60
)
//00 20 01 60 C5 A1 39 7A 12 8E BC 34 C3 56 70 E3 1A ED 20 67 ED A9 DB 06 C1 70 81 3C 01 69 0D FF 63 DA 00 00 01 03 00 14 00 01 00 10 60 C9 5D A7 45 70 04 7F 21 7D 84 50 5C 66 A5 C6
discardExact
(
when
(
readUByte
().
toUInt
())
{
0
x00u
->
when
(
readUByte
().
toUInt
())
{
0
x33u
->
28
else
->
null
}
0
x01u
->
when
(
readUByte
().
toUInt
())
{
0
x07u
->
0
0
x10u
->
64
else
->
null
}
else
->
null
}
?:
error
(
"Unknown length flag"
)
)
discardExact
(
23
+
3
)
//01 D3 00 01 00 16 00 00 00 01 00 00 00 64 00 00 0D DE 00 09 3A 80 00
discardExact
(
2
)
//00 02
sessionResponseDecryptionKey
=
readIoBuffer
(
16
)
discardExact
(
2
)
token88
=
readIoBuffer
(
136
)
discardExact
(
299
)
//2E 72 7A 50 41 54 5B 62 7D 47 5D 37 41 53 47 51 00 78 00 01 5D A2 DB 79 00 70 72 E7 D3 4E 6F D8 D1 DD F2 67 04 1D 23 4D E9 A7 AB 89 7A B7 E6 4B C0 79 60 3B 4F AA 31 C5 24 51 C1 4B 4F A4 32 74 BA FE 8E 06 DB 54 25 A2 56 91 E8 66 BB 23 29 EB F7 13 7B 94 1E AF B2 40 4E 69 5C 8C 35 04 D1 25 1F 60 93 F3 40 71 0B 61 60 F1 B6 A9 7A E8 B1 DA 0E 16 A2 F1 2D 69 5A 01 20 7A AB A7 37 68 D2 1A B0 4D 35 D1 E1 35 64 F6 90 2B 00 83 01 24 5B 4E 69 3D 45 54 6B 29 5E 73 23 2D 4E 42 3F 00 70 00 01 5D A2 DB 79 00 68 FD 10 8A 39 51 09 C6 69 CE 09 A4 52 8C 53 D3 B6 87 E1 7B 7E 4E 52 6D BA 9C C4 6E 6D DE 09 99 67 B4 BD 56 71 14 5A 54 01 68 1C 3C AA 0D 76 0B 86 5A C1 F1 BC 5E 0A ED E3 8C 57 86 35 D8 A5 F8 16 01 24 8B 57 56 8C A6 31 6F 65 73 03 DA ED 21 FA 6B 79 32 2B 09 01 E8 D2 D8 F0 7B F1 60 C2 7F 53 5D F6 53 50 8A 43 E2 23 2E 52 7B 60 39 56 67 2D 6A 23 43 4B 60 55 68 35 01 08 00 23 00 01 00 1F 00 17 02 5B
val
nickLength
=
readUByte
().
toInt
()
nickname
=
readString
(
nickLength
)
//后文
//00 05 00 04 00 00 00 01 01 15 00 10 49 83 5C D9 93 6C 8D FE 09 18 99 37 99 80 68 92
discardExact
(
4
)
//02 13 80 02
age
=
readShort
()
//00 05
discardExact
(
4
)
//00 04 00 00
discardExact
(
2
)
//00 01
gender
=
if
(
readBoolean
())
Gender
.
FEMALE
else
Gender
.
MALE
}
@AnnotatedId
(
KnownPacketId
.
LOGIN
)
class
Encrypted
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
fun
decrypt
(
privateKey
:
ByteArray
):
LoginResponseSuccessPacket
=
LoginResponseSuccessPacket
(
this
.
decryptBy
(
TIMProtocol
.
shareKey
,
privateKey
)).
applySequence
(
sequenceId
)
}
}
/**
* 收到这个包意味着需要验证码登录, 并且能得到验证码图片文件的一部分
*
* @author Him188moe
*/
@AnnotatedId
(
KnownPacketId
.
LOGIN
)
class
LoginResponseCaptchaInitPacket
(
input
:
ByteReadPacket
)
:
ServerLoginResponsePacket
(
input
)
{
lateinit
var
captchaPart1
:
IoBuffer
lateinit
var
token00BA
:
ByteArray
var
unknownBoolean
:
Boolean
by
Delegates
.
notNull
()
@Tested
override
fun
decode
()
{
this
.
input
.
discardExact
(
78
)
//println(this.input.readRemainingBytes().toUHexString())
val
captchaLength
=
this
.
input
.
readShort
()
//2bytes
this
.
captchaPart1
=
this
.
input
.
readIoBuffer
(
captchaLength
)
this
.
input
.
discardExact
(
1
)
this
.
unknownBoolean
=
this
.
input
.
readByte
().
toInt
()
==
1
this
.
input
.
discardExact
(
this
.
input
.
remaining
-
60
)
this
.
token00BA
=
this
.
input
.
readBytes
(
40
)
}
@AnnotatedId
(
KnownPacketId
.
LOGIN
)
class
Encrypted
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
fun
decrypt
():
LoginResponseCaptchaInitPacket
=
LoginResponseCaptchaInitPacket
(
decryptBy
(
TIMProtocol
.
shareKey
)).
applySequence
(
sequenceId
)
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/ServerLoginSuccessPacket.kt
deleted
100644 → 0
View file @
6f498554
@
file
:
Suppress
(
"EXPERIMENTAL_UNSIGNED_LITERALS"
)
package
net.mamoe.mirai.network.protocol.tim.packet.login
import
kotlinx.io.core.ByteReadPacket
import
net.mamoe.mirai.network.protocol.tim.packet.AnnotatedId
import
net.mamoe.mirai.network.protocol.tim.packet.KnownPacketId
import
net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
/**
* Congratulations!
*
* @author Him188moe
*/
@AnnotatedId
(
KnownPacketId
.
CHANGE_ONLINE_STATUS
)
class
ServerLoginSuccessPacket
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
//TODO 可能只是 login status change 的返回包
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/Session.kt
View file @
bd9cf3bf
...
@@ -3,14 +3,14 @@
...
@@ -3,14 +3,14 @@
package
net.mamoe.mirai.network.protocol.tim.packet.login
package
net.mamoe.mirai.network.protocol.tim.packet.login
import
kotlinx.io.core.*
import
kotlinx.io.core.*
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.utils.Tested
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.localIpAddress
import
net.mamoe.mirai.utils.localIpAddress
@AnnotatedId
(
KnownPacketId
.
SESSION_KEY
)
@AnnotatedId
(
KnownPacketId
.
SESSION_KEY
)
object
RequestSessionPacket
:
OutgoingPacketBuilder
{
object
RequestSessionPacket
:
PacketFactory
<
RequestSessionPacket
.
SessionKeyResponse
,
SessionResponseDecryptionKey
>(
SessionResponseDecryptionKey
)
{
operator
fun
invoke
(
operator
fun
invoke
(
bot
:
UInt
,
bot
:
UInt
,
serverIp
:
String
,
serverIp
:
String
,
...
@@ -58,61 +58,49 @@ object RequestSessionPacket : OutgoingPacketBuilder {
...
@@ -58,61 +58,49 @@ object RequestSessionPacket : OutgoingPacketBuilder {
writeIP
(
localIpAddress
())
//todo random to avoid being banned? or that may cause errors?
writeIP
(
localIpAddress
())
//todo random to avoid being banned? or that may cause errors?
}
}
}
}
}
class
SessionKeyResponse
:
Packet
{
var
sessionKey
:
SessionKey
?
=
null
lateinit
var
tlv0105
:
ByteReadPacket
}
@AnnotatedId
(
KnownPacketId
.
SESSION_KEY
)
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
SessionKeyResponse
=
class
SessionKeyResponsePacket
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
SessionKeyResponse
().
apply
{
lateinit
var
sessionKey
:
ByteArray
when
(
remaining
)
{
lateinit
var
tlv0105
:
ByteReadPacket
@Tested
override
fun
decode
()
=
with
(
input
)
{
when
(
val
dataLength
=
remaining
)
{
407L
->
{
407L
->
{
input
.
discardExact
(
25
)
//todo test
discardExact
(
25
)
//todo test
sessionKey
=
input
.
readBytes
(
16
)
sessionKey
=
SessionKey
(
readBytes
(
16
)
)
}
}
439L
->
{
439L
->
{
input
.
discardExact
(
63
)
discardExact
(
63
)
sessionKey
=
input
.
readBytes
(
16
)
sessionKey
=
SessionKey
(
readBytes
(
16
)
)
}
}
502L
,
//?
502L
,
//?
512L
,
512L
,
527L
->
{
527L
->
{
input
.
discardExact
(
63
)
//00 00 0D 00 06 00 01 00 00 00 00 00 1F 00 22 00 01 D7 EC FC 38 1B 74 6F 91 42 00 B9 DB 69 32 43 EC 8C 02 DC E0 07 35 58 8C 6C FE 43 5D AA 6A 88 E0 00 14 00 04 00 01 00 3C 01 0C 00 73 00 01
discardExact
(
63
)
//00 00 0D 00 06 00 01 00 00 00 00 00 1F 00 22 00 01 D7 EC FC 38 1B 74 6F 91 42 00 B9 DB 69 32 43 EC 8C 02 DC E0 07 35 58 8C 6C FE 43 5D AA 6A 88 E0 00 14 00 04 00 01 00 3C 01 0C 00 73 00 01
sessionKey
=
input
.
readBytes
(
16
)
sessionKey
=
SessionKey
(
readBytes
(
16
)
)
tlv0105
=
buildPacket
{
tlv0105
=
buildPacket
{
writeHex
(
"01 05 00 88 00 01 01 02 00 40 02 01 03 3C 01 03 00 00"
)
writeHex
(
"01 05 00 88 00 01 01 02 00 40 02 01 03 3C 01 03 00 00"
)
input
.
discardExact
(
input
.
remaining
-
122
-
1
)
discardExact
(
remaining
-
122
-
1
)
writeFully
(
input
.
readIoBuffer
(
56
))
writeFully
(
readIoBuffer
(
56
))
writeHex
(
"00 40 02 02 03 3C 01 03 00 00"
)
writeHex
(
"00 40 02 02 03 3C 01 03 00 00"
)
input
.
discardExact
(
11
)
discardExact
(
11
)
writeFully
(
input
.
readIoBuffer
(
56
))
writeFully
(
readIoBuffer
(
56
))
}
//todo 这个 tlv0105似乎可以保存起来然后下次登录时使用.
}
//todo 这个 tlv0105似乎可以保存起来然后下次登录时使用.
/*
/*
Discarded(63) =00 00 0D 00 06 00 01 00 00 00 00 00 1F 00 22 00 01 F7 AB 01 4B 23 B5 47 FC 79 02 09 E0 19 EF 61 91 14 AD 8F 38 2E 8B D7 47 39 DE FE 84 A7 E5 6E 3D 00 14 00 04 00 01 00 3C 01 0C 00 73 00 01
Discarded(63) =00 00 0D 00 06 00 01 00 00 00 00 00 1F 00 22 00 01 F7 AB 01 4B 23 B5 47 FC 79 02 09 E0 19 EF 61 91 14 AD 8F 38 2E 8B D7 47 39 DE FE 84 A7 E5 6E 3D 00 14 00 04 00 01 00 3C 01 0C 00 73 00 01
sessionKey=7E 8C 1D AC 52 64 B8 D0 9A 55 3A A6 DF 53 88 C8
sessionKey=7E 8C 1D AC 52 64 B8 D0 9A 55 3A A6 DF 53 88 C8
Discarded(301) =76 E4 B8 DD AB 53 02 2B 53 F1 5D A2 DA CB 00 00 00 B4 03 3D 97 B4 D1 3D 97 B4 C7 00 00 00 07 00 30 D4 E2 53 73 2E 00 F6 3F 8E 45 9F 2E 74 63 39 99 B4 AC 3B 40 C8 9A EE B0 62 A8 E1 39 FE 8E 75 EC 28 6C 03 E6 3B 5F F5 6D 50 7D 1E 29 EC 3D 47 85 08 02 04 08 08 08 08 08 04 00 05 01 0E 12 AC F6 01 0E 00 56 00 01 00 52 13 80 42 00 00 02 02 00 00 18 AB 52 CF 5B E8 CD 95 CC 3F 5C A7 BA C9 C1 5D DD F8 E2 6E 0D A3 DF F8 76 00 20 D3 87 6B 1F F2 2B C7 53 38 60 F3 AD 07 82 8B F6 62 3C E0 DB 66 BC AD D0 68 D0 30 9D 8A 41 E7 75 00 0C 00 00 00 01 00 00 00 00 00 00 00 40 00 2F 00 2A 00 01 8F FE 4F BB B2 63 C7 69 C3 F1 3C DC A1 E8 77 A3 DD 97 FA 00 36 04 40 EF 11 7A 31 02 4E 10 13 94 02 28 00 00 00 00 00 00 01 0D 00 2C 00 01 00 28 EF CB 22 58 6F AE DC F5 CC CE 45 EE 6D CA E7 EF 06 3F 60 B5 8A 22 D5 9E 37 FA 92 9F A9 11 68 F0 2A 25 4A 45 C3 D4 56 CF 01 05 00 8A 00 01 02 02 00 41 01 00 01 03 3C 01 03 00 00 FB
Discarded(301) =76 E4 B8 DD AB 53 02 2B 53 F1 5D A2 DA CB 00 00 00 B4 03 3D 97 B4 D1 3D 97 B4 C7 00 00 00 07 00 30 D4 E2 53 73 2E 00 F6 3F 8E 45 9F 2E 74 63 39 99 B4 AC 3B 40 C8 9A EE B0 62 A8 E1 39 FE 8E 75 EC 28 6C 03 E6 3B 5F F5 6D 50 7D 1E 29 EC 3D 47 85 08 02 04 08 08 08 08 08 04 00 05 01 0E 12 AC F6 01 0E 00 56 00 01 00 52 13 80 42 00 00 02 02 00 00 18 AB 52 CF 5B E8 CD 95 CC 3F 5C A7 BA C9 C1 5D DD F8 E2 6E 0D A3 DF F8 76 00 20 D3 87 6B 1F F2 2B C7 53 38 60 F3 AD 07 82 8B F6 62 3C E0 DB 66 BC AD D0 68 D0 30 9D 8A 41 E7 75 00 0C 00 00 00 01 00 00 00 00 00 00 00 40 00 2F 00 2A 00 01 8F FE 4F BB B2 63 C7 69 C3 F1 3C DC A1 E8 77 A3 DD 97 FA 00 36 04 40 EF 11 7A 31 02 4E 10 13 94 02 28 00 00 00 00 00 00 01 0D 00 2C 00 01 00 28 EF CB 22 58 6F AE DC F5 CC CE 45 EE 6D CA E7 EF 06 3F 60 B5 8A 22 D5 9E 37 FA 92 9F A9 11 68 F0 2A 25 4A 45 C3 D4 56 CF 01 05 00 8A 00 01 02 02 00 41 01 00 01 03 3C 01 03 00 00 FB
56长度=39 89 04 81 64 6B C0 71 B5 6E B0 DF 7D D4 C0 7E 97 83 BC 9F 31 39 39 C3 95 93 D9 CD 48 00 1D 0D 18 52 87 21 B2 C1 B1 AD EF 96 82 D6 D4 57 EA 48 5A 27 8C 14 6F E2 83 00
56长度=39 89 04 81 64 6B C0 71 B5 6E B0 DF 7D D4 C0 7E 97 83 BC 9F 31 39 39 C3 95 93 D9 CD 48 00 1D 0D 18 52 87 21 B2 C1 B1 AD EF 96 82 D6 D4 57 EA 48 5A 27 8C 14 6F E2 83 00
Discarded(11) =41 01 00 02 03 3C 01 03 00 00 86
Discarded(11) =41 01 00 02 03 3C 01 03 00 00 86
*/
*/
}
}
else
->
throw
IllegalArgumentException
(
dataLength
.
toString
())
else
->
throw
IllegalArgumentException
(
remaining
.
toString
())
}
}
//tlv0105 = "01 05 00 88 00 01 01 02 00 40 02 01 03 3C 01 03 00 00" + 取文本中间(data, 取文本长度(data) - 367, 167) + “00 40 02 02 03 3C 01 03 00 00 ” + 取文本中间 (data, 取文本长度 (data) - 166, 167)
}
@AnnotatedId
(
KnownPacketId
.
SESSION_KEY
)
class
Encrypted
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
fun
decrypt
(
sessionResponseDecryptionKey
:
IoBuffer
):
SessionKeyResponsePacket
=
SessionKeyResponsePacket
(
decryptBy
(
sessionResponseDecryptionKey
)).
applySequence
(
sequenceId
)
}
}
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/Touch.kt
View file @
bd9cf3bf
...
@@ -5,53 +5,13 @@ package net.mamoe.mirai.network.protocol.tim.packet.login
...
@@ -5,53 +5,13 @@ package net.mamoe.mirai.network.protocol.tim.packet.login
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.discardExact
import
kotlinx.io.core.discardExact
import
kotlinx.io.core.readBytes
import
kotlinx.io.core.readBytes
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.network.protocol.tim.packet.*
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.io.*
/**
object
TouchKey
:
DecrypterByteArray
,
DecrypterType
<
TouchKey
>
{
* The packet received when logging in, used to redirect server address
override
val
value
:
ByteArray
=
TIMProtocol
.
touchKey
.
hexToBytes
(
withCache
=
false
)
*
* @see RedirectionPacket
* @see SubmitPasswordPacket
*
* @author Him188moe
*/
@Suppress
(
"EXPERIMENTAL_API_USAGE"
,
"EXPERIMENTAL_UNSIGNED_LITERALS"
)
@AnnotatedId
(
KnownPacketId
.
TOUCH
)
class
TouchResponsePacket
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
var
serverIP
:
String
?
=
null
var
loginTime
:
Int
=
0
lateinit
var
loginIP
:
String
lateinit
var
token0825
:
ByteArray
//56
override
fun
decode
()
=
with
(
input
)
{
when
(
val
id
=
readByte
().
toUByte
().
toInt
())
{
0
xFE
->
{
discardExact
(
94
)
serverIP
=
readIP
()
}
0
x00
->
{
discardExact
(
4
)
token0825
=
readBytes
(
56
)
discardExact
(
6
)
loginTime
=
readInt
()
loginIP
=
readIP
()
}
else
->
{
throw
IllegalStateException
(
id
.
toByte
().
toUHexString
())
}
}
}
@AnnotatedId
(
KnownPacketId
.
TOUCH
)
class
Encrypted
(
input
:
ByteReadPacket
)
:
ServerPacket
(
input
)
{
fun
decrypt
():
TouchResponsePacket
=
TouchResponsePacket
(
decryptBy
(
TIMProtocol
.
touchKey
.
hexToBytes
())).
applySequence
(
sequenceId
)
}
}
}
/**
/**
...
@@ -60,11 +20,12 @@ class TouchResponsePacket(input: ByteReadPacket) : ServerPacket(input) {
...
@@ -60,11 +20,12 @@ class TouchResponsePacket(input: ByteReadPacket) : ServerPacket(input) {
* @author Him188moe
* @author Him188moe
*/
*/
@AnnotatedId
(
KnownPacketId
.
TOUCH
)
@AnnotatedId
(
KnownPacketId
.
TOUCH
)
object
TouchPacket
:
OutgoingPacketBuilder
{
object
TouchPacket
:
PacketFactory
<
TouchPacket
.
TouchResponse
,
TouchKey
>(
TouchKey
)
{
operator
fun
invoke
(
operator
fun
invoke
(
bot
:
UInt
,
bot
:
UInt
,
serverIp
:
String
serverIp
:
String
,
)
=
buildOutgoingPacket
{
isRedirect
:
Boolean
):
OutgoingPacket
=
buildOutgoingPacket
{
writeQQ
(
bot
)
writeQQ
(
bot
)
writeHex
(
TIMProtocol
.
fixVer
)
writeHex
(
TIMProtocol
.
fixVer
)
writeHex
(
TIMProtocol
.
touchKey
)
writeHex
(
TIMProtocol
.
touchKey
)
...
@@ -73,37 +34,44 @@ object TouchPacket : OutgoingPacketBuilder {
...
@@ -73,37 +34,44 @@ object TouchPacket : OutgoingPacketBuilder {
writeHex
(
TIMProtocol
.
constantData1
)
writeHex
(
TIMProtocol
.
constantData1
)
writeHex
(
TIMProtocol
.
constantData2
)
writeHex
(
TIMProtocol
.
constantData2
)
writeQQ
(
bot
)
writeQQ
(
bot
)
writeHex
(
"00 00 00 00 03 09 00 08 00 01"
)
writeHex
(
if
(
isRedirect
)
"00 01 00 00 03 09 00 0C 00 01"
else
"00 00 00 00 03 09 00 08 00 01"
)
writeIP
(
serverIp
)
writeIP
(
serverIp
)
writeHex
(
"00 02 00 36 00 12 00 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 14 00 1D 01 02 00 19"
)
writeHex
(
if
(
isRedirect
)
"01 6F A1 58 22 01 00 36 00 12 00 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 14 00 1D 01 03 00 19"
else
"00 02 00 36 00 12 00 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 14 00 1D 01 02 00 19"
)
writeHex
(
TIMProtocol
.
publicKey
)
writeHex
(
TIMProtocol
.
publicKey
)
}
}
}
}
}
/**
class
TouchResponse
:
Packet
{
* Server redirection (0825 response)
var
serverIP
:
String
?
=
null
*
internal
set
* @author Him188moe
var
loginTime
:
Int
=
0
*/
internal
set
@AnnotatedId
(
KnownPacketId
.
TOUCH
)
object
RedirectionPacket
:
OutgoingPacketBuilder
{
operator
fun
invoke
(
bot
:
UInt
,
serverIP
:
String
)
=
buildOutgoingPacket
{
writeQQ
(
bot
)
writeHex
(
TIMProtocol
.
fixVer
)
writeHex
(
TIMProtocol
.
touchKey
)
//redirection key
encryptAndWrite
(
TIMProtocol
.
touchKey
)
{
lateinit
var
loginIP
:
String
writeHex
(
TIMProtocol
.
constantData1
)
internal
set
writeHex
(
TIMProtocol
.
constantData2
)
lateinit
var
token0825
:
ByteArray
writeQQ
(
bot
)
internal
set
writeHex
(
"00 01 00 00 03 09 00 0C 00 01"
)
}
writeIP
(
serverIP
)
writeHex
(
"01 6F A1 58 22 01 00 36 00 12 00 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 14 00 1D 01 03 00 19"
)
override
suspend
fun
ByteReadPacket
.
decode
(
id
:
PacketId
,
sequenceId
:
UShort
,
handler
:
BotNetworkHandler
<
*
>):
TouchResponse
=
TouchResponse
().
apply
{
writeHex
(
TIMProtocol
.
publicKey
)
when
(
val
id
=
readByte
().
toUByte
().
toInt
())
{
0
xFE
->
{
discardExact
(
94
)
serverIP
=
readIP
()
}
0
x00
->
{
discardExact
(
4
)
token0825
=
readBytes
(
56
)
discardExact
(
6
)
loginTime
=
readInt
()
loginIP
=
readIP
()
}
else
->
throw
IllegalStateException
(
id
.
toByte
().
toUHexString
())
}
}
}
}
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotNetworkConfiguration.kt
View file @
bd9cf3bf
...
@@ -2,7 +2,6 @@ package net.mamoe.mirai.utils
...
@@ -2,7 +2,6 @@ package net.mamoe.mirai.utils
import
com.soywiz.klock.TimeSpan
import
com.soywiz.klock.TimeSpan
import
com.soywiz.klock.seconds
import
com.soywiz.klock.seconds
import
net.mamoe.mirai.network.protocol.tim.packet.login.TouchResponsePacket
import
kotlin.jvm.JvmField
import
kotlin.jvm.JvmField
/**
/**
...
@@ -10,7 +9,7 @@ import kotlin.jvm.JvmField
...
@@ -10,7 +9,7 @@ import kotlin.jvm.JvmField
*/
*/
class
BotNetworkConfiguration
{
class
BotNetworkConfiguration
{
/**
/**
* 等待 [TouchResp
onsePacket
] 的时间
* 等待 [TouchResp
nose
] 的时间
*/
*/
var
touchTimeout
:
TimeSpan
=
2
.
seconds
var
touchTimeout
:
TimeSpan
=
2
.
seconds
/**
/**
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
View file @
bd9cf3bf
...
@@ -21,7 +21,7 @@ fun ExternalImage(
...
@@ -21,7 +21,7 @@ fun ExternalImage(
md5
:
ByteArray
,
md5
:
ByteArray
,
format
:
String
,
format
:
String
,
data
:
ByteReadPacket
data
:
ByteReadPacket
)
=
ExternalImage
(
width
,
height
,
md5
,
format
,
data
,
data
.
remaining
)
)
:
ExternalImage
=
ExternalImage
(
width
,
height
,
md5
,
format
,
data
,
data
.
remaining
)
/**
/**
* 外部图片. 图片数据还没有读取到内存.
* 外部图片. 图片数据还没有读取到内存.
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/OnlineStatus.kt
View file @
bd9cf3bf
...
@@ -19,11 +19,20 @@ enum class OnlineStatus(
...
@@ -19,11 +19,20 @@ enum class OnlineStatus(
/**
/**
* 忙碌
* 忙碌
*/
*/
BUSY
(
0
x32u
)
;
BUSY
(
0
x32u
)
,
/**
* 离线 ? 也可能是被删好友 TODO confirm that
*/
OFFLINE
(
0
x02u
),
// TODO: 2019/10/29 what is 0x20u
/**
* ?
*/
UNKNOWN
(
0
x20u
)
;
// TODO: 2019/10/29 what is 0x20u
companion
object
{
companion
object
{
fun
ofId
(
id
:
UByte
):
OnlineStatus
?
=
values
().
firstOrNull
{
it
.
id
==
id
}
fun
ofId
(
id
:
UByte
):
OnlineStatus
?
=
values
().
firstOrNull
{
it
.
id
==
id
}
}
}
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/TEA.kt
View file @
bd9cf3bf
...
@@ -3,6 +3,7 @@ package net.mamoe.mirai.utils
...
@@ -3,6 +3,7 @@ package net.mamoe.mirai.utils
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.IoBuffer
import
kotlinx.io.core.IoBuffer
import
kotlinx.io.pool.useInstance
import
kotlinx.io.pool.useInstance
import
net.mamoe.mirai.network.protocol.tim.packet.DecrypterByteArray
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.io.*
import
kotlin.experimental.and
import
kotlin.experimental.and
import
kotlin.experimental.xor
import
kotlin.experimental.xor
...
@@ -26,6 +27,8 @@ class DecryptionFailedException : Exception()
...
@@ -26,6 +27,8 @@ class DecryptionFailedException : Exception()
*/
*/
fun
ByteArray
.
encryptBy
(
key
:
ByteArray
,
length
:
Int
=
this
.
size
):
ByteArray
=
TEA
.
encrypt
(
this
,
key
,
sourceLength
=
length
)
fun
ByteArray
.
encryptBy
(
key
:
ByteArray
,
length
:
Int
=
this
.
size
):
ByteArray
=
TEA
.
encrypt
(
this
,
key
,
sourceLength
=
length
)
fun
ByteArray
.
encryptBy
(
key
:
DecrypterByteArray
,
length
:
Int
=
this
.
size
):
ByteArray
=
TEA
.
encrypt
(
this
,
key
.
value
,
sourceLength
=
length
)
/**
/**
* 通过 [String.hexToBytes] 将 [keyHex] 转为 [ByteArray] 后用它解密 [this].
* 通过 [String.hexToBytes] 将 [keyHex] 转为 [ByteArray] 后用它解密 [this].
* 将会使用 [HexCache]
* 将会使用 [HexCache]
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt
View file @
bd9cf3bf
...
@@ -3,14 +3,6 @@
...
@@ -3,14 +3,6 @@
package
net.mamoe.mirai.utils.io
package
net.mamoe.mirai.utils.io
import
kotlinx.io.core.*
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.KnownPacketId.*
import
net.mamoe.mirai.network.protocol.tim.packet.action.*
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
(
fun
ByteReadPacket
.
readRemainingBytes
(
...
@@ -23,66 +15,6 @@ fun ByteReadPacket.readIoBuffer(
...
@@ -23,66 +15,6 @@ fun ByteReadPacket.readIoBuffer(
fun
ByteReadPacket
.
readIoBuffer
(
n
:
Number
)
=
this
.
readIoBuffer
(
n
.
toInt
())
fun
ByteReadPacket
.
readIoBuffer
(
n
:
Number
)
=
this
.
readIoBuffer
(
n
.
toInt
())
//必须消耗完 packet
fun
ByteReadPacket
.
parseServerPacket
(
size
:
Int
):
ServerPacket
{
discardExact
(
3
)
val
id
=
readUShort
()
val
sequenceId
=
readUShort
()
discardExact
(
7
)
//4 for qq number, 3 for 0x00 0x00 0x00. 但更可能是应该 discard 8
return
when
(
PacketId
(
id
))
{
TOUCH
->
TouchResponsePacket
.
Encrypted
(
this
)
LOGIN
->
//todo 不要用size分析
when
{
size
==
271
||
size
==
207
->
LoginResponseKeyExchangeResponsePacket
.
Encrypted
(
this
)
size
==
871
->
LoginResponseCaptchaInitPacket
.
Encrypted
(
this
)
size
>
700
->
LoginResponseSuccessPacket
.
Encrypted
(
this
)
else
->
LoginResponseFailedPacket
(
when
(
size
)
{
135
->
{
//包数据错误. 目前怀疑是 tlv0006
this
.
readRemainingBytes
().
cutTail
(
1
).
decryptBy
(
TIMProtocol
.
shareKey
).
read
{
discardExact
(
51
)
MiraiLogger
.
error
(
"Internal error: "
+
readUShortLVString
())
//抱歉,请重新输入密码。
}
LoginResult
.
INTERNAL_ERROR
}
319
,
351
->
LoginResult
.
WRONG_PASSWORD
//135 -> LoginState.RETYPE_PASSWORD
63
->
LoginResult
.
BLOCKED
263
->
LoginResult
.
UNKNOWN_QQ_NUMBER
279
,
495
,
551
,
487
->
LoginResult
.
DEVICE_LOCK
343
,
359
->
LoginResult
.
TAKEN_BACK
else
->
LoginResult
.
UNKNOWN
},
this
)
}
SESSION_KEY
->
SessionKeyResponsePacket
.
Encrypted
(
this
)
CHANGE_ONLINE_STATUS
->
ServerLoginSuccessPacket
(
this
)
CAPTCHA
->
ServerCaptchaPacket
.
Encrypted
(
this
)
SERVER_EVENT_1
,
SERVER_EVENT_2
->
ServerEventPacket
.
Raw
.
Encrypted
(
this
,
PacketId
(
id
),
sequenceId
)
FRIEND_ONLINE_STATUS_CHANGE
->
FriendOnlineStatusChangedPacket
.
Encrypted
(
this
)
S_KEY
->
ResponsePacket
.
Encrypted
<
RequestSKeyPacket
.
Response
>(
this
)
ACCOUNT_INFO
->
ResponsePacket
.
Encrypted
<
RequestAccountInfoPacket
.
Response
>(
this
)
SEND_GROUP_MESSAGE
->
ResponsePacket
.
Encrypted
<
SendGroupMessagePacket
.
Response
>(
this
)
SEND_FRIEND_MESSAGE
->
ResponsePacket
.
Encrypted
<
SendFriendMessagePacket
.
Response
>(
this
)
CAN_ADD_FRIEND
->
ResponsePacket
.
Encrypted
<
CanAddFriendPacket
.
Response
>(
this
)
HEARTBEAT
->
ResponsePacket
.
Encrypted
<
HeartbeatPacket
.
Response
>(
this
)
GROUP_IMAGE_ID
->
ResponsePacket
.
Encrypted
<
GroupImageIdRequestPacket
.
Response
>(
this
)
FRIEND_IMAGE_ID
->
ResponsePacket
.
Encrypted
<
FriendImageIdRequestPacket
.
Response
>(
this
)
REQUEST_PROFILE_DETAILS
->
ResponsePacket
.
Encrypted
<
RequestProfileDetailsPacket
.
Response
>(
this
)
// 0x01_BDu -> EventResponse.Encrypted<SubmitImageFilenamePacket.Response>(this)
else
->
UnknownServerPacket
.
Encrypted
(
this
,
PacketId
(
id
),
sequenceId
)
}.
applySequence
(
sequenceId
)
}
fun
Input
.
readIP
():
String
=
buildString
(
4
+
3
)
{
fun
Input
.
readIP
():
String
=
buildString
(
4
+
3
)
{
repeat
(
4
)
{
repeat
(
4
)
{
val
byte
=
readUByte
()
val
byte
=
readUByte
()
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/OutputUtils.kt
View file @
bd9cf3bf
...
@@ -7,6 +7,8 @@ import kotlinx.io.pool.useInstance
...
@@ -7,6 +7,8 @@ import kotlinx.io.pool.useInstance
import
net.mamoe.mirai.contact.GroupId
import
net.mamoe.mirai.contact.GroupId
import
net.mamoe.mirai.contact.GroupInternalId
import
net.mamoe.mirai.contact.GroupInternalId
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.TIMProtocol
import
net.mamoe.mirai.network.protocol.tim.packet.DecrypterByteArray
import
net.mamoe.mirai.network.protocol.tim.packet.login.PrivateKey
import
net.mamoe.mirai.utils.*
import
net.mamoe.mirai.utils.*
import
net.mamoe.mirai.utils.internal.coerceAtMostOrFail
import
net.mamoe.mirai.utils.internal.coerceAtMostOrFail
import
kotlin.random.Random
import
kotlin.random.Random
...
@@ -20,6 +22,7 @@ fun BytePacketBuilder.writeQQ(qq: Long) = this.writeUInt(qq.toUInt())
...
@@ -20,6 +22,7 @@ fun BytePacketBuilder.writeQQ(qq: Long) = this.writeUInt(qq.toUInt())
fun
BytePacketBuilder
.
writeQQ
(
qq
:
UInt
)
=
this
.
writeUInt
(
qq
)
fun
BytePacketBuilder
.
writeQQ
(
qq
:
UInt
)
=
this
.
writeUInt
(
qq
)
fun
BytePacketBuilder
.
writeGroup
(
groupId
:
GroupId
)
=
this
.
writeUInt
(
groupId
.
value
)
fun
BytePacketBuilder
.
writeGroup
(
groupId
:
GroupId
)
=
this
.
writeUInt
(
groupId
.
value
)
fun
BytePacketBuilder
.
writeGroup
(
groupInternalId
:
GroupInternalId
)
=
this
.
writeUInt
(
groupInternalId
.
value
)
fun
BytePacketBuilder
.
writeGroup
(
groupInternalId
:
GroupInternalId
)
=
this
.
writeUInt
(
groupInternalId
.
value
)
fun
BytePacketBuilder
.
writeFully
(
value
:
DecrypterByteArray
)
=
this
.
writeFully
(
value
.
value
)
fun
BytePacketBuilder
.
writeShortLVByteArray
(
byteArray
:
ByteArray
)
{
fun
BytePacketBuilder
.
writeShortLVByteArray
(
byteArray
:
ByteArray
)
{
this
.
writeShort
(
byteArray
.
size
.
toShort
())
this
.
writeShort
(
byteArray
.
size
.
toShort
())
...
@@ -109,9 +112,11 @@ fun BytePacketBuilder.encryptAndWrite(key: IoBuffer, encoder: BytePacketBuilder.
...
@@ -109,9 +112,11 @@ fun BytePacketBuilder.encryptAndWrite(key: IoBuffer, encoder: BytePacketBuilder.
encryptAndWrite
(
it
,
encoder
)
encryptAndWrite
(
it
,
encoder
)
}
}
fun
BytePacketBuilder
.
encryptAndWrite
(
key
:
DecrypterByteArray
,
encoder
:
BytePacketBuilder
.()
->
Unit
)
=
encryptAndWrite
(
key
.
value
,
encoder
)
fun
BytePacketBuilder
.
encryptAndWrite
(
keyHex
:
String
,
encoder
:
BytePacketBuilder
.()
->
Unit
)
=
encryptAndWrite
(
keyHex
.
hexToBytes
(),
encoder
)
fun
BytePacketBuilder
.
encryptAndWrite
(
keyHex
:
String
,
encoder
:
BytePacketBuilder
.()
->
Unit
)
=
encryptAndWrite
(
keyHex
.
hexToBytes
(),
encoder
)
fun
BytePacketBuilder
.
writeTLV0006
(
qq
:
UInt
,
password
:
String
,
loginTime
:
Int
,
loginIP
:
String
,
privateKey
:
ByteArra
y
)
{
fun
BytePacketBuilder
.
writeTLV0006
(
qq
:
UInt
,
password
:
String
,
loginTime
:
Int
,
loginIP
:
String
,
privateKey
:
PrivateKe
y
)
{
val
firstMD5
=
md5
(
password
)
val
firstMD5
=
md5
(
password
)
val
secondMD5
=
md5
(
firstMD5
+
byteArrayOf
(
0
,
0
,
0
,
0
)
+
qq
.
toUInt
().
toByteArray
())
val
secondMD5
=
md5
(
firstMD5
+
byteArrayOf
(
0
,
0
,
0
,
0
)
+
qq
.
toUInt
().
toByteArray
())
...
@@ -130,7 +135,7 @@ fun BytePacketBuilder.writeTLV0006(qq: UInt, password: String, loginTime: Int, l
...
@@ -130,7 +135,7 @@ fun BytePacketBuilder.writeTLV0006(qq: UInt, password: String, loginTime: Int, l
writeZero
(
8
)
writeZero
(
8
)
writeHex
(
"00 10"
)
//这两个hex是passwordSubmissionTLV2的末尾
writeHex
(
"00 10"
)
//这两个hex是passwordSubmissionTLV2的末尾
writeHex
(
"15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B"
)
//16
writeHex
(
"15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B"
)
//16
writeFully
(
privateKey
)
writeFully
(
privateKey
.
value
)
}
}
}
}
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/EventDispatcher.kt
View file @
bd9cf3bf
package
net.mamoe.mirai.event
package
net.mamoe.mirai.event
import
kotlinx.coroutines.CoroutineDispatcher
import
kotlinx.coroutines.CoroutineDispatcher
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.asCoroutineDispatcher
import
java.util.concurrent.Executors
internal
actual
val
EventDispatcher
:
CoroutineDispatcher
get
()
=
Dispatchers
.
Default
internal
actual
val
EventDispatcher
:
CoroutineDispatcher
=
Executors
.
newFixedThreadPool
(
2
).
asCoroutineDispatcher
()
\ No newline at end of file
\ No newline at end of file
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/CaptchaResolverJvm.kt
View file @
bd9cf3bf
package
net.mamoe.mirai.utils
package
net.mamoe.mirai.utils
import
io.ktor.util.KtorExperimentalAPI
import
io.ktor.util.cio.writeChannel
import
io.ktor.util.cio.writeChannel
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.sync.Mutex
import
kotlinx.coroutines.sync.Mutex
...
@@ -19,14 +20,15 @@ import kotlin.math.min
...
@@ -19,14 +20,15 @@ import kotlin.math.min
*
*
* @return 用户输入得到的验证码
* @return 用户输入得到的验证码
*/
*/
@KtorExperimentalAPI
internal
actual
suspend
fun
solveCaptcha
(
captchaBuffer
:
IoBuffer
):
String
?
=
captchaLock
.
withLock
{
internal
actual
suspend
fun
solveCaptcha
(
captchaBuffer
:
IoBuffer
):
String
?
=
captchaLock
.
withLock
{
val
tempFile
:
File
=
createTempFile
(
suffix
=
".png"
).
apply
{
deleteOnExit
()
}
val
tempFile
:
File
=
createTempFile
(
suffix
=
".png"
).
apply
{
deleteOnExit
()
}
withContext
(
Dispatchers
.
IO
)
{
withContext
(
Dispatchers
.
IO
)
{
tempFile
.
createNewFile
()
tempFile
.
createNewFile
()
@Suppress
(
"EXPERIMENTAL_API_USAGE"
)
@Suppress
(
"EXPERIMENTAL_API_USAGE"
)
MiraiLogger
.
info
(
"需要验证码登录, 验证码为 4 字母"
)
try
{
try
{
tempFile
.
writeChannel
().
writeFully
(
captchaBuffer
)
tempFile
.
writeChannel
().
writeFully
(
captchaBuffer
)
MiraiLogger
.
info
(
"需要验证码登录, 验证码为 4 字母"
)
MiraiLogger
.
info
(
"若看不清字符图片, 请查看 ${tempFile.absolutePath}"
)
MiraiLogger
.
info
(
"若看不清字符图片, 请查看 ${tempFile.absolutePath}"
)
}
catch
(
e
:
Exception
)
{
}
catch
(
e
:
Exception
)
{
MiraiLogger
.
info
(
"无法写出验证码文件(${e.message}), 请尝试查看以上字符图片"
)
MiraiLogger
.
info
(
"无法写出验证码文件(${e.message}), 请尝试查看以上字符图片"
)
...
...
mirai-demos/mirai-demo-gentleman/build.gradle
View file @
bd9cf3bf
...
@@ -2,12 +2,11 @@ apply plugin: "kotlin"
...
@@ -2,12 +2,11 @@ apply plugin: "kotlin"
apply
plugin:
"java"
apply
plugin:
"java"
dependencies
{
dependencies
{
implementation
project
(
":mirai-core"
)
api
project
(
":mirai-core"
)
runtime
files
(
"../../mirai-core/build/classes/kotlin/jvm/main"
)
// mpp targeting android limitation
api
group:
'org.jetbrains.kotlin'
,
name:
'kotlin-stdlib-jdk8'
,
version:
kotlin_version
api
group:
'org.jetbrains.kotlin'
,
name:
'kotlin-stdlib-jdk8'
,
version:
kotlin_version
api
group:
'org.jetbrains.kotlinx'
,
name:
'kotlinx-coroutines-core'
,
version:
coroutines_version
api
group:
'org.jetbrains.kotlinx'
,
name:
'kotlinx-coroutines-core'
,
version:
coroutines_version
compile
group:
'com.alibaba'
,
name:
'fastjson'
,
version:
'1.2.62'
compile
group:
'com.alibaba'
,
name:
'fastjson'
,
version:
'1.2.62'
implementation
'org.jsoup:jsoup:1.12.1'
implementation
'org.jsoup:jsoup:1.12.1'
implementation
files
(
'./lib/ExImageGallery.jar'
)
}
}
mirai-demos/mirai-demo-gentleman/lib/ExImageGallery.jar
deleted
100644 → 0
View file @
6f498554
File deleted
mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt
View file @
bd9cf3bf
...
@@ -33,8 +33,8 @@ private fun readTestAccount(): BotAccount? {
...
@@ -33,8 +33,8 @@ private fun readTestAccount(): BotAccount? {
suspend
fun
main
()
{
suspend
fun
main
()
{
val
bot
=
Bot
(
val
bot
=
Bot
(
readTestAccount
()
?:
BotAccount
(
readTestAccount
()
?:
BotAccount
(
id
=
1994701121
u
,
id
=
913366033
u
,
password
=
"
123456
"
password
=
"
a18260132383
"
)
)
).
apply
{
login
().
requireSuccess
()
}
).
apply
{
login
().
requireSuccess
()
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment