Commit 512d27b8 authored by Him188moe's avatar Him188moe

Updated robot & network structure

parent bde4610f
...@@ -4,7 +4,6 @@ import lombok.Getter; ...@@ -4,7 +4,6 @@ import lombok.Getter;
import net.mamoe.mirai.event.MiraiEventManager; import net.mamoe.mirai.event.MiraiEventManager;
import net.mamoe.mirai.event.events.server.ServerDisableEvent; import net.mamoe.mirai.event.events.server.ServerDisableEvent;
import net.mamoe.mirai.event.events.server.ServerEnableEvent; import net.mamoe.mirai.event.events.server.ServerEnableEvent;
import net.mamoe.mirai.network.RobotNetworkHandler;
import net.mamoe.mirai.network.packet.login.LoginState; import net.mamoe.mirai.network.packet.login.LoginState;
import net.mamoe.mirai.task.MiraiTaskManager; import net.mamoe.mirai.task.MiraiTaskManager;
import net.mamoe.mirai.utils.LoggerTextFormat; import net.mamoe.mirai.utils.LoggerTextFormat;
...@@ -36,7 +35,7 @@ public class MiraiServer { ...@@ -36,7 +35,7 @@ public class MiraiServer {
@Getter //is running under UNIX @Getter //is running under UNIX
private boolean unix; private boolean unix;
@Getter//file path @Getter//file pathq
public File parentFolder; public File parentFolder;
@Getter @Getter
...@@ -121,8 +120,7 @@ public class MiraiServer { ...@@ -121,8 +120,7 @@ public class MiraiServer {
this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> { this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> {
try { try {
Robot robot = new Robot(section); Robot robot = new Robot(section);
RobotNetworkHandler robotNetworkHandler = robot.getNetworkHandler(); robot.network.tryLogin$mirai_core(state -> {
robotNetworkHandler.tryLogin$mirai_core(state -> {
if (state == LoginState.SUCCEED) { if (state == LoginState.SUCCEED) {
Robot.instances.add(robot); Robot.instances.add(robot);
} else { } else {
......
...@@ -5,79 +5,95 @@ import net.mamoe.mirai.contact.Group; ...@@ -5,79 +5,95 @@ import net.mamoe.mirai.contact.Group;
import net.mamoe.mirai.contact.QQ; import net.mamoe.mirai.contact.QQ;
import net.mamoe.mirai.network.RobotNetworkHandler; import net.mamoe.mirai.network.RobotNetworkHandler;
import net.mamoe.mirai.utils.ContactList; import net.mamoe.mirai.utils.ContactList;
import net.mamoe.mirai.utils.RobotAccount;
import net.mamoe.mirai.utils.config.MiraiConfigSection; import net.mamoe.mirai.utils.config.MiraiConfigSection;
import org.jetbrains.annotations.NotNull;
import java.io.Closeable; import java.io.Closeable;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class Robot implements Closeable { /**
* Robot that is the base of the whole program.
* It contains a {@link ContactSystem}, which manage contacts such as {@link QQ} and {@link Group}.
*/
public final class Robot implements Closeable {
public static final List<Robot> instances = Collections.synchronizedList(new LinkedList<>()); public static final List<Robot> instances = Collections.synchronizedList(new LinkedList<>());
private final long qqNumber; public final RobotAccount account;
private final String password;
@Getter public final ContactSystem contacts = new ContactSystem();
private final RobotNetworkHandler networkHandler;
public final RobotNetworkHandler network;
/** /**
* Ref list * Robot 联系人管理.
*
* @see Robot#contacts
*/ */
@Getter public final class ContactSystem {
private final List<String> owners; private final ContactList<Group> groups = new ContactList<>();
private final ContactList<QQ> qqs = new ContactList<>();
private final ContactList<Group> groups = new ContactList<>(); private ContactSystem() {
private final ContactList<QQ> qqs = new ContactList<>();
public void close() { }
this.networkHandler.close();
this.owners.clear(); public QQ getQQ(long qqNumber) {
this.groups.values().forEach(Group::close); if (!this.qqs.containsKey(qqNumber)) {
this.groups.clear(); this.qqs.put(qqNumber, new QQ(Robot.this, qqNumber));
this.qqs.clear(); }
return this.qqs.get(qqNumber);
}
public Group getGroupByNumber(long groupNumber) {
if (!this.groups.containsKey(groupNumber)) {
this.groups.put(groupNumber, new Group(Robot.this, groupNumber));
}
return groups.get(groupNumber);
}
public Group getGroupById(long groupId) {
return getGroupByNumber(Group.Companion.groupIdToNumber(groupId));
}
} }
/**
* Ref list
*/
@Getter
private final List<String> owners;
public boolean isOwnBy(String ownerName) { public boolean isOwnBy(String ownerName) {
return owners.contains(ownerName); return owners.contains(ownerName);
} }
public long getQQNumber() {
return qqNumber;
}
public Robot(MiraiConfigSection<Object> data) throws Throwable { public Robot(MiraiConfigSection<Object> data) throws Throwable {
this( this(
data.getLongOrThrow("account", () -> new IllegalArgumentException("account")), new RobotAccount(
data.getStringOrThrow("password", () -> new IllegalArgumentException("password")), data.getLongOrThrow("account", () -> new IllegalArgumentException("account")),
data.getStringOrThrow("password", () -> new IllegalArgumentException("password"))
),
data.getAsOrDefault("owners", ArrayList::new) data.getAsOrDefault("owners", ArrayList::new)
); );
} }
public Robot(long qqNumber, String password, List<String> owners) { public Robot(@NotNull RobotAccount account, @NotNull List<String> owners) {
this.qqNumber = qqNumber; Objects.requireNonNull(account);
this.password = password; Objects.requireNonNull(owners);
this.account = account;
this.owners = Collections.unmodifiableList(owners); this.owners = Collections.unmodifiableList(owners);
this.networkHandler = new RobotNetworkHandler(this, this.qqNumber, this.password); this.network = new RobotNetworkHandler(this);
} }
public QQ getQQ(long qqNumber) {
if (!this.qqs.containsKey(qqNumber)) {
this.qqs.put(qqNumber, new QQ(qqNumber));
}
return this.qqs.get(qqNumber);
}
public Group getGroup(long groupNumber) { public void close() {
if (!this.groups.containsKey(groupNumber)) { this.network.close();
this.groups.put(groupNumber, new Group(groupNumber)); this.owners.clear();
} this.contacts.groups.values().forEach(Group::close);
return groups.get(groupNumber); this.contacts.groups.clear();
this.contacts.qqs.clear();
} }
public Group getGroupByGroupId(long groupId) {
return getGroup(Group.Companion.groupIdToNumber(groupId));
}
} }
package net.mamoe.mirai.contact package net.mamoe.mirai.contact
import net.mamoe.mirai.Robot
import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.Message
import net.mamoe.mirai.message.defaults.PlainText import net.mamoe.mirai.message.defaults.PlainText
/** /**
* A contact is a [QQ] or a [Group] for one particular [Robot] instance only. * A contact is a [QQ] or a [Group] for one particular [Robot] instance only.
* *
* @param robot Owner [Robot]
* @author Him188moe * @author Him188moe
*/ */
abstract class Contact(val number: Long) { abstract class Contact(val robot: Robot, val number: Long) {
/** /**
* Async * Async
......
package net.mamoe.mirai.contact package net.mamoe.mirai.contact
import net.mamoe.mirai.Robot
import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.Message
import net.mamoe.mirai.utils.ContactList import net.mamoe.mirai.utils.ContactList
import java.io.Closeable import java.io.Closeable
class Group(number: Long) : Contact(number), Closeable { class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable {
val groupId = groupNumberToId(number) val groupId = groupNumberToId(number)
val members = ContactList<QQ>() val members = ContactList<QQ>()
override fun sendMessage(message: Message) { override fun sendMessage(message: Message) {
robot.network.packetSystem.sendGroupMessage(this, message)
} }
override fun sendXMLMessage(message: String) { override fun sendXMLMessage(message: String) {
......
package net.mamoe.mirai.contact package net.mamoe.mirai.contact
import net.mamoe.mirai.Robot
import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.Message
import net.mamoe.mirai.message.defaults.At import net.mamoe.mirai.message.defaults.At
/** /**
* A QQ instance helps you to receive message from or send message to.
* Notice that one QQ instance belong to one [Robot], that is, QQ instances from different [Robot] are NOT the same.
*
* @author Him188moe * @author Him188moe
*/ */
class QQ(number: Long) : Contact(number) { class QQ(robot: Robot, number: Long) : Contact(robot, number) {
override fun sendMessage(message: Message) { override fun sendMessage(message: Message) {
robot.network.packetSystem.sendFriendMessage(this, message)
} }
override fun sendXMLMessage(message: String) { override fun sendXMLMessage(message: String) {
......
...@@ -28,26 +28,44 @@ interface Protocol { ...@@ -28,26 +28,44 @@ interface Protocol {
const val head = "02" const val head = "02"
const val ver = "37 13 " const val ver = "37 13"
const val fixVer = "03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00 " const val fixVer = "03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00"
const val tail = " 03" const val tail = "03"
const val _fixVer = "02 00 00 00 01 01 01 00 00 68 20 " /**
const val _0825data0 = "00 18 00 16 00 01 " * _fixVer
const val _0825data2 = "00 00 04 53 00 00 00 01 00 00 15 85 " */
const val _0825key = "A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D" const val fixVer2 = "02 00 00 00 01 01 01 00 00 68 20"
/**
* 0825data1
*/
const val constantData0 = "00 18 00 16 00 01 "
/**
* 0825data2
*/
const val constantData1 = "00 00 04 53 00 00 00 01 00 00 15 85 "
const val key0825 = "A4 F1 91 88 C9 82 14 99 0C 9E 56 55 91 23 C8 3D"
const val redirectionKey = "A8 F2 14 5F 58 12 60 AF 07 63 97 D6 76 B2 1A 3B" const val redirectionKey = "A8 F2 14 5F 58 12 60 AF 07 63 97 D6 76 B2 1A 3B"
const val publicKey = "02 6D 28 41 D2 A5 6F D2 FC 3E 2A 1F 03 75 DE 6E 28 8F A8 19 3E 5F 16 49 D3" const val publicKey = "02 6D 28 41 D2 A5 6F D2 FC 3E 2A 1F 03 75 DE 6E 28 8F A8 19 3E 5F 16 49 D3"
const val shareKey = "1A E9 7F 7D C9 73 75 98 AC 02 E0 80 5F A9 C6 AF" const val shareKey = "1A E9 7F 7D C9 73 75 98 AC 02 E0 80 5F A9 C6 AF"
const val _0836fix = "06 A9 12 97 B7 F8 76 25 AF AF D3 EA B4 C8 BC E7 " const val fix0836 = "06 A9 12 97 B7 F8 76 25 AF AF D3 EA B4 C8 BC E7 "
const val _00BaKey = "C1 9C B8 C8 7B 8C 81 BA 9E 9E 7A 89 E1 7A EC 94" const val key00BA = "C1 9C B8 C8 7B 8C 81 BA 9E 9E 7A 89 E1 7A EC 94"
const val _00BaFixKey = "69 20 D1 14 74 F5 B3 93 E4 D5 02 B3 71 1A CD 2A" const val key00BAFix = "69 20 D1 14 74 F5 B3 93 E4 D5 02 B3 71 1A CD 2A"
const val encryptKey = "“BA 42 FF 01 CF B4 FF D2 12 F0 6E A7 1B 7C B3 08”" const val encryptKey = "“BA 42 FF 01 CF B4 FF D2 12 F0 6E A7 1B 7C B3 08”"
const val _0836_622_fix2 = "00 15 00 30 00 01 01 27 9B C7 F5 00 10 65 03 FD 8B 00 00 00 00 00 00 00 00 00 00 00 00 02 90 49 55 33 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B"; /**
const val _0836_622_fix1 = "03 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 01 01 03 00 19"; * 0836_622_fix2
const val _0836key1 = "EF 4A 36 6A 16 A8 E6 3D 2E EA BD 1F 98 C1 3C DA" */
const val passwordSubmissionKey2 = "00 15 00 30 00 01 01 27 9B C7 F5 00 10 65 03 FD 8B 00 00 00 00 00 00 00 00 00 00 00 00 02 90 49 55 33 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B";
/**
* 0836_622_fix1
*/
const val passwordSubmissionKey1 = "03 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 01 01 03 00 19";
/**
* fix_0836_1
*/
const val key0836 = "EF 4A 36 6A 16 A8 E6 3D 2E EA BD 1F 98 C1 3C DA"
private val hexToByteArrayCacheMap: MutableMap<Int, ByteArray> = mutableMapOf() private val hexToByteArrayCacheMap: MutableMap<Int, ByteArray> = mutableMapOf()
......
...@@ -2,33 +2,36 @@ package net.mamoe.mirai.network ...@@ -2,33 +2,36 @@ package net.mamoe.mirai.network
import net.mamoe.mirai.Robot import net.mamoe.mirai.Robot
import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.event.events.qq.FriendMessageEvent import net.mamoe.mirai.event.events.qq.FriendMessageEvent
import net.mamoe.mirai.event.events.robot.RobotLoginSucceedEvent import net.mamoe.mirai.event.events.robot.RobotLoginSucceedEvent
import net.mamoe.mirai.message.Message
import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.network.packet.*
import net.mamoe.mirai.network.packet.login.* import net.mamoe.mirai.network.packet.login.*
import net.mamoe.mirai.network.packet.message.ClientSendGroupMessagePacket
import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket
import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket
import net.mamoe.mirai.task.MiraiThreadPool import net.mamoe.mirai.task.MiraiThreadPool
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.ClientLoginStatus
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.getGTK
import net.mamoe.mirai.utils.lazyEncode
import java.io.Closeable import java.io.Closeable
import java.net.DatagramPacket import java.net.DatagramPacket
import java.net.DatagramSocket import java.net.DatagramSocket
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
/** /**
* A RobotNetworkHandler is used to connect with Tencent servers. * A RobotNetworkHandler is used to connect with Tencent servers.
* *
* @author Him188moe * @author Him188moe
*/ */
@ExperimentalUnsignedTypes @Suppress("EXPERIMENTAL_API_USAGE")//to simplify code
internal class RobotNetworkHandler(val robot: Robot, val number: Long, private val password: String) : Closeable { internal class RobotNetworkHandler(private val robot: Robot) : Closeable {
var socket: DatagramSocket = DatagramSocket((15314 + Math.random() * 100).toInt()) private var socket: DatagramSocket = DatagramSocket((15314 + Math.random() * 100).toInt())
var serverIP: String = "" private var serverIP: String = ""
set(value) { set(value) {
serverAddress = InetSocketAddress(value, 8000) serverAddress = InetSocketAddress(value, 8000)
field = value field = value
...@@ -45,7 +48,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v ...@@ -45,7 +48,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
private lateinit var loginIP: String private lateinit var loginIP: String
private var tgtgtKey: ByteArray? = null private var tgtgtKey: ByteArray? = null
private var tlv0105: ByteArray private var tlv0105: ByteArray
private lateinit var _0828_rec_decr_key: ByteArray private lateinit var sessionResponseDecryptionKey: ByteArray
private var verificationCodeSequence: Int = 0//这两个验证码使用 private var verificationCodeSequence: Int = 0//这两个验证码使用
private var verificationCodeCache: ByteArray? = null//每次包只发一部分验证码来 private var verificationCodeCache: ByteArray? = null//每次包只发一部分验证码来
...@@ -82,10 +85,6 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v ...@@ -82,10 +85,6 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
} }
} }
@ExperimentalUnsignedTypes
private var md5_32: ByteArray = getRandomKey(32)
/** /**
* Try to login to server * Try to login to server
*/ */
...@@ -110,7 +109,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v ...@@ -110,7 +109,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
if (loginHook != null) { if (loginHook != null) {
this.loginHook = loginHook this.loginHook = loginHook
} }
this.sendPacket(ClientTouchPacket(this.number, this.serverIP)) this.sendPacket(ClientTouchPacket(this.robot.account.qqNumber, this.serverIP))
} }
private fun restartSocket() { private fun restartSocket() {
...@@ -151,20 +150,20 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v ...@@ -151,20 +150,20 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
packet.decode() packet.decode()
MiraiLogger info "Packet received: $packet" MiraiLogger info "Packet received: $packet"
if (packet is ServerEventPacket) { if (packet is ServerEventPacket) {
sendPacket(ClientMessageResponsePacket(this.number, packet.packetId, this.sessionKey, packet.eventIdentity)) sendPacket(ClientMessageResponsePacket(this.robot.account.qqNumber, packet.packetId, this.sessionKey, packet.eventIdentity))
} }
when (packet) { when (packet) {
is ServerTouchResponsePacket -> { is ServerTouchResponsePacket -> {
if (packet.serverIP != null) {//redirection if (packet.serverIP != null) {//redirection
serverIP = packet.serverIP!! serverIP = packet.serverIP!!
//connect(packet.serverIP!!) //connect(packet.serverIP!!)
sendPacket(ClientServerRedirectionPacket(packet.serverIP!!, number)) sendPacket(ClientServerRedirectionPacket(packet.serverIP!!, this.robot.account.qqNumber))
} else {//password submission } else {//password submission
this.loginIP = packet.loginIP this.loginIP = packet.loginIP
this.loginTime = packet.loginTime this.loginTime = packet.loginTime
this.token0825 = packet.token0825 this.token0825 = packet.token0825
this.tgtgtKey = packet.tgtgtKey this.tgtgtKey = packet.tgtgtKey
sendPacket(ClientPasswordSubmissionPacket(this.number, this.password, packet.loginTime, packet.loginIP, packet.tgtgtKey, packet.token0825)) sendPacket(ClientPasswordSubmissionPacket(this.robot.account.qqNumber, this.robot.account.password, packet.loginTime, packet.loginIP, packet.tgtgtKey, packet.token0825))
} }
} }
...@@ -182,7 +181,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v ...@@ -182,7 +181,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
if (packet.unknownBoolean != null && packet.unknownBoolean!!) { if (packet.unknownBoolean != null && packet.unknownBoolean!!) {
this.verificationCodeSequence = 1 this.verificationCodeSequence = 1
sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, this.number, this.token0825, this.verificationCodeSequence, this.token00BA)) sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, this.robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA))
} }
} }
...@@ -190,7 +189,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v ...@@ -190,7 +189,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
is ServerVerificationCodeRepeatPacket -> {//todo 这个名字正确么 is ServerVerificationCodeRepeatPacket -> {//todo 这个名字正确么
this.tgtgtKey = packet.tgtgtKeyUpdate this.tgtgtKey = packet.tgtgtKeyUpdate
this.token00BA = packet.token00BA this.token00BA = packet.token00BA
sendPacket(ClientLoginResendPacket3105(this.number, this.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA)) sendPacket(ClientLoginResendPacket3105(this.robot.account.qqNumber, this.robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA))
} }
is ServerVerificationCodeTransmissionPacket -> { is ServerVerificationCodeTransmissionPacket -> {
...@@ -210,26 +209,26 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v ...@@ -210,26 +209,26 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
this.verificationCodeCache this.verificationCodeCache
TODO("验证码好了") TODO("验证码好了")
} else { } else {
sendPacket(ClientVerificationCodeTransmissionRequestPacket(this.verificationCodeCacheCount, this.number, this.token0825, this.verificationCodeSequence, this.token00BA)) sendPacket(ClientVerificationCodeTransmissionRequestPacket(this.verificationCodeCacheCount, this.robot.account.qqNumber, this.token0825, this.verificationCodeSequence, this.token00BA))
} }
} }
is ServerLoginResponseSuccessPacket -> { is ServerLoginResponseSuccessPacket -> {
this._0828_rec_decr_key = packet._0828_rec_decr_key this.sessionResponseDecryptionKey = packet._0828_rec_decr_key
sendPacket(ClientSessionRequestPacket(this.number, this.serverIP, this.loginIP, this.md5_32, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105)) sendPacket(ClientSessionRequestPacket(this.robot.account.qqNumber, this.serverIP, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105))
} }
//是ClientPasswordSubmissionPacket之后服务器回复的 //是ClientPasswordSubmissionPacket之后服务器回复的
is ServerLoginResponseResendPacket -> { is ServerLoginResponseResendPacket -> {
if (packet.tokenUnknown != null) { //if (packet.tokenUnknown != null) {
//this.token00BA = packet.token00BA!! //this.token00BA = packet.token00BA!!
//println("token00BA changed!!! to " + token00BA.toUByteArray()) //println("token00BA changed!!! to " + token00BA.toUByteArray())
} //}
if (packet.flag == ServerLoginResponseResendPacket.Flag.`08 36 31 03`) { if (packet.flag == ServerLoginResponseResendPacket.Flag.`08 36 31 03`) {
this.tgtgtKey = packet.tgtgtKey this.tgtgtKey = packet.tgtgtKey
sendPacket(ClientLoginResendPacket3104( sendPacket(ClientLoginResendPacket3104(
this.number, this.robot.account.qqNumber,
this.password, this.robot.account.password,
this.loginTime, this.loginTime,
this.loginIP, this.loginIP,
this.tgtgtKey!!, this.tgtgtKey!!,
...@@ -242,8 +241,8 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v ...@@ -242,8 +241,8 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
)) ))
} else { } else {
sendPacket(ClientLoginResendPacket3106( sendPacket(ClientLoginResendPacket3106(
this.number, this.robot.account.qqNumber,
this.password, this.robot.account.password,
this.loginTime, this.loginTime,
this.loginIP, this.loginIP,
this.tgtgtKey!!, this.tgtgtKey!!,
...@@ -261,7 +260,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v ...@@ -261,7 +260,7 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
is ServerSessionKeyResponsePacket -> { is ServerSessionKeyResponsePacket -> {
this.sessionKey = packet.sessionKey this.sessionKey = packet.sessionKey
MiraiThreadPool.getInstance().scheduleWithFixedDelay({ MiraiThreadPool.getInstance().scheduleWithFixedDelay({
sendPacket(ClientHeartbeatPacket(this.number, this.sessionKey)) sendPacket(ClientHeartbeatPacket(this.robot.account.qqNumber, this.sessionKey))
}, 90000, 90000, TimeUnit.MILLISECONDS) }, 90000, 90000, TimeUnit.MILLISECONDS)
RobotLoginSucceedEvent(robot).broadcast() RobotLoginSucceedEvent(robot).broadcast()
...@@ -270,24 +269,24 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v ...@@ -270,24 +269,24 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
}, 2, TimeUnit.SECONDS) }, 2, TimeUnit.SECONDS)
this.tlv0105 = packet.tlv0105 this.tlv0105 = packet.tlv0105
sendPacket(ClientLoginStatusPacket(this.number, this.sessionKey, ClientLoginStatus.ONLINE)) sendPacket(ClientChangeOnlineStatusPacket(this.robot.account.qqNumber, this.sessionKey, ClientLoginStatus.ONLINE))
} }
is ServerLoginSuccessPacket -> { is ServerLoginSuccessPacket -> {
loginState = LoginState.SUCCEED loginState = LoginState.SUCCEED
sendPacket(ClientSKeyRequestPacket(this.number, this.sessionKey)) sendPacket(ClientSKeyRequestPacket(this.robot.account.qqNumber, this.sessionKey))
} }
is ServerSKeyResponsePacket -> { is ServerSKeyResponsePacket -> {
this.sKey = packet.sKey this.sKey = packet.sKey
this.cookies = "uin=o" + this.number + ";skey=" + this.sKey + ";" this.cookies = "uin=o" + this.robot.account.qqNumber + ";skey=" + this.sKey + ";"
MiraiThreadPool.getInstance().scheduleWithFixedDelay({ MiraiThreadPool.getInstance().scheduleWithFixedDelay({
sendPacket(ClientSKeyRefreshmentRequestPacket(this.number, this.sessionKey)) sendPacket(ClientSKeyRefreshmentRequestPacket(this.robot.account.qqNumber, this.sessionKey))
}, 1800000, 1800000, TimeUnit.MILLISECONDS) }, 1800000, 1800000, TimeUnit.MILLISECONDS)
this.gtk = getGTK(sKey) this.gtk = getGTK(sKey)
sendPacket(ClientAccountInfoRequestPacket(this.number, this.sessionKey)) sendPacket(ClientAccountInfoRequestPacket(this.robot.account.qqNumber, this.sessionKey))
} }
is ServerHeartbeatResponsePacket -> { is ServerHeartbeatResponsePacket -> {
...@@ -304,17 +303,12 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v ...@@ -304,17 +303,12 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
return return
} }
FriendMessageEvent(this.robot, this.robot.getQQ(packet.qq), packet.message) FriendMessageEvent(this.robot, this.robot.contacts.getQQ(packet.qq), packet.message)
} }
is ServerGroupMessageEventPacket -> { is ServerGroupMessageEventPacket -> {
//group message //todo message chain
if (packet.message == "牛逼") { //GroupMessageEvent(this.robot, this.robot.contacts.getGroupByNumber(packet.groupNumber), this.robot.contacts.getQQ(packet.qq), packet.message)
sendPacket(ClientSendGroupMessagePacket(Group.groupNumberToId(packet.groupNumber), this.number, this.sessionKey, "牛逼!"))
}
//todo
//GroupMessageEvent(this.robot, this.robot.getGroup(packet.groupNumber), this.robot.getQQ(packet.qq), packet.message)
} }
is UnknownServerEventPacket -> { is UnknownServerEventPacket -> {
...@@ -329,17 +323,17 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v ...@@ -329,17 +323,17 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
} }
is ServerMessageEventPacketRaw -> onPacketReceived(packet.analyze()) is ServerEventPacket.Raw -> onPacketReceived(packet.distribute())
is ServerVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt()) is ServerVerificationCodePacket.Encrypted -> onPacketReceived(packet.decrypt())
is ServerLoginResponseVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt()) is ServerLoginResponseVerificationCodeInitPacket.Encrypted -> onPacketReceived(packet.decrypt())
is ServerLoginResponseResendPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) is ServerLoginResponseResendPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
is ServerLoginResponseSuccessPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!)) is ServerLoginResponseSuccessPacket.Encrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
is ServerSessionKeyResponsePacketEncrypted -> onPacketReceived(packet.decrypt(this._0828_rec_decr_key)) is ServerSessionKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionResponseDecryptionKey))
is ServerTouchResponsePacketEncrypted -> onPacketReceived(packet.decrypt()) is ServerTouchResponsePacket.Encrypted -> onPacketReceived(packet.decrypt())
is ServerSKeyResponsePacketEncrypted -> onPacketReceived(packet.decrypt(this.sessionKey)) is ServerSKeyResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey))
is ServerAccountInfoResponsePacketEncrypted -> onPacketReceived(packet.decrypt(this.sessionKey)) is ServerAccountInfoResponsePacket.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey))
is ServerMessageEventPacketRawEncoded -> onPacketReceived(packet.decrypt(this.sessionKey)) is ServerEventPacket.Raw.Encrypted -> onPacketReceived(packet.decrypt(this.sessionKey))
is ServerSendFriendMessageResponsePacket, is ServerSendFriendMessageResponsePacket,
...@@ -352,6 +346,21 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v ...@@ -352,6 +346,21 @@ internal class RobotNetworkHandler(val robot: Robot, val number: Long, private v
} }
internal val packetSystem: PacketSystem = PacketSystem()
inner class PacketSystem {
fun sendFriendMessage(qq: QQ, message: Message) {
TODO()
//sendPacket(ClientSendFriendMessagePacket(robot.account.qqNumber, qq.number, sessionKey, message))
}
fun sendGroupMessage(group: Group, message: Message): Unit {
TODO()
//sendPacket(ClientSendGroupMessagePacket(group.groupId, robot.account.qqNumber, sessionKey, message))
}
}
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
fun sendPacket(packet: ClientPacket) { fun sendPacket(packet: ClientPacket) {
MiraiThreadPool.getInstance().submit { MiraiThreadPool.getInstance().submit {
......
package net.mamoe.mirai.network.packet package net.mamoe.mirai.network.packet
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.utils.TEACryptor import net.mamoe.mirai.utils.TEA
import java.io.DataInputStream import java.io.DataInputStream
/** /**
...@@ -18,7 +18,7 @@ class ClientAccountInfoRequestPacket( ...@@ -18,7 +18,7 @@ class ClientAccountInfoRequestPacket(
override fun encode() { override fun encode() {
this.writeRandom(2)//part of packet id this.writeRandom(2)//part of packet id
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex(Protocol._fixVer) this.writeHex(Protocol.fixVer2)
this.encryptAndWrite(sessionKey) { this.encryptAndWrite(sessionKey) {
it.writeByte(0x88) it.writeByte(0x88)
it.writeQQ(qq) it.writeQQ(qq)
...@@ -27,6 +27,7 @@ class ClientAccountInfoRequestPacket( ...@@ -27,6 +27,7 @@ class ClientAccountInfoRequestPacket(
} }
} }
@PacketId("00 5C")
class ServerAccountInfoResponsePacket(input: DataInputStream) : ServerPacket(input) { class ServerAccountInfoResponsePacket(input: DataInputStream) : ServerPacket(input) {
//等级 //等级
//升级剩余活跃天数 //升级剩余活跃天数
...@@ -34,16 +35,13 @@ class ServerAccountInfoResponsePacket(input: DataInputStream) : ServerPacket(inp ...@@ -34,16 +35,13 @@ class ServerAccountInfoResponsePacket(input: DataInputStream) : ServerPacket(inp
override fun decode() { override fun decode() {
} }
}
class ServerAccountInfoResponsePacketEncrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
override fun decode() {
} @PacketId("00 5C")
class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
fun decrypt(sessionKey: ByteArray): ServerAccountInfoResponsePacket { fun decrypt(sessionKey: ByteArray): ServerAccountInfoResponsePacket {
this.input goto 14 this.input goto 14
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) } val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
return ServerAccountInfoResponsePacket(TEACryptor.decrypt(data, sessionKey).dataInputStream()); return ServerAccountInfoResponsePacket(TEA.decrypt(data, sessionKey).dataInputStream());
}
} }
} }
\ No newline at end of file
...@@ -108,15 +108,15 @@ fun DataOutputStream.writeVarInt(dec: UInt) { ...@@ -108,15 +108,15 @@ fun DataOutputStream.writeVarInt(dec: UInt) {
} }
fun DataOutputStream.encryptAndWrite(byteArray: ByteArray, key: ByteArray) { fun DataOutputStream.encryptAndWrite(byteArray: ByteArray, key: ByteArray) {
this.write(TEACryptor.encrypt(byteArray, key)) this.write(TEA.encrypt(byteArray, key))
} }
fun DataOutputStream.encryptAndWrite(byteArray: ByteArray, cryptor: TEACryptor) { fun DataOutputStream.encryptAndWrite(byteArray: ByteArray, cryptor: TEA) {
this.write(cryptor.encrypt(byteArray)) this.write(cryptor.encrypt(byteArray))
} }
fun DataOutputStream.encryptAndWrite(key: ByteArray, encoder: (ByteArrayDataOutputStream) -> Unit) { fun DataOutputStream.encryptAndWrite(key: ByteArray, encoder: (ByteArrayDataOutputStream) -> Unit) {
this.write(TEACryptor.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() }, key)) this.write(TEA.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() }, key))
} }
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
...@@ -124,7 +124,7 @@ fun DataOutputStream.encryptAndWrite(keyHex: String, encoder: (ByteArrayDataOutp ...@@ -124,7 +124,7 @@ fun DataOutputStream.encryptAndWrite(keyHex: String, encoder: (ByteArrayDataOutp
this.encryptAndWrite(keyHex.hexToBytes(), encoder) this.encryptAndWrite(keyHex.hexToBytes(), encoder)
} }
fun DataOutputStream.encryptAndWrite(cryptor: TEACryptor, encoder: (ByteArrayDataOutputStream) -> Unit) { fun DataOutputStream.encryptAndWrite(cryptor: TEA, encoder: (ByteArrayDataOutputStream) -> Unit) {
this.write(cryptor.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() })) this.write(cryptor.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() }))
} }
...@@ -132,24 +132,24 @@ fun DataOutputStream.encryptAndWrite(cryptor: TEACryptor, encoder: (ByteArrayDat ...@@ -132,24 +132,24 @@ fun DataOutputStream.encryptAndWrite(cryptor: TEACryptor, encoder: (ByteArrayDat
@Throws(IOException::class) @Throws(IOException::class)
fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray) { fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray) {
ByteArrayDataOutputStream().let { ByteArrayDataOutputStream().let {
it.writeHex("12 12 12 12")//it.writeRandom(4) todo it.writeRandom(4)
it.writeHex("00 02") it.writeHex("00 02")
it.writeQQ(qq) it.writeQQ(qq)
it.writeHex(Protocol._0825data2) it.writeHex(Protocol.constantData1)
it.writeHex("00 00 01") it.writeHex("00 00 01")
val md5_1 = md5(password); val firstMD5 = md5(password)
val md5_2 = md5(md5_1 + "00 00 00 00".hexToBytes() + qq.toUInt().toByteArray()) val secondMD5 = md5(firstMD5 + "00 00 00 00".hexToBytes() + qq.toUInt().toByteArray())
it.write(md5_1) it.write(firstMD5)
it.writeInt(loginTime) it.writeInt(loginTime)
it.writeByte(0); it.writeByte(0)
it.writeZero(4 * 3) it.writeZero(4 * 3)
it.writeIP(loginIP) it.writeIP(loginIP)
it.writeZero(8) it.writeZero(8)
it.writeHex("00 10") it.writeHex("00 10")
it.writeHex("15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B") it.writeHex("15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B")
it.write(tgtgtKey) it.write(tgtgtKey)
this.write(TEACryptor.encrypt(it.toByteArray(), md5_2)) this.write(TEA.encrypt(it.toByteArray(), secondMD5))
} }
} }
...@@ -216,7 +216,7 @@ fun Int.toLByteArray(): ByteArray = byteArrayOf( ...@@ -216,7 +216,7 @@ fun Int.toLByteArray(): ByteArray = byteArrayOf(
) )
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
fun Int.toHexString(separator: String = " "): String = this.toByteArray().toUByteArray().toUHexString(separator); fun Int.toHexString(separator: String = " "): String = this.toByteArray().toUByteArray().toUHexString(separator)
internal fun md5(str: String): ByteArray = MessageDigest.getInstance("MD5").digest(str.toByteArray()) internal fun md5(str: String): ByteArray = MessageDigest.getInstance("MD5").digest(str.toByteArray())
......
...@@ -24,8 +24,4 @@ class ClientHeartbeatPacket( ...@@ -24,8 +24,4 @@ class ClientHeartbeatPacket(
} }
} }
class ServerHeartbeatResponsePacket(input: DataInputStream) : ServerPacket(input) { class ServerHeartbeatResponsePacket(input: DataInputStream) : ServerPacket(input)
override fun decode() { \ No newline at end of file
}
}
\ No newline at end of file
package net.mamoe.mirai.network.packet
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.utils.TEACryptor
import net.mamoe.mirai.utils.toUHexString
import java.io.DataInputStream
/**
* 告知服务器已经收到数据
*/
@PacketId("")//随后写入
@ExperimentalUnsignedTypes
class ClientMessageResponsePacket(
private val qq: Long,
private val packetIdFromServer: ByteArray,
private val sessionKey: ByteArray,
private val eventIdentity: ByteArray
) : ClientPacket() {
override fun encode() {
this.write(packetIdFromServer)
this.writeQQ(qq)
this.writeHex(Protocol._fixVer)
this.encryptAndWrite(sessionKey) {
it.write(eventIdentity)
}
}
}
/**
* 群聊和好友消息分发
*/
@PacketId("00 17")
class ServerMessageEventPacketRaw(
input: DataInputStream,
private val dataLength: Int,
private val packetId: ByteArray
) : ServerPacket(input) {
lateinit var type: ByteArray;
lateinit var eventIdentity: ByteArray;
override fun decode() {
eventIdentity = this.input.readNBytes(16)
type = this.input.goto(18).readNBytes(2)
}
fun analyze(): ServerEventPacket = when (val typeHex = type.toUHexString()) {
"00 C4" -> {
if (this.input.goto(33).readBoolean()) {
ServerAndroidOnlineEventPacket(this.input, packetId, eventIdentity)
} else {
ServerAndroidOfflineEventPacket(this.input, packetId, eventIdentity)
}
}
"00 2D" -> ServerGroupUploadFileEventPacket(this.input, packetId, eventIdentity)
"00 52" -> ServerGroupMessageEventPacket(this.input, packetId, eventIdentity)
"00 A6" -> ServerFriendMessageEventPacket(this.input, packetId, eventIdentity)
//"02 10", "00 12" -> ServerUnknownEventPacket(this.input, packetId, eventIdentity)
else -> UnknownServerEventPacket(this.input, packetId, eventIdentity)
}
}
class UnknownServerEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity)
@PacketId("00 17")
class ServerMessageEventPacketRawEncoded(input: DataInputStream, val packetId: ByteArray) : ServerPacket(input) {
override fun decode() {
}
fun decrypt(sessionKey: ByteArray): ServerMessageEventPacketRaw {
this.input goto 14
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
return ServerMessageEventPacketRaw(TEACryptor.decrypt(data, sessionKey).dataInputStream(), data.size, packetId);
}
}
\ No newline at end of file
package net.mamoe.mirai.network.packet package net.mamoe.mirai.network.packet
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.utils.TEACryptor import net.mamoe.mirai.utils.TEA
import java.io.DataInputStream import java.io.DataInputStream
...@@ -18,7 +18,7 @@ class ClientSKeyRequestPacket( ...@@ -18,7 +18,7 @@ class ClientSKeyRequestPacket(
this.writeRandom(2)//part of packet id this.writeRandom(2)//part of packet id
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex(Protocol._fixVer) this.writeHex(Protocol.fixVer2)
this.encryptAndWrite(sessionKey) { this.encryptAndWrite(sessionKey) {
it.writeHex("33 00 05 00 08 74 2E 71 71 2E 63 6F 6D 00 0A 71 75 6E 2E 71 71 2E 63 6F 6D 00 0C 71 7A 6F 6E 65 2E 71 71 2E 63 6F 6D 00 0C 6A 75 62 61 6F 2E 71 71 2E 63 6F 6D 00 09 6B 65 2E 71 71 2E 63 6F 6D") it.writeHex("33 00 05 00 08 74 2E 71 71 2E 63 6F 6D 00 0A 71 75 6E 2E 71 71 2E 63 6F 6D 00 0C 71 7A 6F 6E 65 2E 71 71 2E 63 6F 6D 00 0C 6A 75 62 61 6F 2E 71 71 2E 63 6F 6D 00 09 6B 65 2E 71 71 2E 63 6F 6D")
} }
...@@ -52,19 +52,13 @@ class ServerSKeyResponsePacket(input: DataInputStream) : ServerPacket(input) { ...@@ -52,19 +52,13 @@ class ServerSKeyResponsePacket(input: DataInputStream) : ServerPacket(input) {
override fun decode() { override fun decode() {
this.sKey = String(this.input.goto(4).readNBytes(10)) this.sKey = String(this.input.goto(4).readNBytes(10))
} }
}
/**
* @author Him188moe
*/
class ServerSKeyResponsePacketEncrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
override fun decode() {
}
fun decrypt(sessionKey: ByteArray): ServerSKeyResponsePacket { class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
this.input goto 14 fun decrypt(sessionKey: ByteArray): ServerSKeyResponsePacket {
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) } this.input goto 14
return ServerSKeyResponsePacket(TEACryptor.decrypt(data, sessionKey).dataInputStream()); val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
return ServerSKeyResponsePacket(TEA.decrypt(data, sessionKey).dataInputStream());
}
} }
} }
\ No newline at end of file
...@@ -2,6 +2,7 @@ package net.mamoe.mirai.network.packet ...@@ -2,6 +2,7 @@ package net.mamoe.mirai.network.packet
import net.mamoe.mirai.message.defaults.MessageChain import net.mamoe.mirai.message.defaults.MessageChain
import net.mamoe.mirai.message.defaults.PlainText import net.mamoe.mirai.message.defaults.PlainText
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.toUHexString import net.mamoe.mirai.utils.toUHexString
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
...@@ -9,15 +10,50 @@ import java.io.DataInputStream ...@@ -9,15 +10,50 @@ import java.io.DataInputStream
import java.util.zip.GZIPInputStream import java.util.zip.GZIPInputStream
/** /**
* Packet id: `00 CE` or `00 17`
*
* @author Him188moe * @author Him188moe
*/ */
open class ServerEventPacket(input: DataInputStream, val packetId: ByteArray, val eventIdentity: ByteArray) : ServerPacket(input) { open class ServerEventPacket(input: DataInputStream, val packetId: ByteArray, val eventIdentity: ByteArray) : ServerPacket(input) {
@PacketId("00 17")
class Raw(input: DataInputStream, private val packetId: ByteArray) : ServerPacket(input) {
@ExperimentalUnsignedTypes
fun distribute(): ServerEventPacket {
val eventIdentity = this.input.readNBytes(16)
val type = this.input.goto(18).readNBytes(2)
return when (type.toUHexString()) {
"00 C4" -> {
if (this.input.goto(33).readBoolean()) {
ServerAndroidOnlineEventPacket(this.input, packetId, eventIdentity)
} else {
ServerAndroidOfflineEventPacket(this.input, packetId, eventIdentity)
}
}
"00 2D" -> ServerGroupUploadFileEventPacket(this.input, packetId, eventIdentity)
override fun decode() { "00 52" -> ServerGroupMessageEventPacket(this.input, packetId, eventIdentity)
"00 A6" -> ServerFriendMessageEventPacket(this.input, packetId, eventIdentity)
//"02 10", "00 12" -> ServerUnknownEventPacket(this.input, packetId, eventIdentity)
else -> UnknownServerEventPacket(this.input, packetId, eventIdentity)
}
}
@PacketId("00 17")
class Encrypted(input: DataInputStream, private val packetId: ByteArray) : ServerPacket(input) {
fun decrypt(sessionKey: ByteArray): Raw = Raw(decryptBy(sessionKey), packetId)
}
} }
} }
/**
* Unknown event
*/
class UnknownServerEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity)
/** /**
* Android 客户端上线 * Android 客户端上线
*/ */
...@@ -32,7 +68,7 @@ class ServerAndroidOfflineEventPacket(input: DataInputStream, packetId: ByteArra ...@@ -32,7 +68,7 @@ class ServerAndroidOfflineEventPacket(input: DataInputStream, packetId: ByteArra
* 群文件上传 * 群文件上传
*/ */
class ServerGroupUploadFileEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) { class ServerGroupUploadFileEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
lateinit var xmlMessage: String private lateinit var xmlMessage: String
override fun decode() { override fun decode() {
xmlMessage = String(this.input.goto(65).readNBytes(this.input.goto(60).readShort().toInt())) xmlMessage = String(this.input.goto(65).readNBytes(this.input.goto(60).readShort().toInt()))
...@@ -147,7 +183,6 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray ...@@ -147,7 +183,6 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
var qq: Long = 0 var qq: Long = 0
lateinit var message: MessageChain lateinit var message: MessageChain
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
override fun decode() { override fun decode() {
//start at Sep1.0:27 //start at Sep1.0:27
...@@ -166,6 +201,30 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray ...@@ -166,6 +201,30 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
} }
} }
/**
* 告知服务器已经收到数据
*/
@PacketId("")//随后写入
@ExperimentalUnsignedTypes
class ClientMessageResponsePacket(
private val qq: Long,
private val packetIdFromServer: ByteArray,//4bytes
private val sessionKey: ByteArray,
private val eventIdentity: ByteArray
) : ClientPacket() {
override fun encode() {
this.write(packetIdFromServer)//packet id 4bytes
this.writeQQ(qq)
this.writeHex(Protocol.fixVer2)
this.encryptAndWrite(sessionKey) {
it.write(eventIdentity)
}
}
}
/* /*
3E 03 3F A2 76 E4 B8 DD 00 09 7C 3F 64 5C 2A 60 1F 40 00 A6 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 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E4 5D 6B A8 F6 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A8 F6 08 7E 90 CE 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 E7 89 9B E9 80 BC 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 3E 03 3F A2 76 E4 B8 DD 00 09 7C 3F 64 5C 2A 60 1F 40 00 A6 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 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E4 5D 6B A8 F6 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A8 F6 08 7E 90 CE 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 E7 89 9B E9 80 BC 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
3E 03 3F A2 76 E4 B8 DD 00 03 5F 85 64 5C 2A A4 1F 40 00 A6 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 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E5 5D 6B A9 16 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A9 17 1B B3 4D D7 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 E7 89 9B E9 80 BC 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 3E 03 3F A2 76 E4 B8 DD 00 03 5F 85 64 5C 2A A4 1F 40 00 A6 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 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E5 5D 6B A9 16 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A9 17 1B B3 4D D7 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 E7 89 9B E9 80 BC 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
......
...@@ -3,10 +3,7 @@ package net.mamoe.mirai.network.packet ...@@ -3,10 +3,7 @@ package net.mamoe.mirai.network.packet
import net.mamoe.mirai.network.packet.login.* import net.mamoe.mirai.network.packet.login.*
import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket
import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket
import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.getAllDeclaredFields
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.toUHexString
import java.io.DataInputStream import java.io.DataInputStream
/** /**
...@@ -14,7 +11,9 @@ import java.io.DataInputStream ...@@ -14,7 +11,9 @@ import java.io.DataInputStream
*/ */
abstract class ServerPacket(val input: DataInputStream) : Packet { abstract class ServerPacket(val input: DataInputStream) : Packet {
abstract fun decode() open fun decode() {
}
companion object { companion object {
...@@ -28,23 +27,22 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { ...@@ -28,23 +27,22 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
return when (val idHex = stream.readInt().toHexString(" ")) { return when (val idHex = stream.readInt().toHexString(" ")) {
"08 25 31 01" -> ServerTouchResponsePacketEncrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_01, stream) "08 25 31 01" -> ServerTouchResponsePacket.Encrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_01, stream)
"08 25 31 02" -> ServerTouchResponsePacket.Encrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_02, stream)
"08 25 31 02" -> ServerTouchResponsePacketEncrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_02, stream)
"08 36 31 03", "08 36 31 04", "08 36 31 05", "08 36 31 06" -> { "08 36 31 03", "08 36 31 04", "08 36 31 05", "08 36 31 06" -> {
when (bytes.size) { when (bytes.size) {
271, 207 -> return ServerLoginResponseResendPacketEncrypted(stream, when (idHex) { 271, 207 -> return ServerLoginResponseResendPacket.Encrypted(stream, when (idHex) {
"08 36 31 03" -> ServerLoginResponseResendPacket.Flag.`08 36 31 03` "08 36 31 03" -> ServerLoginResponseResendPacket.Flag.`08 36 31 03`
else -> { else -> {
MiraiLogger debug ("ServerLoginResponseResendPacketEncrypted: flag=$idHex"); ServerLoginResponseResendPacket.Flag.OTHER MiraiLogger debug ("ServerLoginResponseResendPacketEncrypted: flag=$idHex"); ServerLoginResponseResendPacket.Flag.OTHER
} }
}) })
871 -> return ServerLoginResponseVerificationCodePacketEncrypted(stream) 871 -> return ServerLoginResponseVerificationCodeInitPacket.Encrypted(stream)
} }
if (bytes.size > 700) { if (bytes.size > 700) {
return ServerLoginResponseSuccessPacketEncrypted(stream) return ServerLoginResponseSuccessPacket.Encrypted(stream)
} }
return ServerLoginResponseFailedPacket(when (bytes.size) { return ServerLoginResponseFailedPacket(when (bytes.size) {
...@@ -63,20 +61,20 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { ...@@ -63,20 +61,20 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
}, stream) }, stream)
} }
"08 28 04 34" -> ServerSessionKeyResponsePacketEncrypted(stream) "08 28 04 34" -> ServerSessionKeyResponsePacket.Encrypted(stream)
else -> when (idHex.substring(0, 5)) { else -> when (idHex.substring(0, 5)) {
"00 EC" -> ServerLoginSuccessPacket(stream) "00 EC" -> ServerLoginSuccessPacket(stream)
"00 1D" -> ServerSKeyResponsePacketEncrypted(stream) "00 1D" -> ServerSKeyResponsePacket.Encrypted(stream)
"00 5C" -> ServerAccountInfoResponsePacketEncrypted(stream) "00 5C" -> ServerAccountInfoResponsePacket.Encrypted(stream)
"00 58" -> ServerHeartbeatResponsePacket(stream) "00 58" -> ServerHeartbeatResponsePacket(stream)
"00 BA" -> ServerVerificationCodePacketEncrypted(stream) "00 BA" -> ServerVerificationCodePacket.Encrypted(stream)
"00 CE", "00 17" -> ServerMessageEventPacketRawEncoded(stream, idHex.hexToBytes()) "00 CE", "00 17" -> ServerEventPacket.Raw.Encrypted(stream, idHex.hexToBytes())
"00 81" -> UnknownServerPacket(stream) "00 81" -> UnknownServerPacket(stream)
...@@ -101,6 +99,16 @@ abstract class ServerPacket(val input: DataInputStream) : Packet { ...@@ -101,6 +99,16 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
} }
} }
} }
fun decryptBy(key: ByteArray): DataInputStream {
input.goto(14)
return DataInputStream(TEA.decrypt(input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, key).inputStream())
}
@ExperimentalUnsignedTypes
fun decryptBy(keyHex: String): DataInputStream {
return this.decryptBy(keyHex.hexToBytes())
}
} }
...@@ -173,4 +181,6 @@ fun <N : Number> DataInputStream.readByteAt(position: N): Byte { ...@@ -173,4 +181,6 @@ fun <N : Number> DataInputStream.readByteAt(position: N): Byte {
fun <N : Number> DataInputStream.readShortAt(position: N): Short { fun <N : Number> DataInputStream.readShortAt(position: N): Short {
this.goto(position) this.goto(position)
return this.readShort(); return this.readShort();
} }
\ No newline at end of file
fun ByteArray.cutTail(length: Int): ByteArray = this.copyOfRange(0, this.size - length)
\ No newline at end of file
...@@ -2,7 +2,7 @@ package net.mamoe.mirai.network.packet ...@@ -2,7 +2,7 @@ package net.mamoe.mirai.network.packet
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.utils.ByteArrayDataOutputStream import net.mamoe.mirai.utils.ByteArrayDataOutputStream
import net.mamoe.mirai.utils.TEACryptor import net.mamoe.mirai.utils.TEA
import net.mamoe.mirai.utils.getRandomKey import net.mamoe.mirai.utils.getRandomKey
import net.mamoe.mirai.utils.lazyEncode import net.mamoe.mirai.utils.lazyEncode
import java.io.DataInputStream import java.io.DataInputStream
...@@ -16,8 +16,6 @@ import java.net.InetAddress ...@@ -16,8 +16,6 @@ import java.net.InetAddress
class ClientSessionRequestPacket( class ClientSessionRequestPacket(
private val qq: Long, private val qq: Long,
private val serverIp: String, private val serverIp: String,
private val loginIP: String,
private val md5_32: ByteArray,
private val token38: ByteArray, private val token38: ByteArray,
private val token88: ByteArray, private val token88: ByteArray,
private val encryptionKey: ByteArray, private val encryptionKey: ByteArray,
...@@ -28,7 +26,7 @@ class ClientSessionRequestPacket( ...@@ -28,7 +26,7 @@ class ClientSessionRequestPacket(
this.writeHex("02 00 00 00 01 2E 01 00 00 68 52 00 30 00 3A") this.writeHex("02 00 00 00 01 2E 01 00 00 68 52 00 30 00 3A")
this.writeHex("00 38") this.writeHex("00 38")
this.write(token38) this.write(token38)
this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() { this.write(TEA.encrypt(object : ByteArrayDataOutputStream() {
override fun toByteArray(): ByteArray { override fun toByteArray(): ByteArray {
this.writeHex("00 07 00 88") this.writeHex("00 07 00 88")
this.write(token88) this.write(token88)
...@@ -36,10 +34,10 @@ class ClientSessionRequestPacket( ...@@ -36,10 +34,10 @@ class ClientSessionRequestPacket(
this.writeIP(serverIp) this.writeIP(serverIp)
this.writeHex("1F 40 00 00 00 00 00 15 00 30 00 01")//fix1 this.writeHex("1F 40 00 00 00 00 00 15 00 30 00 01")//fix1
this.writeHex("01 92 A5 D2 59 00 10 54 2D CF 9B 60 BF BB EC 0D D4 81 CE 36 87 DE 35 02 AE 6D ED DC 00 10 ") this.writeHex("01 92 A5 D2 59 00 10 54 2D CF 9B 60 BF BB EC 0D D4 81 CE 36 87 DE 35 02 AE 6D ED DC 00 10 ")
this.writeHex(Protocol._0836fix) this.writeHex(Protocol.fix0836)
this.writeHex("00 36 00 12 00 02 00 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00") this.writeHex("00 36 00 12 00 02 00 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00")
this.writeHex(Protocol._0825data0) this.writeHex(Protocol.constantData0)
this.writeHex(Protocol._0825data2) this.writeHex(Protocol.constantData1)
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex("00 00 00 00 00 1F 00 22 00 01") this.writeHex("00 00 00 00 00 1F 00 22 00 01")
this.writeHex("1A 68 73 66 E4 BA 79 92 CC C2 D4 EC 14 7C 8B AF 43 B0 62 FB 65 58 A9 EB 37 55 1D 26 13 A8 E5 3D")//device ID this.writeHex("1A 68 73 66 E4 BA 79 92 CC C2 D4 EC 14 7C 8B AF 43 B0 62 FB 65 58 A9 EB 37 55 1D 26 13 A8 E5 3D")//device ID
...@@ -51,7 +49,7 @@ class ClientSessionRequestPacket( ...@@ -51,7 +49,7 @@ class ClientSessionRequestPacket(
//fix3 //fix3
this.writeHex("00 63 3E 00 63 02 04 03 06 02 00 04 00 52 D9 00 00 00 00 A9 58 3E 6D 6D 49 AA F6 A6 D9 33 0A E7 7E 36 84 03 01 00 00 68 20 15 8B 00 00 01 02 00 00 03 00 07 DF 00 0A 00 0C 00 01 00 04 00 03 00 04 20 5C 00") this.writeHex("00 63 3E 00 63 02 04 03 06 02 00 04 00 52 D9 00 00 00 00 A9 58 3E 6D 6D 49 AA F6 A6 D9 33 0A E7 7E 36 84 03 01 00 00 68 20 15 8B 00 00 01 02 00 00 03 00 07 DF 00 0A 00 0C 00 01 00 04 00 03 00 04 20 5C 00")
this.write(md5_32) this.write(getRandomKey(32))//md5 32
this.writeHex("68") this.writeHex("68")
this.writeHex("00 00 00 00 00 2D 00 06 00 01") this.writeHex("00 00 00 00 00 2D 00 06 00 01")
...@@ -106,16 +104,12 @@ class ServerSessionKeyResponsePacket(inputStream: DataInputStream, private val d ...@@ -106,16 +104,12 @@ class ServerSessionKeyResponsePacket(inputStream: DataInputStream, private val d
//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) //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)
} }
}
class ServerSessionKeyResponsePacketEncrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
override fun decode() {
} class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
fun decrypt(_0828_rec_decr_key: ByteArray): ServerSessionKeyResponsePacket {
fun decrypt(_0828_rec_decr_key: ByteArray): ServerSessionKeyResponsePacket { this.input goto 14
this.input goto 14 val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) } return ServerSessionKeyResponsePacket(TEA.decrypt(data, _0828_rec_decr_key).dataInputStream(), data.size);
return ServerSessionKeyResponsePacket(TEACryptor.decrypt(data, _0828_rec_decr_key).dataInputStream(), data.size); }
} }
} }
\ No newline at end of file
...@@ -48,24 +48,13 @@ class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inp ...@@ -48,24 +48,13 @@ class ServerTouchResponsePacket(inputStream: DataInputStream) : ServerPacket(inp
} }
} }
} }
}
class ServerTouchResponsePacketEncrypted(private val type: ServerTouchResponsePacket.Type, inputStream: DataInputStream) : ServerPacket(inputStream) {
override fun decode() {
}
@ExperimentalUnsignedTypes
fun decrypt(): ServerTouchResponsePacket {
input.skip(7)
var bytes = input.readAllBytes();
bytes = bytes.copyOfRange(0, bytes.size - 1);
println(bytes.toUByteArray().toUHexString())
return ServerTouchResponsePacket(DataInputStream(TEACryptor.decrypt(bytes, when (type) { class Encrypted(private val type: Type, inputStream: DataInputStream) : ServerPacket(inputStream) {
ServerTouchResponsePacket.Type.TYPE_08_25_31_02 -> Protocol.redirectionKey.hexToBytes() @ExperimentalUnsignedTypes
ServerTouchResponsePacket.Type.TYPE_08_25_31_01 -> Protocol._0825key.hexToBytes() fun decrypt(): ServerTouchResponsePacket = ServerTouchResponsePacket(decryptBy(when (type) {
}).inputStream())); Type.TYPE_08_25_31_02 -> Protocol.redirectionKey.hexToBytes()
Type.TYPE_08_25_31_01 -> Protocol.key0825.hexToBytes()
}))
} }
} }
...@@ -82,13 +71,13 @@ class ClientTouchPacket(val qq: Long, val serverIp: String) : ClientPacket() { ...@@ -82,13 +71,13 @@ class ClientTouchPacket(val qq: Long, val serverIp: String) : ClientPacket() {
override fun encode() { override fun encode() {
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex(Protocol.fixVer) this.writeHex(Protocol.fixVer)
this.writeHex(Protocol._0825key) this.writeHex(Protocol.key0825)
this.write(TEACryptor.CRYPTOR_0825KEY.encrypt(object : ByteArrayDataOutputStream() { this.write(TEA.CRYPTOR_0825KEY.encrypt(object : ByteArrayDataOutputStream() {
@Throws(IOException::class) @Throws(IOException::class)
override fun toByteArray(): ByteArray { override fun toByteArray(): ByteArray {
this.writeHex(Protocol._0825data0) this.writeHex(Protocol.constantData0)
this.writeHex(Protocol._0825data2) this.writeHex(Protocol.constantData1)
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex("00 00 00 00 03 09 00 08 00 01") this.writeHex("00 00 00 00 03 09 00 08 00 01")
this.writeIP(serverIp); this.writeIP(serverIp);
...@@ -116,11 +105,11 @@ class ClientServerRedirectionPacket(private val serverIP: String, private val qq ...@@ -116,11 +105,11 @@ class ClientServerRedirectionPacket(private val serverIP: String, private val qq
this.writeHex(Protocol.redirectionKey) this.writeHex(Protocol.redirectionKey)
this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() { this.write(TEA.encrypt(object : ByteArrayDataOutputStream() {
@Throws(IOException::class) @Throws(IOException::class)
override fun toByteArray(): ByteArray { override fun toByteArray(): ByteArray {
this.writeHex(Protocol._0825data0) this.writeHex(Protocol.constantData0)
this.writeHex(Protocol._0825data2) this.writeHex(Protocol.constantData1)
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex("00 01 00 00 03 09 00 0C 00 01") this.writeHex("00 01 00 00 03 09 00 0C 00 01")
this.writeIP(serverIP) this.writeIP(serverIP)
......
...@@ -23,11 +23,11 @@ class ClientVerificationCodeTransmissionRequestPacket( ...@@ -23,11 +23,11 @@ class ClientVerificationCodeTransmissionRequestPacket(
this.writeByte(count)//part of packet id this.writeByte(count)//part of packet id
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex(Protocol._fixVer) this.writeHex(Protocol.fixVer2)
this.writeHex(Protocol._00BaKey) this.writeHex(Protocol.key00BA)
this.encryptAndWrite(Protocol._00BaKey) { this.encryptAndWrite(Protocol.key00BA) {
it.writeHex("00 02 00 00 08 04 01 E0") it.writeHex("00 02 00 00 08 04 01 E0")
it.writeHex(Protocol._0825data2) it.writeHex(Protocol.constantData1)
it.writeHex("00 00 38") it.writeHex("00 00 38")
it.write(token0825) it.write(token0825)
it.writeHex("01 03 00 19") it.writeHex("01 03 00 19")
...@@ -37,7 +37,7 @@ class ClientVerificationCodeTransmissionRequestPacket( ...@@ -37,7 +37,7 @@ class ClientVerificationCodeTransmissionRequestPacket(
it.writeHex("00 28") it.writeHex("00 28")
it.write(token00BA) it.write(token00BA)
it.writeHex("00 10") it.writeHex("00 10")
it.writeHex(Protocol._00BaFixKey) it.writeHex(Protocol.key00BAFix)
} }
} }
} }
...@@ -87,22 +87,19 @@ class ServerVerificationCodeRepeatPacket(input: DataInputStream) : ServerVerific ...@@ -87,22 +87,19 @@ class ServerVerificationCodeRepeatPacket(input: DataInputStream) : ServerVerific
} }
} }
abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input) abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input) {
@PacketId("00 BA") @PacketId("00 BA")
class ServerVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) { class Encrypted(input: DataInputStream) : ServerPacket(input) {
override fun decode() { @ExperimentalUnsignedTypes
fun decrypt(): ServerVerificationCodePacket {
} this.input goto 14
val data = TEA.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, Protocol.key00BA.hexToBytes())
@ExperimentalUnsignedTypes return if (data.size == 95) {
fun decrypt(): ServerVerificationCodePacket { ServerVerificationCodeRepeatPacket(data.dataInputStream())
this.input goto 14 } else {
val data = TEACryptor.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, Protocol._00BaKey.hexToBytes()) ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4))
return if (data.size == 95) { }
ServerVerificationCodeRepeatPacket(data.dataInputStream())
} else {
ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4))
} }
} }
} }
\ No newline at end of file
...@@ -5,11 +5,13 @@ import net.mamoe.mirai.network.packet.* ...@@ -5,11 +5,13 @@ import net.mamoe.mirai.network.packet.*
import net.mamoe.mirai.utils.ClientLoginStatus import net.mamoe.mirai.utils.ClientLoginStatus
/** /**
* 改变在线状态: "我在线上", "隐身" 等
*
* @author Him188moe * @author Him188moe
*/ */
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
@PacketId("00 EC") @PacketId("00 EC")
class ClientLoginStatusPacket( class ClientChangeOnlineStatusPacket(
private val qq: Long, private val qq: Long,
private val sessionKey: ByteArray, private val sessionKey: ByteArray,
private val loginStatus: ClientLoginStatus private val loginStatus: ClientLoginStatus
...@@ -18,7 +20,7 @@ class ClientLoginStatusPacket( ...@@ -18,7 +20,7 @@ class ClientLoginStatusPacket(
override fun encode() { override fun encode() {
this.writeRandom(2)//part of packet id this.writeRandom(2)//part of packet id
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex(Protocol._fixVer) this.writeHex(Protocol.fixVer2)
this.encryptAndWrite(sessionKey) { this.encryptAndWrite(sessionKey) {
it.writeHex("01 00") it.writeHex("01 00")
it.writeByte(loginStatus.id) it.writeByte(loginStatus.id)
......
...@@ -4,7 +4,7 @@ import net.mamoe.mirai.network.Protocol ...@@ -4,7 +4,7 @@ import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.network.packet.*
import net.mamoe.mirai.util.TestedSuccessfully import net.mamoe.mirai.util.TestedSuccessfully
import net.mamoe.mirai.utils.ByteArrayDataOutputStream import net.mamoe.mirai.utils.ByteArrayDataOutputStream
import net.mamoe.mirai.utils.TEACryptor import net.mamoe.mirai.utils.TEA
import net.mamoe.mirai.utils.hexToBytes import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.toUHexString import net.mamoe.mirai.utils.toUHexString
import java.io.DataOutputStream import java.io.DataOutputStream
...@@ -28,10 +28,10 @@ class ClientPasswordSubmissionPacket( ...@@ -28,10 +28,10 @@ class ClientPasswordSubmissionPacket(
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
override fun encode() { override fun encode() {
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex(Protocol._0836_622_fix1) this.writeHex(Protocol.passwordSubmissionKey1)
this.writeHex(Protocol.publicKey) this.writeHex(Protocol.publicKey)
this.writeHex("00 00 00 10") this.writeHex("00 00 00 10")
this.writeHex(Protocol._0836key1) this.writeHex(Protocol.key0836)
this.encryptAndWrite(Protocol.shareKey.hexToBytes()) { this.encryptAndWrite(Protocol.shareKey.hexToBytes()) {
it.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825) it.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825)
...@@ -69,12 +69,12 @@ open class ClientLoginResendPacket internal constructor( ...@@ -69,12 +69,12 @@ open class ClientLoginResendPacket internal constructor(
) : ClientPacket() { ) : ClientPacket() {
override fun encode() { override fun encode() {
this.writeQQ(qq) this.writeQQ(qq)
this.writeHex(Protocol._0836_622_fix1) this.writeHex(Protocol.passwordSubmissionKey1)
this.writeHex(Protocol.publicKey) this.writeHex(Protocol.publicKey)
this.writeHex("00 00 00 10") this.writeHex("00 00 00 10")
this.writeHex(Protocol._0836key1) this.writeHex(Protocol.key0836)
this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() { this.write(TEA.encrypt(object : ByteArrayDataOutputStream() {
override fun toByteArray(): ByteArray { override fun toByteArray(): ByteArray {
this.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825, tlv_0006_encr) this.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825, tlv_0006_encr)
...@@ -115,12 +115,12 @@ private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: I ...@@ -115,12 +115,12 @@ private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: I
this.writeTLV0006(qq, password, loginTime, loginIP, tgtgtKey) this.writeTLV0006(qq, password, loginTime, loginIP, tgtgtKey)
} }
//fix //fix
this.writeHex(Protocol._0836_622_fix2) this.writeHex(Protocol.passwordSubmissionKey2)
this.writeHex("00 1A")//tag this.writeHex("00 1A")//tag
this.writeHex("00 40")//length this.writeHex("00 40")//length
this.write(TEACryptor.encrypt(Protocol._0836_622_fix2.hexToBytes(), tgtgtKey)) this.write(TEA.encrypt(Protocol.passwordSubmissionKey2.hexToBytes(), tgtgtKey))
this.writeHex(Protocol._0825data0) this.writeHex(Protocol.constantData0)
this.writeHex(Protocol._0825data2) this.writeHex(Protocol.constantData1)
this.writeQQ(qq) this.writeQQ(qq)
this.writeZero(4) this.writeZero(4)
......
package net.mamoe.mirai.network.packet.login package net.mamoe.mirai.network.packet.login
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.ServerPacket import net.mamoe.mirai.network.packet.*
import net.mamoe.mirai.network.packet.goto
import net.mamoe.mirai.network.packet.readNBytesAt
import net.mamoe.mirai.network.packet.readVarString
import net.mamoe.mirai.util.TestedSuccessfully import net.mamoe.mirai.util.TestedSuccessfully
import net.mamoe.mirai.utils.TEACryptor import net.mamoe.mirai.utils.TEA
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.toUHexString import net.mamoe.mirai.utils.toUHexString
import java.io.DataInputStream import java.io.DataInputStream
...@@ -117,21 +113,14 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in ...@@ -117,21 +113,14 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
//this.gender = this.input.goto(packetDataLength - 32).readByteAt().toInt() //this.gender = this.input.goto(packetDataLength - 32).readByteAt().toInt()
} }
}
class ServerLoginResponseSuccessPacketEncrypted(input: DataInputStream) : ServerPacket(input) {
override fun decode() {
class Encrypted(input: DataInputStream) : ServerPacket(input) {
@ExperimentalUnsignedTypes
fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseSuccessPacket {
input goto 14
return ServerLoginResponseSuccessPacket(TEA.decrypt(TEA.decrypt(input.readAllBytes().cutTail(1), Protocol.shareKey), tgtgtKey).dataInputStream());
}
} }
@ExperimentalUnsignedTypes }
fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseSuccessPacket { \ No newline at end of file
input goto 14
var bytes = input.readAllBytes()
bytes = bytes.copyOfRange(0, bytes.size - 1)
println(bytes.toUByteArray().toUHexString())
return ServerLoginResponseSuccessPacket(DataInputStream(TEACryptor.decrypt(TEACryptor.decrypt(bytes, Protocol.shareKey.hexToBytes()), tgtgtKey).inputStream()));
//TeaDecrypt(取文本中间(data, 43, 取文本长度(data) - 45), m_0828_rec_decr_key)
}
}
...@@ -2,10 +2,8 @@ package net.mamoe.mirai.network.packet.login ...@@ -2,10 +2,8 @@ package net.mamoe.mirai.network.packet.login
import net.mamoe.mirai.network.packet.PacketId import net.mamoe.mirai.network.packet.PacketId
import net.mamoe.mirai.network.packet.ServerPacket import net.mamoe.mirai.network.packet.ServerPacket
import net.mamoe.mirai.network.packet.dataInputStream
import net.mamoe.mirai.network.packet.goto import net.mamoe.mirai.network.packet.goto
import net.mamoe.mirai.util.TestedSuccessfully import net.mamoe.mirai.util.TestedSuccessfully
import net.mamoe.mirai.utils.TEACryptor
import java.io.DataInputStream import java.io.DataInputStream
/** /**
...@@ -43,20 +41,9 @@ class ServerLoginResponseResendPacket(input: DataInputStream, val flag: Flag) : ...@@ -43,20 +41,9 @@ class ServerLoginResponseResendPacket(input: DataInputStream, val flag: Flag) :
} }
} }
} }
}
class ServerLoginResponseResendPacketEncrypted(input: DataInputStream, private val flag: ServerLoginResponseResendPacket.Flag) : ServerPacket(input) {
override fun decode() {
class Encrypted(input: DataInputStream, private val flag: Flag) : ServerPacket(input) {
@TestedSuccessfully
fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseResendPacket = ServerLoginResponseResendPacket(decryptBy(tgtgtKey), flag)
} }
}
@TestedSuccessfully
fun decrypt(tgtgtKey: ByteArray): ServerLoginResponseResendPacket {
//this.input.skip(7)
this.input goto 14
var data: ByteArray = this.input.readAllBytes()
data = TEACryptor.CRYPTOR_SHARE_KEY.decrypt(data.let { it.copyOfRange(0, it.size - 1) });
data = TEACryptor.decrypt(data, tgtgtKey)
return ServerLoginResponseResendPacket(data.dataInputStream(), flag)
}
}
\ No newline at end of file
package net.mamoe.mirai.network.packet.login package net.mamoe.mirai.network.packet.login
import net.mamoe.mirai.network.packet.ServerPacket import net.mamoe.mirai.network.packet.ServerPacket
import net.mamoe.mirai.network.packet.cutTail
import net.mamoe.mirai.network.packet.dataInputStream import net.mamoe.mirai.network.packet.dataInputStream
import net.mamoe.mirai.network.packet.goto import net.mamoe.mirai.network.packet.goto
import net.mamoe.mirai.util.TestedSuccessfully import net.mamoe.mirai.util.TestedSuccessfully
import net.mamoe.mirai.utils.TEACryptor import net.mamoe.mirai.utils.TEA
import net.mamoe.mirai.utils.hexToUBytes import net.mamoe.mirai.utils.hexToUBytes
import java.io.DataInputStream import java.io.DataInputStream
...@@ -32,6 +33,19 @@ class ServerLoginResponseVerificationCodeInitPacket(input: DataInputStream, priv ...@@ -32,6 +33,19 @@ class ServerLoginResponseVerificationCodeInitPacket(input: DataInputStream, priv
this.token00BA = this.input.goto(packetLength - 60).readNBytes(40) this.token00BA = this.input.goto(packetLength - 60).readNBytes(40)
} }
class Encrypted(input: DataInputStream) : ServerPacket(input) {
override fun decode() {
}
fun decrypt(): ServerLoginResponseVerificationCodeInitPacket {
this.input goto 14
val data = TEA.CRYPTOR_SHARE_KEY.decrypt(this.input.readAllBytes().cutTail(1));
return ServerLoginResponseVerificationCodeInitPacket(data.dataInputStream(), data.size)
}
}
} }
fun main() { fun main() {
...@@ -54,15 +68,3 @@ verify code ...@@ -54,15 +68,3 @@ verify code
token00ba token00ba
42 E6 18 57 D4 B1 4D AE 51 27 D5 EF A2 38 91 39 15 37 6C 5A FE 75 93 49 DB FC 57 3C 12 3F 26 D9 16 1D 83 45 8B 78 39 D8 42 E6 18 57 D4 B1 4D AE 51 27 D5 EF A2 38 91 39 15 37 6C 5A FE 75 93 49 DB FC 57 3C 12 3F 26 D9 16 1D 83 45 8B 78 39 D8
*/ */
class ServerLoginResponseVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) {
override fun decode() {
}
fun decrypt(): ServerLoginResponseVerificationCodeInitPacket {
this.input goto 14
val data = TEACryptor.CRYPTOR_SHARE_KEY.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) });
return ServerLoginResponseVerificationCodeInitPacket(data.dataInputStream(), data.size)
}
}
\ No newline at end of file
...@@ -4,10 +4,8 @@ import net.mamoe.mirai.network.packet.ServerPacket ...@@ -4,10 +4,8 @@ import net.mamoe.mirai.network.packet.ServerPacket
import java.io.DataInputStream import java.io.DataInputStream
/** /**
* Congratulations!
*
* @author Him188moe * @author Him188moe
*/ */
class ServerLoginSuccessPacket(input: DataInputStream) : ServerPacket(input) { class ServerLoginSuccessPacket(input: DataInputStream) : ServerPacket(input)
override fun decode() { \ No newline at end of file
}
}
\ No newline at end of file
...@@ -19,7 +19,7 @@ class ClientSendFriendMessagePacket( ...@@ -19,7 +19,7 @@ class ClientSendFriendMessagePacket(
override fun encode() { override fun encode() {
this.writeRandom(2)//part of packet id this.writeRandom(2)//part of packet id
this.writeQQ(robotQQ) this.writeQQ(robotQQ)
this.writeHex(Protocol._fixVer) this.writeHex(Protocol.fixVer2)
this.encryptAndWrite(sessionKey) { this.encryptAndWrite(sessionKey) {
it.writeQQ(robotQQ) it.writeQQ(robotQQ)
...@@ -58,7 +58,4 @@ class ClientSendFriendMessagePacket( ...@@ -58,7 +58,4 @@ class ClientSendFriendMessagePacket(
} }
@PacketId("00 CD") @PacketId("00 CD")
class ServerSendFriendMessageResponsePacket(input: DataInputStream) : ServerPacket(input) { class ServerSendFriendMessageResponsePacket(input: DataInputStream) : ServerPacket(input)
override fun decode() { \ No newline at end of file
}
}
\ No newline at end of file
...@@ -2,7 +2,6 @@ package net.mamoe.mirai.network.packet.message ...@@ -2,7 +2,6 @@ package net.mamoe.mirai.network.packet.message
import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.network.packet.*
import net.mamoe.mirai.utils.lazyEncode
import net.mamoe.mirai.utils.toUHexString import net.mamoe.mirai.utils.toUHexString
import java.io.DataInputStream import java.io.DataInputStream
...@@ -13,14 +12,14 @@ import java.io.DataInputStream ...@@ -13,14 +12,14 @@ import java.io.DataInputStream
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
class ClientSendGroupMessagePacket( class ClientSendGroupMessagePacket(
private val groupId: Long,//不是 number private val groupId: Long,//不是 number
private val qq: Long, private val robotQQ: Long,
private val sessionKey: ByteArray, private val sessionKey: ByteArray,
private val message: String private val message: String
) : ClientPacket() { ) : ClientPacket() {
override fun encode() { override fun encode() {
this.writeRandom(2)//part of packet id this.writeRandom(2)//part of packet id
this.writeQQ(qq) this.writeQQ(robotQQ)
this.writeHex(Protocol._fixVer) this.writeHex(Protocol.fixVer2)
this.encryptAndWrite(sessionKey) { this.encryptAndWrite(sessionKey) {
val bytes = message.toByteArray() val bytes = message.toByteArray()
...@@ -46,24 +45,5 @@ class ClientSendGroupMessagePacket( ...@@ -46,24 +45,5 @@ class ClientSendGroupMessagePacket(
} }
} }
fun main() {
println(lazyEncode {
val bytes = "message".toByteArray()
it.writeByte(0x2A)
it.writeInt(580266363)
it.writeShort(19 + bytes.size)
it.writeByte(0x01)
it.writeByte(0x01)
it.writeShort(bytes.size + 3)
it.writeByte(0x01)
it.writeShort(bytes.size)
it.write(bytes)
}.toUHexString())
}
@PacketId("00 02") @PacketId("00 02")
class ServerSendGroupMessageResponsePacket(input: DataInputStream) : ServerPacket(input) { class ServerSendGroupMessageResponsePacket(input: DataInputStream) : ServerPacket(input)
override fun decode() { \ No newline at end of file
}
}
\ No newline at end of file
...@@ -4,10 +4,14 @@ package net.mamoe.mirai.utils; ...@@ -4,10 +4,14 @@ package net.mamoe.mirai.utils;
* @author Him188moe * @author Him188moe
*/ */
public enum ClientLoginStatus { public enum ClientLoginStatus {
/**
* 我在线上
*/
ONLINE(0x0A); ONLINE(0x0A);
// TODO: 2019/8/31 add more // TODO: 2019/8/31 add more ClientLoginStatus
public final int id;//1byte
public final int id;//1 ubyte
ClientLoginStatus(int id) { ClientLoginStatus(int id) {
this.id = id; this.id = id;
......
package net.mamoe.mirai.utils;
import lombok.Data;
/**
* @author Him188moe
*/
@Data
public final class RobotAccount {
public final long qqNumber;
public final String password;
public RobotAccount(long qqNumber, String password) {
this.qqNumber = qqNumber;
this.password = password;
}
}
...@@ -8,10 +8,10 @@ import java.util.Random; ...@@ -8,10 +8,10 @@ import java.util.Random;
/** /**
* @author iweiz https://github.com/iweizime/StepChanger/blob/master/app/src/main/java/me/iweizi/stepchanger/qq/Cryptor.java * @author iweiz https://github.com/iweizime/StepChanger/blob/master/app/src/main/java/me/iweizi/stepchanger/qq/Cryptor.java
*/ */
public class TEACryptor { public class TEA {
public static final TEACryptor CRYPTOR_SHARE_KEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol.shareKey)); public static final TEA CRYPTOR_SHARE_KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.shareKey));
public static final TEACryptor CRYPTOR_0825KEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol._0825key)); public static final TEA CRYPTOR_0825KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key0825));
public static final TEACryptor CRYPTOR_00BAKEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol._00BaKey)); public static final TEA CRYPTOR_00BAKEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key00BA));
private static final long UINT32_MASK = 0xffffffffL; private static final long UINT32_MASK = 0xffffffffL;
private final long[] mKey; private final long[] mKey;
...@@ -25,7 +25,7 @@ public class TEACryptor { ...@@ -25,7 +25,7 @@ public class TEACryptor {
private boolean isFirstBlock; private boolean isFirstBlock;
private boolean isRand; private boolean isRand;
public TEACryptor(byte[] key) { public TEA(byte[] key) {
mKey = new long[4]; mKey = new long[4];
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
mKey[i] = pack(key, i * 4, 4); mKey[i] = pack(key, i * 4, 4);
...@@ -36,11 +36,19 @@ public class TEACryptor { ...@@ -36,11 +36,19 @@ public class TEACryptor {
} }
public static byte[] encrypt(byte[] source, byte[] key) { public static byte[] encrypt(byte[] source, byte[] key) {
return new TEACryptor(key).encrypt(source); return new TEA(key).encrypt(source);
}
public static byte[] encrypt(byte[] source, String keyHex) {
return encrypt(source, UtilsKt.hexToBytes(keyHex));
} }
public static byte[] decrypt(byte[] source, byte[] key) { public static byte[] decrypt(byte[] source, byte[] key) {
return new TEACryptor(key).decrypt(source); return new TEA(key).decrypt(source);
}
public static byte[] decrypt(byte[] source, String keyHex) {
return decrypt(source, UtilsKt.hexToBytes(keyHex));
} }
private static long pack(byte[] bytes, int offset, int len) { private static long pack(byte[] bytes, int offset, int len) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment