Commit 512d27b8 authored by Him188moe's avatar Him188moe

Updated robot & network structure

parent bde4610f
......@@ -4,7 +4,6 @@ import lombok.Getter;
import net.mamoe.mirai.event.MiraiEventManager;
import net.mamoe.mirai.event.events.server.ServerDisableEvent;
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.task.MiraiTaskManager;
import net.mamoe.mirai.utils.LoggerTextFormat;
......@@ -36,7 +35,7 @@ public class MiraiServer {
@Getter //is running under UNIX
private boolean unix;
@Getter//file path
@Getter//file pathq
public File parentFolder;
@Getter
......@@ -121,8 +120,7 @@ public class MiraiServer {
this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> {
try {
Robot robot = new Robot(section);
RobotNetworkHandler robotNetworkHandler = robot.getNetworkHandler();
robotNetworkHandler.tryLogin$mirai_core(state -> {
robot.network.tryLogin$mirai_core(state -> {
if (state == LoginState.SUCCEED) {
Robot.instances.add(robot);
} else {
......
......@@ -5,79 +5,95 @@ import net.mamoe.mirai.contact.Group;
import net.mamoe.mirai.contact.QQ;
import net.mamoe.mirai.network.RobotNetworkHandler;
import net.mamoe.mirai.utils.ContactList;
import net.mamoe.mirai.utils.RobotAccount;
import net.mamoe.mirai.utils.config.MiraiConfigSection;
import org.jetbrains.annotations.NotNull;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.*;
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<>());
private final long qqNumber;
private final String password;
@Getter
private final RobotNetworkHandler networkHandler;
public final RobotAccount account;
public final ContactSystem contacts = new ContactSystem();
public final RobotNetworkHandler network;
/**
* Ref list
* Robot 联系人管理.
*
* @see Robot#contacts
*/
@Getter
private final List<String> owners;
public final class ContactSystem {
private final ContactList<Group> groups = new ContactList<>();
private final ContactList<QQ> qqs = new ContactList<>();
private final ContactList<Group> groups = new ContactList<>();
private final ContactList<QQ> qqs = new ContactList<>();
private ContactSystem() {
public void close() {
this.networkHandler.close();
this.owners.clear();
this.groups.values().forEach(Group::close);
this.groups.clear();
this.qqs.clear();
}
public QQ getQQ(long qqNumber) {
if (!this.qqs.containsKey(qqNumber)) {
this.qqs.put(qqNumber, new QQ(Robot.this, qqNumber));
}
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) {
return owners.contains(ownerName);
}
public long getQQNumber() {
return qqNumber;
}
public Robot(MiraiConfigSection<Object> data) throws Throwable {
this(
data.getLongOrThrow("account", () -> new IllegalArgumentException("account")),
data.getStringOrThrow("password", () -> new IllegalArgumentException("password")),
new RobotAccount(
data.getLongOrThrow("account", () -> new IllegalArgumentException("account")),
data.getStringOrThrow("password", () -> new IllegalArgumentException("password"))
),
data.getAsOrDefault("owners", ArrayList::new)
);
}
public Robot(long qqNumber, String password, List<String> owners) {
this.qqNumber = qqNumber;
this.password = password;
public Robot(@NotNull RobotAccount account, @NotNull List<String> owners) {
Objects.requireNonNull(account);
Objects.requireNonNull(owners);
this.account = account;
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) {
if (!this.groups.containsKey(groupNumber)) {
this.groups.put(groupNumber, new Group(groupNumber));
}
return groups.get(groupNumber);
public void close() {
this.network.close();
this.owners.clear();
this.contacts.groups.values().forEach(Group::close);
this.contacts.groups.clear();
this.contacts.qqs.clear();
}
public Group getGroupByGroupId(long groupId) {
return getGroup(Group.Companion.groupIdToNumber(groupId));
}
}
package net.mamoe.mirai.contact
import net.mamoe.mirai.Robot
import net.mamoe.mirai.message.Message
import net.mamoe.mirai.message.defaults.PlainText
/**
* A contact is a [QQ] or a [Group] for one particular [Robot] instance only.
*
* @param robot Owner [Robot]
* @author Him188moe
*/
abstract class Contact(val number: Long) {
abstract class Contact(val robot: Robot, val number: Long) {
/**
* Async
......
package net.mamoe.mirai.contact
import net.mamoe.mirai.Robot
import net.mamoe.mirai.message.Message
import net.mamoe.mirai.utils.ContactList
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 members = ContactList<QQ>()
override fun sendMessage(message: Message) {
robot.network.packetSystem.sendGroupMessage(this, message)
}
override fun sendXMLMessage(message: String) {
......
package net.mamoe.mirai.contact
import net.mamoe.mirai.Robot
import net.mamoe.mirai.message.Message
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
*/
class QQ(number: Long) : Contact(number) {
class QQ(robot: Robot, number: Long) : Contact(robot, number) {
override fun sendMessage(message: Message) {
robot.network.packetSystem.sendFriendMessage(this, message)
}
override fun sendXMLMessage(message: String) {
......
......@@ -28,26 +28,44 @@ interface Protocol {
const val head = "02"
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 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 "
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 ver = "37 13"
const val fixVer = "03 00 00 00 01 2E 01 00 00 68 52 00 00 00 00"
const val tail = "03"
/**
* _fixVer
*/
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 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 _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 _00BaFixKey = "69 20 D1 14 74 F5 B3 93 E4 D5 02 B3 71 1A CD 2A"
const val key00BA = "C1 9C B8 C8 7B 8C 81 BA 9E 9E 7A 89 E1 7A EC 94"
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 _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";
const val _0836key1 = "EF 4A 36 6A 16 A8 E6 3D 2E EA BD 1F 98 C1 3C DA"
/**
* 0836_622_fix2
*/
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()
......
package net.mamoe.mirai.network.packet
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.utils.TEACryptor
import net.mamoe.mirai.utils.TEA
import java.io.DataInputStream
/**
......@@ -18,7 +18,7 @@ class ClientAccountInfoRequestPacket(
override fun encode() {
this.writeRandom(2)//part of packet id
this.writeQQ(qq)
this.writeHex(Protocol._fixVer)
this.writeHex(Protocol.fixVer2)
this.encryptAndWrite(sessionKey) {
it.writeByte(0x88)
it.writeQQ(qq)
......@@ -27,6 +27,7 @@ class ClientAccountInfoRequestPacket(
}
}
@PacketId("00 5C")
class ServerAccountInfoResponsePacket(input: DataInputStream) : ServerPacket(input) {
//等级
//升级剩余活跃天数
......@@ -34,16 +35,13 @@ class ServerAccountInfoResponsePacket(input: DataInputStream) : ServerPacket(inp
override fun decode() {
}
}
class ServerAccountInfoResponsePacketEncrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
override fun decode() {
}
fun decrypt(sessionKey: ByteArray): ServerAccountInfoResponsePacket {
this.input goto 14
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
return ServerAccountInfoResponsePacket(TEACryptor.decrypt(data, sessionKey).dataInputStream());
@PacketId("00 5C")
class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
fun decrypt(sessionKey: ByteArray): ServerAccountInfoResponsePacket {
this.input goto 14
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
return ServerAccountInfoResponsePacket(TEA.decrypt(data, sessionKey).dataInputStream());
}
}
}
\ No newline at end of file
......@@ -108,15 +108,15 @@ fun DataOutputStream.writeVarInt(dec: UInt) {
}
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))
}
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
......@@ -124,7 +124,7 @@ fun DataOutputStream.encryptAndWrite(keyHex: String, encoder: (ByteArrayDataOutp
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() }))
}
......@@ -132,24 +132,24 @@ fun DataOutputStream.encryptAndWrite(cryptor: TEACryptor, encoder: (ByteArrayDat
@Throws(IOException::class)
fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray) {
ByteArrayDataOutputStream().let {
it.writeHex("12 12 12 12")//it.writeRandom(4) todo
it.writeRandom(4)
it.writeHex("00 02")
it.writeQQ(qq)
it.writeHex(Protocol._0825data2)
it.writeHex(Protocol.constantData1)
it.writeHex("00 00 01")
val md5_1 = md5(password);
val md5_2 = md5(md5_1 + "00 00 00 00".hexToBytes() + qq.toUInt().toByteArray())
it.write(md5_1)
val firstMD5 = md5(password)
val secondMD5 = md5(firstMD5 + "00 00 00 00".hexToBytes() + qq.toUInt().toByteArray())
it.write(firstMD5)
it.writeInt(loginTime)
it.writeByte(0);
it.writeByte(0)
it.writeZero(4 * 3)
it.writeIP(loginIP)
it.writeZero(8)
it.writeHex("00 10")
it.writeHex("15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B")
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(
)
@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())
......
......@@ -24,8 +24,4 @@ class ClientHeartbeatPacket(
}
}
class ServerHeartbeatResponsePacket(input: DataInputStream) : ServerPacket(input) {
override fun decode() {
}
}
\ No newline at end of file
class ServerHeartbeatResponsePacket(input: DataInputStream) : ServerPacket(input)
\ 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
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.utils.TEACryptor
import net.mamoe.mirai.utils.TEA
import java.io.DataInputStream
......@@ -18,7 +18,7 @@ class ClientSKeyRequestPacket(
this.writeRandom(2)//part of packet id
this.writeQQ(qq)
this.writeHex(Protocol._fixVer)
this.writeHex(Protocol.fixVer2)
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")
}
......@@ -52,19 +52,13 @@ class ServerSKeyResponsePacket(input: DataInputStream) : ServerPacket(input) {
override fun decode() {
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 {
this.input goto 14
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
return ServerSKeyResponsePacket(TEACryptor.decrypt(data, sessionKey).dataInputStream());
class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
fun decrypt(sessionKey: ByteArray): ServerSKeyResponsePacket {
this.input goto 14
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
import net.mamoe.mirai.message.defaults.MessageChain
import net.mamoe.mirai.message.defaults.PlainText
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.toUHexString
import java.io.ByteArrayOutputStream
......@@ -9,15 +10,50 @@ import java.io.DataInputStream
import java.util.zip.GZIPInputStream
/**
* Packet id: `00 CE` or `00 17`
*
* @author Him188moe
*/
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 客户端上线
*/
......@@ -32,7 +68,7 @@ class ServerAndroidOfflineEventPacket(input: DataInputStream, packetId: ByteArra
* 群文件上传
*/
class ServerGroupUploadFileEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
lateinit var xmlMessage: String
private lateinit var xmlMessage: String
override fun decode() {
xmlMessage = String(this.input.goto(65).readNBytes(this.input.goto(60).readShort().toInt()))
......@@ -147,7 +183,6 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
var qq: Long = 0
lateinit var message: MessageChain
@ExperimentalUnsignedTypes
override fun decode() {
//start at Sep1.0:27
......@@ -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 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
import net.mamoe.mirai.network.packet.login.*
import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket
import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.getAllDeclaredFields
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.toUHexString
import net.mamoe.mirai.utils.*
import java.io.DataInputStream
/**
......@@ -14,7 +11,9 @@ import java.io.DataInputStream
*/
abstract class ServerPacket(val input: DataInputStream) : Packet {
abstract fun decode()
open fun decode() {
}
companion object {
......@@ -28,23 +27,22 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
return when (val idHex = stream.readInt().toHexString(" ")) {
"08 25 31 01" -> ServerTouchResponsePacketEncrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_01, stream)
"08 25 31 02" -> ServerTouchResponsePacketEncrypted(ServerTouchResponsePacket.Type.TYPE_08_25_31_02, 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 36 31 03", "08 36 31 04", "08 36 31 05", "08 36 31 06" -> {
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`
else -> {
MiraiLogger debug ("ServerLoginResponseResendPacketEncrypted: flag=$idHex"); ServerLoginResponseResendPacket.Flag.OTHER
}
})
871 -> return ServerLoginResponseVerificationCodePacketEncrypted(stream)
871 -> return ServerLoginResponseVerificationCodeInitPacket.Encrypted(stream)
}
if (bytes.size > 700) {
return ServerLoginResponseSuccessPacketEncrypted(stream)
return ServerLoginResponseSuccessPacket.Encrypted(stream)
}
return ServerLoginResponseFailedPacket(when (bytes.size) {
......@@ -63,20 +61,20 @@ abstract class ServerPacket(val input: DataInputStream) : Packet {
}, stream)
}
"08 28 04 34" -> ServerSessionKeyResponsePacketEncrypted(stream)
"08 28 04 34" -> ServerSessionKeyResponsePacket.Encrypted(stream)
else -> when (idHex.substring(0, 5)) {
"00 EC" -> ServerLoginSuccessPacket(stream)
"00 1D" -> ServerSKeyResponsePacketEncrypted(stream)
"00 5C" -> ServerAccountInfoResponsePacketEncrypted(stream)
"00 1D" -> ServerSKeyResponsePacket.Encrypted(stream)
"00 5C" -> ServerAccountInfoResponsePacket.Encrypted(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)
......@@ -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 {
fun <N : Number> DataInputStream.readShortAt(position: N): Short {
this.goto(position)
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
import net.mamoe.mirai.network.Protocol
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.lazyEncode
import java.io.DataInputStream
......@@ -16,8 +16,6 @@ import java.net.InetAddress
class ClientSessionRequestPacket(
private val qq: Long,
private val serverIp: String,
private val loginIP: String,
private val md5_32: ByteArray,
private val token38: ByteArray,
private val token88: ByteArray,
private val encryptionKey: ByteArray,
......@@ -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("00 38")
this.write(token38)
this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() {
this.write(TEA.encrypt(object : ByteArrayDataOutputStream() {
override fun toByteArray(): ByteArray {
this.writeHex("00 07 00 88")
this.write(token88)
......@@ -36,10 +34,10 @@ class ClientSessionRequestPacket(
this.writeIP(serverIp)
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(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(Protocol._0825data0)
this.writeHex(Protocol._0825data2)
this.writeHex(Protocol.constantData0)
this.writeHex(Protocol.constantData1)
this.writeQQ(qq)
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
......@@ -51,7 +49,7 @@ class ClientSessionRequestPacket(
//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.write(md5_32)
this.write(getRandomKey(32))//md5 32
this.writeHex("68")
this.writeHex("00 00 00 00 00 2D 00 06 00 01")
......@@ -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)
}
}
class ServerSessionKeyResponsePacketEncrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
override fun decode() {
}
fun decrypt(_0828_rec_decr_key: ByteArray): ServerSessionKeyResponsePacket {
this.input goto 14
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
return ServerSessionKeyResponsePacket(TEACryptor.decrypt(data, _0828_rec_decr_key).dataInputStream(), data.size);
class Encrypted(inputStream: DataInputStream) : ServerPacket(inputStream) {
fun decrypt(_0828_rec_decr_key: ByteArray): ServerSessionKeyResponsePacket {
this.input goto 14
val data = this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }
return ServerSessionKeyResponsePacket(TEA.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
}
}
}
}
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) {
ServerTouchResponsePacket.Type.TYPE_08_25_31_02 -> Protocol.redirectionKey.hexToBytes()
ServerTouchResponsePacket.Type.TYPE_08_25_31_01 -> Protocol._0825key.hexToBytes()
}).inputStream()));
class Encrypted(private val type: Type, inputStream: DataInputStream) : ServerPacket(inputStream) {
@ExperimentalUnsignedTypes
fun decrypt(): ServerTouchResponsePacket = ServerTouchResponsePacket(decryptBy(when (type) {
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() {
override fun encode() {
this.writeQQ(qq)
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)
override fun toByteArray(): ByteArray {
this.writeHex(Protocol._0825data0)
this.writeHex(Protocol._0825data2)
this.writeHex(Protocol.constantData0)
this.writeHex(Protocol.constantData1)
this.writeQQ(qq)
this.writeHex("00 00 00 00 03 09 00 08 00 01")
this.writeIP(serverIp);
......@@ -116,11 +105,11 @@ class ClientServerRedirectionPacket(private val serverIP: String, private val qq
this.writeHex(Protocol.redirectionKey)
this.write(TEACryptor.encrypt(object : ByteArrayDataOutputStream() {
this.write(TEA.encrypt(object : ByteArrayDataOutputStream() {
@Throws(IOException::class)
override fun toByteArray(): ByteArray {
this.writeHex(Protocol._0825data0)
this.writeHex(Protocol._0825data2)
this.writeHex(Protocol.constantData0)
this.writeHex(Protocol.constantData1)
this.writeQQ(qq)
this.writeHex("00 01 00 00 03 09 00 0C 00 01")
this.writeIP(serverIP)
......
......@@ -23,11 +23,11 @@ class ClientVerificationCodeTransmissionRequestPacket(
this.writeByte(count)//part of packet id
this.writeQQ(qq)
this.writeHex(Protocol._fixVer)
this.writeHex(Protocol._00BaKey)
this.encryptAndWrite(Protocol._00BaKey) {
this.writeHex(Protocol.fixVer2)
this.writeHex(Protocol.key00BA)
this.encryptAndWrite(Protocol.key00BA) {
it.writeHex("00 02 00 00 08 04 01 E0")
it.writeHex(Protocol._0825data2)
it.writeHex(Protocol.constantData1)
it.writeHex("00 00 38")
it.write(token0825)
it.writeHex("01 03 00 19")
......@@ -37,7 +37,7 @@ class ClientVerificationCodeTransmissionRequestPacket(
it.writeHex("00 28")
it.write(token00BA)
it.writeHex("00 10")
it.writeHex(Protocol._00BaFixKey)
it.writeHex(Protocol.key00BAFix)
}
}
}
......@@ -87,22 +87,19 @@ class ServerVerificationCodeRepeatPacket(input: DataInputStream) : ServerVerific
}
}
abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input)
@PacketId("00 BA")
class ServerVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) {
override fun decode() {
}
@ExperimentalUnsignedTypes
fun decrypt(): ServerVerificationCodePacket {
this.input goto 14
val data = TEACryptor.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) }, Protocol._00BaKey.hexToBytes())
return if (data.size == 95) {
ServerVerificationCodeRepeatPacket(data.dataInputStream())
} else {
ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4))
abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input) {
@PacketId("00 BA")
class Encrypted(input: DataInputStream) : ServerPacket(input) {
@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())
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.*
import net.mamoe.mirai.utils.ClientLoginStatus
/**
* 改变在线状态: "我在线上", "隐身" 等
*
* @author Him188moe
*/
@ExperimentalUnsignedTypes
@PacketId("00 EC")
class ClientLoginStatusPacket(
class ClientChangeOnlineStatusPacket(
private val qq: Long,
private val sessionKey: ByteArray,
private val loginStatus: ClientLoginStatus
......@@ -18,7 +20,7 @@ class ClientLoginStatusPacket(
override fun encode() {
this.writeRandom(2)//part of packet id
this.writeQQ(qq)
this.writeHex(Protocol._fixVer)
this.writeHex(Protocol.fixVer2)
this.encryptAndWrite(sessionKey) {
it.writeHex("01 00")
it.writeByte(loginStatus.id)
......
......@@ -4,7 +4,7 @@ import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.*
import net.mamoe.mirai.util.TestedSuccessfully
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.toUHexString
import java.io.DataOutputStream
......@@ -28,10 +28,10 @@ class ClientPasswordSubmissionPacket(
@ExperimentalUnsignedTypes
override fun encode() {
this.writeQQ(qq)
this.writeHex(Protocol._0836_622_fix1)
this.writeHex(Protocol.passwordSubmissionKey1)
this.writeHex(Protocol.publicKey)
this.writeHex("00 00 00 10")
this.writeHex(Protocol._0836key1)
this.writeHex(Protocol.key0836)
this.encryptAndWrite(Protocol.shareKey.hexToBytes()) {
it.writePart1(qq, password, loginTime, loginIP, tgtgtKey, token0825)
......@@ -69,12 +69,12 @@ open class ClientLoginResendPacket internal constructor(
) : ClientPacket() {
override fun encode() {
this.writeQQ(qq)
this.writeHex(Protocol._0836_622_fix1)
this.writeHex(Protocol.passwordSubmissionKey1)
this.writeHex(Protocol.publicKey)
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 {
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
this.writeTLV0006(qq, password, loginTime, loginIP, tgtgtKey)
}
//fix
this.writeHex(Protocol._0836_622_fix2)
this.writeHex(Protocol.passwordSubmissionKey2)
this.writeHex("00 1A")//tag
this.writeHex("00 40")//length
this.write(TEACryptor.encrypt(Protocol._0836_622_fix2.hexToBytes(), tgtgtKey))
this.writeHex(Protocol._0825data0)
this.writeHex(Protocol._0825data2)
this.write(TEA.encrypt(Protocol.passwordSubmissionKey2.hexToBytes(), tgtgtKey))
this.writeHex(Protocol.constantData0)
this.writeHex(Protocol.constantData1)
this.writeQQ(qq)
this.writeZero(4)
......
package net.mamoe.mirai.network.packet.login
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.ServerPacket
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.network.packet.*
import net.mamoe.mirai.util.TestedSuccessfully
import net.mamoe.mirai.utils.TEACryptor
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.TEA
import net.mamoe.mirai.utils.toUHexString
import java.io.DataInputStream
......@@ -117,21 +113,14 @@ class ServerLoginResponseSuccessPacket(input: DataInputStream) : ServerPacket(in
//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 {
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)
}
}
}
\ No newline at end of file
......@@ -2,10 +2,8 @@ package net.mamoe.mirai.network.packet.login
import net.mamoe.mirai.network.packet.PacketId
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.util.TestedSuccessfully
import net.mamoe.mirai.utils.TEACryptor
import java.io.DataInputStream
/**
......@@ -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
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.goto
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 java.io.DataInputStream
......@@ -32,6 +33,19 @@ class ServerLoginResponseVerificationCodeInitPacket(input: DataInputStream, priv
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() {
......@@ -54,15 +68,3 @@ verify code
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
*/
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
import java.io.DataInputStream
/**
* Congratulations!
*
* @author Him188moe
*/
class ServerLoginSuccessPacket(input: DataInputStream) : ServerPacket(input) {
override fun decode() {
}
}
\ No newline at end of file
class ServerLoginSuccessPacket(input: DataInputStream) : ServerPacket(input)
\ No newline at end of file
......@@ -19,7 +19,7 @@ class ClientSendFriendMessagePacket(
override fun encode() {
this.writeRandom(2)//part of packet id
this.writeQQ(robotQQ)
this.writeHex(Protocol._fixVer)
this.writeHex(Protocol.fixVer2)
this.encryptAndWrite(sessionKey) {
it.writeQQ(robotQQ)
......@@ -58,7 +58,4 @@ class ClientSendFriendMessagePacket(
}
@PacketId("00 CD")
class ServerSendFriendMessageResponsePacket(input: DataInputStream) : ServerPacket(input) {
override fun decode() {
}
}
\ No newline at end of file
class ServerSendFriendMessageResponsePacket(input: DataInputStream) : ServerPacket(input)
\ No newline at end of file
......@@ -2,7 +2,6 @@ package net.mamoe.mirai.network.packet.message
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.*
import net.mamoe.mirai.utils.lazyEncode
import net.mamoe.mirai.utils.toUHexString
import java.io.DataInputStream
......@@ -13,14 +12,14 @@ import java.io.DataInputStream
@ExperimentalUnsignedTypes
class ClientSendGroupMessagePacket(
private val groupId: Long,//不是 number
private val qq: Long,
private val robotQQ: Long,
private val sessionKey: ByteArray,
private val message: String
) : ClientPacket() {
override fun encode() {
this.writeRandom(2)//part of packet id
this.writeQQ(qq)
this.writeHex(Protocol._fixVer)
this.writeQQ(robotQQ)
this.writeHex(Protocol.fixVer2)
this.encryptAndWrite(sessionKey) {
val bytes = message.toByteArray()
......@@ -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")
class ServerSendGroupMessageResponsePacket(input: DataInputStream) : ServerPacket(input) {
override fun decode() {
}
}
\ No newline at end of file
class ServerSendGroupMessageResponsePacket(input: DataInputStream) : ServerPacket(input)
\ No newline at end of file
......@@ -4,10 +4,14 @@ package net.mamoe.mirai.utils;
* @author Him188moe
*/
public enum ClientLoginStatus {
/**
* 我在线上
*/
ONLINE(0x0A);
// TODO: 2019/8/31 add more
public final int id;//1byte
// TODO: 2019/8/31 add more ClientLoginStatus
public final int id;//1 ubyte
ClientLoginStatus(int 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;
/**
* @author iweiz https://github.com/iweizime/StepChanger/blob/master/app/src/main/java/me/iweizi/stepchanger/qq/Cryptor.java
*/
public class TEACryptor {
public static final TEACryptor CRYPTOR_SHARE_KEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol.shareKey));
public static final TEACryptor CRYPTOR_0825KEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol._0825key));
public static final TEACryptor CRYPTOR_00BAKEY = new TEACryptor(Protocol.Companion.hexToBytes(Protocol._00BaKey));
public class TEA {
public static final TEA CRYPTOR_SHARE_KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.shareKey));
public static final TEA CRYPTOR_0825KEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key0825));
public static final TEA CRYPTOR_00BAKEY = new TEA(Protocol.Companion.hexToBytes(Protocol.key00BA));
private static final long UINT32_MASK = 0xffffffffL;
private final long[] mKey;
......@@ -25,7 +25,7 @@ public class TEACryptor {
private boolean isFirstBlock;
private boolean isRand;
public TEACryptor(byte[] key) {
public TEA(byte[] key) {
mKey = new long[4];
for (int i = 0; i < 4; i++) {
mKey[i] = pack(key, i * 4, 4);
......@@ -36,11 +36,19 @@ public class TEACryptor {
}
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) {
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) {
......
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