mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-23 22:00:10 +08:00
Updated verification code processing
This commit is contained in:
parent
beb64dd436
commit
7ca62bb0c8
@ -1,28 +1,14 @@
|
||||
package net.mamoe.mirai;
|
||||
|
||||
|
||||
import net.mamoe.mirai.utils.config.MiraiConfig;
|
||||
import net.mamoe.mirai.utils.config.MiraiConfigSection;
|
||||
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
public final class MiraiMain {
|
||||
private static MiraiServer server;
|
||||
|
||||
public static void main(String[] args) {
|
||||
server = new MiraiServer();
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
server.shutdown();
|
||||
}));
|
||||
MiraiConfig config = new MiraiConfig("QQ.yml");
|
||||
MiraiConfigSection<Object> data = config.getSection("123123");
|
||||
data.put("account","123123a");
|
||||
try {
|
||||
Robot robot = new Robot(data);
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> server.shutdown()));
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ 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.ClientTouchPacket;
|
||||
import net.mamoe.mirai.task.MiraiTaskManager;
|
||||
import net.mamoe.mirai.utils.LoggerTextFormat;
|
||||
import net.mamoe.mirai.utils.MiraiLogger;
|
||||
@ -17,7 +16,6 @@ import net.mamoe.mirai.utils.setting.MiraiSettingMapSection;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class MiraiServer {
|
||||
@ -119,62 +117,20 @@ public class MiraiServer {
|
||||
getLogger().info("ready to connect");
|
||||
|
||||
|
||||
/*
|
||||
MiraiConfigSection section = new MiraiConfigSection<MiraiConfigSection<String>>(){{
|
||||
put("1",new MiraiConfigSection<>(){{
|
||||
put("1","0");
|
||||
}});
|
||||
}};
|
||||
this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> {
|
||||
try {
|
||||
Robot robot = new Robot(section);
|
||||
RobotNetworkHandler robotNetworkHandler = robot.getHandler();
|
||||
robotNetworkHandler.setServerIP("14.116.136.106");
|
||||
robotNetworkHandler.touch$mirai_core();
|
||||
|
||||
this.qqs.put("test",section);
|
||||
this.qqs.save();
|
||||
*/
|
||||
|
||||
|
||||
MiraiConfigSection<MiraiConfigSection> x = this.qqs.getTypedSection("test");
|
||||
//System.out.println(x.getSection("1").getInt("1"));
|
||||
|
||||
/*
|
||||
System.out.println(v);
|
||||
|
||||
System.out.println(v.get("1111"));
|
||||
*/
|
||||
|
||||
|
||||
Robot robot = new Robot(1994701021, "xiaoqqq", new LinkedList<>());
|
||||
RobotNetworkHandler robotNetworkHandler = robot.getHandler();
|
||||
try {
|
||||
//System.out.println(Protocol.Companion.getSERVER_IP().get(3));
|
||||
//System.out.println(Protocol.Companion.getSERVER_IP().toString());
|
||||
|
||||
robotNetworkHandler.setServerIP("14.116.136.106");
|
||||
robotNetworkHandler.sendPacket(new ClientTouchPacket(1994701021, "14.116.136.106"));
|
||||
while (true) ;
|
||||
//robotNetworkHandler.connect("14.116.136.106");
|
||||
//robotNetworkHandler.connect(Protocol.Companion.getSERVER_IP().get(2));
|
||||
//robotNetworkHandler.connect("125.39.132.242");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
/*
|
||||
System.out.println("network test");
|
||||
try {
|
||||
|
||||
|
||||
MiraiUDPServer server = new MiraiUDPServer();
|
||||
MiraiUDPClient client = new MiraiUDPClient(InetAddress.getLocalHost(),9999,MiraiNetwork.getAvailablePort());
|
||||
this.getTaskManager().repeatingTask(() -> {
|
||||
byte[] sendInfo = "test test".getBytes(StandardCharsets.UTF_8);
|
||||
try {
|
||||
client.send(new DatagramPacket(sendInfo,sendInfo.length));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
},300);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}*/
|
||||
Robot.instances.add(robot);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
getLogger().error("Could not load QQ robots config!");
|
||||
System.exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initSetting(File setting) {
|
||||
|
@ -9,11 +9,13 @@ import net.mamoe.mirai.utils.config.MiraiConfigSection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class Robot {
|
||||
public static final List<Robot> instances = Collections.synchronizedList(new LinkedList<>());
|
||||
|
||||
private final int qqNumber;
|
||||
private final long qqNumber;
|
||||
private final String password;
|
||||
@Getter
|
||||
private final RobotNetworkHandler handler;
|
||||
@ -31,38 +33,41 @@ public class Robot {
|
||||
return owners.contains(ownerName);
|
||||
}
|
||||
|
||||
public long getQQNumber() {
|
||||
return qqNumber;
|
||||
}
|
||||
|
||||
public Robot(MiraiConfigSection<Object> data) throws Throwable {
|
||||
this(
|
||||
data.getIntOrThrow("account", () -> new IllegalArgumentException("account")),
|
||||
data.getLongOrThrow("account", () -> new IllegalArgumentException("account")),
|
||||
data.getStringOrThrow("password", () -> new IllegalArgumentException("password")),
|
||||
data.getAsOrDefault("owners", ArrayList::new)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public Robot(int qqNumber, String password, List<String> owners) {
|
||||
public Robot(long qqNumber, String password, List<String> owners) {
|
||||
this.qqNumber = qqNumber;
|
||||
this.password = password;
|
||||
this.owners = Collections.unmodifiableList(owners);
|
||||
this.handler = new RobotNetworkHandler(this, this.qqNumber, this.password);
|
||||
}
|
||||
|
||||
public QQ getQQ(int qqNumber) {
|
||||
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(int groupNumber) {
|
||||
public Group getGroup(long groupNumber) {
|
||||
if (!this.groups.containsKey(groupNumber)) {
|
||||
this.groups.put(groupNumber, new Group(groupNumber));
|
||||
}
|
||||
return groups.get(groupNumber);
|
||||
}
|
||||
|
||||
public Group getGroupByGroupId(int groupId) {
|
||||
public Group getGroupByGroupId(long groupId) {
|
||||
return getGroup(Group.Companion.groupIdToNumber(groupId));
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import net.mamoe.mirai.message.defaults.PlainText
|
||||
*
|
||||
* @author Him188moe
|
||||
*/
|
||||
abstract class Contact(val number: Int) {
|
||||
abstract class Contact(val number: Long) {
|
||||
|
||||
/**
|
||||
* Async
|
||||
|
@ -3,14 +3,10 @@ package net.mamoe.mirai.contact
|
||||
import net.mamoe.mirai.message.Message
|
||||
import net.mamoe.mirai.utils.ContactList
|
||||
|
||||
class Group(number: Int) : Contact(number) {
|
||||
class Group(number: Long) : Contact(number) {
|
||||
val groupId = groupNumberToId(number)
|
||||
val members = ContactList<QQ>()
|
||||
|
||||
init {
|
||||
Instances.groups.add(this)
|
||||
}
|
||||
|
||||
override fun sendMessage(message: Message) {
|
||||
|
||||
}
|
||||
@ -20,38 +16,38 @@ class Group(number: Int) : Contact(number) {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun groupNumberToId(number: Int): Int {
|
||||
val left: Int = number.toString().let {
|
||||
fun groupNumberToId(number: Long): Long {
|
||||
val left: Long = number.toString().let {
|
||||
if (it.length < 6) {
|
||||
return@groupNumberToId number
|
||||
}
|
||||
it.substring(0, it.length - 6).toInt()
|
||||
it.substring(0, it.length - 6).toLong()
|
||||
}
|
||||
val right: Int = number.toString().let {
|
||||
it.substring(it.length - 6).toInt()
|
||||
val right: Long = number.toString().let {
|
||||
it.substring(it.length - 6).toLong()
|
||||
}
|
||||
|
||||
return when (left) {
|
||||
in 1..10 -> {
|
||||
((left + 202).toString() + right.toString()).toInt()
|
||||
((left + 202).toString() + right.toString()).toLong()
|
||||
}
|
||||
in 11..19 -> {
|
||||
((left + 469).toString() + right.toString()).toInt()
|
||||
((left + 469).toString() + right.toString()).toLong()
|
||||
}
|
||||
in 20..66 -> {
|
||||
((left + 208).toString() + right.toString()).toInt()
|
||||
((left + 208).toString() + right.toString()).toLong()
|
||||
}
|
||||
in 67..156 -> {
|
||||
((left + 1943).toString() + right.toString()).toInt()
|
||||
((left + 1943).toString() + right.toString()).toLong()
|
||||
}
|
||||
in 157..209 -> {
|
||||
((left + 199).toString() + right.toString()).toInt()
|
||||
((left + 199).toString() + right.toString()).toLong()
|
||||
}
|
||||
in 210..309 -> {
|
||||
((left + 389).toString() + right.toString()).toInt()
|
||||
((left + 389).toString() + right.toString()).toLong()
|
||||
}
|
||||
in 310..499 -> {
|
||||
((left + 349).toString() + right.toString()).toInt()
|
||||
((left + 349).toString() + right.toString()).toLong()
|
||||
}
|
||||
else -> number
|
||||
}
|
||||
@ -62,60 +58,60 @@ class Group(number: Int) : Contact(number) {
|
||||
groupNumberToId(580266363)
|
||||
}
|
||||
|
||||
fun groupIdToNumber(id: Int): Int {
|
||||
var left: Int = id.toString().let {
|
||||
fun groupIdToNumber(id: Long): Long {
|
||||
var left: Long = id.toString().let {
|
||||
if (it.length < 6) {
|
||||
return@groupIdToNumber id
|
||||
}
|
||||
it.substring(0 until it.length - 6).toInt()
|
||||
it.substring(0 until it.length - 6).toLong()
|
||||
}
|
||||
|
||||
return when (left) {
|
||||
in 203..212 -> {
|
||||
val right: Int = id.toString().let {
|
||||
it.substring(it.length - 6).toInt()
|
||||
val right: Long = id.toString().let {
|
||||
it.substring(it.length - 6).toLong()
|
||||
}
|
||||
((left - 202).toString() + right.toString()).toInt()
|
||||
((left - 202).toString() + right.toString()).toLong()
|
||||
}
|
||||
in 480..488 -> {
|
||||
val right: Int = id.toString().let {
|
||||
it.substring(it.length - 6).toInt()
|
||||
val right: Long = id.toString().let {
|
||||
it.substring(it.length - 6).toLong()
|
||||
}
|
||||
((left - 469).toString() + right.toString()).toInt()
|
||||
((left - 469).toString() + right.toString()).toLong()
|
||||
}
|
||||
in 2100..2146 -> {
|
||||
val right: Int = id.toString().let {
|
||||
it.substring(it.length - 7).toInt()
|
||||
val right: Long = id.toString().let {
|
||||
it.substring(it.length - 7).toLong()
|
||||
}
|
||||
left = left.toString().substring(0 until 3).toInt()
|
||||
((left - 208).toString() + right.toString()).toInt()
|
||||
left = left.toString().substring(0 until 3).toLong()
|
||||
((left - 208).toString() + right.toString()).toLong()
|
||||
}
|
||||
in 2010..2099 -> {
|
||||
val right: Int = id.toString().let {
|
||||
it.substring(it.length - 6).toInt()
|
||||
val right: Long = id.toString().let {
|
||||
it.substring(it.length - 6).toLong()
|
||||
}
|
||||
((left - 1943).toString() + right.toString()).toInt()
|
||||
((left - 1943).toString() + right.toString()).toLong()
|
||||
}
|
||||
in 2147..2199 -> {
|
||||
val right: Int = id.toString().let {
|
||||
it.substring(it.length - 7).toInt()
|
||||
val right: Long = id.toString().let {
|
||||
it.substring(it.length - 7).toLong()
|
||||
}
|
||||
left = left.toString().substring(0 until 3).toInt()
|
||||
((left - 199).toString() + right.toString()).toInt()
|
||||
left = left.toString().substring(0 until 3).toLong()
|
||||
((left - 199).toString() + right.toString()).toLong()
|
||||
}
|
||||
in 4100..4199 -> {
|
||||
val right: Int = id.toString().let {
|
||||
it.substring(it.length - 7).toInt()
|
||||
val right: Long = id.toString().let {
|
||||
it.substring(it.length - 7).toLong()
|
||||
}
|
||||
left = left.toString().substring(0 until 3).toInt()
|
||||
((left - 389).toString() + right.toString()).toInt()
|
||||
left = left.toString().substring(0 until 3).toLong()
|
||||
((left - 389).toString() + right.toString()).toLong()
|
||||
}
|
||||
in 3800..3989 -> {
|
||||
val right: Int = id.toString().let {
|
||||
it.substring(it.length - 7).toInt()
|
||||
val right: Long = id.toString().let {
|
||||
it.substring(it.length - 7).toLong()
|
||||
}
|
||||
left = left.toString().substring(0 until 3).toInt()
|
||||
((left - 349).toString() + right.toString()).toInt()
|
||||
left = left.toString().substring(0 until 3).toLong()
|
||||
((left - 349).toString() + right.toString()).toLong()
|
||||
}
|
||||
else -> id
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
package net.mamoe.mirai.contact
|
||||
|
||||
|
||||
fun Int.asQQ(): QQ = Instances.qqs.stream().filter { t: QQ? -> t?.number?.equals(this)!! }.findAny().orElse(QQ(this))!!
|
||||
|
||||
fun Int.asGroup(): Group = Instances.groups.stream().filter { t: Group? -> t?.number?.equals(this)!! }.findAny().orElse(Group(this))!!
|
||||
|
||||
fun String.withImage(id: String, type: String) = "{$id}.$type"
|
||||
|
||||
fun String.withAt(qq: Int) = qq.asQQ().at()
|
||||
|
||||
fun String.withAt(qq: QQ) = qq.at()
|
||||
|
||||
object Instances {
|
||||
var qqs = arrayListOf<QQ>()
|
||||
var groups = arrayListOf<Group>()
|
||||
}
|
@ -6,10 +6,7 @@ import net.mamoe.mirai.message.defaults.At
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
class QQ(number: Int) : Contact(number) {
|
||||
init {
|
||||
Instances.qqs.add(this)
|
||||
}
|
||||
class QQ(number: Long) : Contact(number) {
|
||||
|
||||
override fun sendMessage(message: Message) {
|
||||
|
||||
|
@ -10,17 +10,17 @@ import java.util.Objects;
|
||||
* @author Him188moe
|
||||
*/
|
||||
public final class At extends Message {
|
||||
private final int target;
|
||||
private final long target;
|
||||
|
||||
public At(@NotNull QQ target) {
|
||||
this(Objects.requireNonNull(target).getNumber());
|
||||
}
|
||||
|
||||
public At(int target) {
|
||||
public At(long target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public int getTarget() {
|
||||
public long getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.mamoe.mirai.network
|
||||
|
||||
import net.mamoe.mirai.MiraiServer
|
||||
import net.mamoe.mirai.Robot
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.event.events.qq.FriendMessageEvent
|
||||
@ -10,12 +9,8 @@ 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.ServerSendGroupMessageResponsePacket
|
||||
import net.mamoe.mirai.network.packet.verification.ServerVerificationCodePacket
|
||||
import net.mamoe.mirai.network.packet.verification.ServerVerificationCodePacketEncrypted
|
||||
import net.mamoe.mirai.task.MiraiThreadPool
|
||||
import net.mamoe.mirai.utils.*
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.net.DatagramPacket
|
||||
import java.net.DatagramSocket
|
||||
import java.net.InetSocketAddress
|
||||
@ -28,9 +23,7 @@ import java.util.concurrent.TimeUnit
|
||||
* @author Him188moe
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
class RobotNetworkHandler(val robot: Robot, val number: Int, private val password: String) {
|
||||
|
||||
private var sequence: Int = 0
|
||||
class RobotNetworkHandler(val robot: Robot, val number: Long, private val password: String) {
|
||||
|
||||
var socket: DatagramSocket = DatagramSocket((15314 + Math.random() * 100).toInt())
|
||||
|
||||
@ -39,33 +32,7 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
|
||||
serverAddress = InetSocketAddress(value, 8000)
|
||||
field = value
|
||||
|
||||
socket.close()
|
||||
socket = DatagramSocket((15314 + Math.random() * 100).toInt())
|
||||
socket.connect(this.serverAddress)
|
||||
val zeroByte: Byte = 0
|
||||
Thread {
|
||||
while (true) {
|
||||
val dp1 = DatagramPacket(ByteArray(2048), 2048)
|
||||
try {
|
||||
socket.receive(dp1)
|
||||
} catch (e: Exception) {
|
||||
if (e.message == "socket closed") {
|
||||
return@Thread
|
||||
}
|
||||
}
|
||||
MiraiThreadPool.getInstance().submit {
|
||||
var i = dp1.data.size - 1;
|
||||
while (dp1.data[i] == zeroByte) {
|
||||
--i
|
||||
}
|
||||
try {
|
||||
onPacketReceived(ServerPacket.ofByteArray(dp1.data.copyOfRange(0, i + 1)))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
restartSocket()
|
||||
}
|
||||
|
||||
private lateinit var serverAddress: InetSocketAddress
|
||||
@ -78,6 +45,10 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
|
||||
private var tlv0105: ByteArray
|
||||
private lateinit var _0828_rec_decr_key: ByteArray
|
||||
|
||||
private var verificationCodeSequence: Int = 0//这两个验证码使用
|
||||
private var verificationCodeCache: ByteArray? = null//每次包只发一部分验证码来
|
||||
private var verificationCodeCacheCount: Int = 0//
|
||||
private lateinit var verificationToken: ByteArray
|
||||
|
||||
private lateinit var sessionKey: ByteArray//这两个是登录成功后得到的
|
||||
private lateinit var sKey: String
|
||||
@ -104,6 +75,40 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
|
||||
private var md5_32: ByteArray = getRandomKey(32)
|
||||
|
||||
|
||||
internal fun touch() {
|
||||
this.sendPacket(ClientTouchPacket(this.number, this.serverIP))
|
||||
}
|
||||
|
||||
private fun restartSocket() {
|
||||
socket.close()
|
||||
socket = DatagramSocket((15314 + Math.random() * 100).toInt())
|
||||
socket.connect(this.serverAddress)
|
||||
val zeroByte: Byte = 0
|
||||
Thread {
|
||||
while (true) {
|
||||
val dp1 = DatagramPacket(ByteArray(2048), 2048)
|
||||
try {
|
||||
socket.receive(dp1)
|
||||
} catch (e: Exception) {
|
||||
if (e.message == "socket closed") {
|
||||
return@Thread
|
||||
}
|
||||
}
|
||||
MiraiThreadPool.getInstance().submit {
|
||||
var i = dp1.data.size - 1;
|
||||
while (dp1.data[i] == zeroByte) {
|
||||
--i
|
||||
}
|
||||
try {
|
||||
onPacketReceived(ServerPacket.ofByteArray(dp1.data.copyOfRange(0, i + 1)))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
internal fun onPacketReceived(packet: ServerPacket) {
|
||||
packet.decode()
|
||||
@ -131,22 +136,44 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
|
||||
return
|
||||
}
|
||||
|
||||
is ServerLoginResponseVerificationCodePacket -> {
|
||||
is ServerLoginResponseVerificationCodeInitPacket -> {
|
||||
//[token00BA]来源之一: 验证码
|
||||
this.token00BA = packet.token00BA
|
||||
this.verificationCodeCache = packet.verifyCodePart1
|
||||
|
||||
with(MiraiServer.getInstance().parentFolder + "verifyCode.png") {
|
||||
ByteArrayInputStream(packet.verifyCode).transferTo(FileOutputStream(this))
|
||||
println("验证码已写入到 " + this.path)
|
||||
}
|
||||
|
||||
if (packet.unknownBoolean != null && packet.unknownBoolean!!) {
|
||||
this.sequence = 1
|
||||
sendPacket(ClientLoginVerificationCodePacket(this.number, this.token0825, this.sequence, this.token00BA))
|
||||
this.verificationCodeSequence = 1
|
||||
sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, this.number, this.token0825, this.verificationCodeSequence, this.token00BA))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
is ServerVerificationCodeRepeatPacket -> {//todo 这个名字正确么
|
||||
this.tgtgtKey = packet.tgtgtKeyUpdate
|
||||
this.token00BA = packet.token00BA
|
||||
sendPacket(ClientLoginResendPacket3105(this.number, this.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA))
|
||||
}
|
||||
|
||||
is ServerVerificationCodeTransmissionPacket -> {
|
||||
this.verificationCodeSequence = 0
|
||||
this.verificationCodeCache = this.verificationCodeCache!! + packet.verificationCodePart2
|
||||
|
||||
this.verificationToken = packet.verificationToken
|
||||
this.verificationCodeCacheCount = packet.count
|
||||
|
||||
this.token00BA = packet.token00BA
|
||||
this.verificationCodeCache
|
||||
|
||||
|
||||
if (packet.transmissionCompleted) {
|
||||
this.verificationCodeCache
|
||||
TODO("验证码好了")
|
||||
} else {
|
||||
sendPacket(ClientVerificationCodeTransmissionRequestPacket(packet.count, this.number, this.token0825, this.verificationCodeSequence, this.token00BA))
|
||||
}
|
||||
}
|
||||
|
||||
is ServerLoginResponseSuccessPacket -> {
|
||||
this._0828_rec_decr_key = packet._0828_rec_decr_key
|
||||
sendPacket(ClientSessionRequestPacket(this.number, this.serverIP, this.loginIP, this.md5_32, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105))
|
||||
@ -190,10 +217,6 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
|
||||
}
|
||||
}
|
||||
|
||||
is ServerVerificationCodePacket -> {
|
||||
this.sequence++
|
||||
|
||||
}
|
||||
|
||||
is ServerSessionKeyResponsePacket -> {
|
||||
this.sessionKey = packet.sessionKey
|
||||
@ -267,7 +290,7 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
|
||||
|
||||
is ServerMessageEventPacketRaw -> onPacketReceived(packet.analyze())
|
||||
|
||||
is ServerVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt(this.token00BA))
|
||||
is ServerVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt())
|
||||
is ServerLoginResponseVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt())
|
||||
is ServerLoginResponseResendPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
|
||||
is ServerLoginResponseSuccessPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
|
||||
|
@ -12,7 +12,7 @@ import java.io.DataInputStream
|
||||
@ExperimentalUnsignedTypes
|
||||
@PacketId("00 5C")
|
||||
class ClientAccountInfoRequestPacket(
|
||||
private val qq: Int,
|
||||
private val qq: Long,
|
||||
private val sessionKey: ByteArray
|
||||
) : ClientPacket() {
|
||||
override fun encode() {
|
||||
|
@ -119,13 +119,18 @@ fun DataOutputStream.encryptAndWrite(key: ByteArray, encoder: (ByteArrayDataOutp
|
||||
this.write(TEACryptor.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() }, key))
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
fun DataOutputStream.encryptAndWrite(keyHex: String, encoder: (ByteArrayDataOutputStream) -> Unit) {
|
||||
this.encryptAndWrite(keyHex.hexToBytes(), encoder)
|
||||
}
|
||||
|
||||
fun DataOutputStream.encryptAndWrite(cryptor: TEACryptor, encoder: (ByteArrayDataOutputStream) -> Unit) {
|
||||
this.write(cryptor.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() }))
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
@Throws(IOException::class)
|
||||
fun DataOutputStream.writeTLV0006(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray) {
|
||||
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.writeHex("00 02")
|
||||
@ -134,7 +139,7 @@ fun DataOutputStream.writeTLV0006(qq: Int, password: String, loginTime: Int, log
|
||||
it.writeHex("00 00 01")
|
||||
|
||||
val md5_1 = md5(password);
|
||||
val md5_2 = md5(md5_1 + "00 00 00 00".hexToBytes() + qq.toByteArray())
|
||||
val md5_2 = md5(md5_1 + "00 00 00 00".hexToBytes() + qq.toUInt().toByteArray())
|
||||
println(md5_1.toUByteArray().toUHexString())
|
||||
println(md5_2.toUByteArray().toUHexString())
|
||||
it.write(md5_1)
|
||||
@ -193,6 +198,17 @@ fun Int.toByteArray(): ByteArray = byteArrayOf(
|
||||
(this.ushr(0) and 0xFF).toByte()
|
||||
)
|
||||
|
||||
/**
|
||||
* 255u -> 00 00 00 FF
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
fun UInt.toByteArray(): ByteArray = byteArrayOf(
|
||||
(this.shr(24) and 255u).toByte(),
|
||||
(this.shr(16) and 255u).toByte(),
|
||||
(this.shr(8) and 255u).toByte(),
|
||||
(this.shr(0) and 255u).toByte()
|
||||
)
|
||||
|
||||
/**
|
||||
* 255 -> FF 00 00 00
|
||||
*/
|
||||
@ -225,7 +241,14 @@ fun DataOutputStream.writeRandom(length: Int) {
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
@Throws(IOException::class)
|
||||
fun DataOutputStream.writeQQ(qq: Int) {
|
||||
this.writeInt(qq)
|
||||
fun DataOutputStream.writeQQ(qq: Long) {
|
||||
this.write(qq.toUInt().toByteArray())
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
@Throws(IOException::class)
|
||||
fun DataOutputStream.writeGroup(groupIdOrGroupNumber: Long) {
|
||||
this.write(groupIdOrGroupNumber.toUInt().toByteArray())
|
||||
}
|
@ -10,7 +10,7 @@ import java.io.IOException
|
||||
@ExperimentalUnsignedTypes
|
||||
@PacketId("00 58")
|
||||
class ClientHeartbeatPacket(
|
||||
private val qq: Int,
|
||||
private val qq: Long,
|
||||
private val sessionKey: ByteArray
|
||||
) : ClientPacket() {
|
||||
@Throws(IOException::class)
|
||||
|
@ -12,7 +12,7 @@ import java.io.DataInputStream
|
||||
@PacketId("")//随后写入
|
||||
@ExperimentalUnsignedTypes
|
||||
class ClientMessageResponsePacket(
|
||||
private val qq: Int,
|
||||
private val qq: Long,
|
||||
private val packetIdFromServer: ByteArray,
|
||||
private val sessionKey: ByteArray,
|
||||
private val eventIdentity: ByteArray
|
||||
|
@ -11,7 +11,7 @@ import java.io.DataInputStream
|
||||
@ExperimentalUnsignedTypes
|
||||
@PacketId("00 1D")
|
||||
class ClientSKeyRequestPacket(
|
||||
private val qq: Int,
|
||||
private val qq: Long,
|
||||
private val sessionKey: ByteArray
|
||||
) : ClientPacket() {
|
||||
override fun encode() {
|
||||
@ -31,7 +31,7 @@ class ClientSKeyRequestPacket(
|
||||
@PacketId("00 1D")
|
||||
@ExperimentalUnsignedTypes
|
||||
class ClientSKeyRefreshmentRequestPacket(
|
||||
private val qq: Int,
|
||||
private val qq: Long,
|
||||
private val sessionKey: ByteArray
|
||||
) : ClientPacket() {
|
||||
override fun encode() {
|
||||
|
@ -39,8 +39,8 @@ class ServerGroupUploadFileEventPacket(input: DataInputStream, packetId: ByteArr
|
||||
}
|
||||
|
||||
class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
|
||||
var groupNumber: Int = 0
|
||||
var qq: Int = 0
|
||||
var groupNumber: Long = 0
|
||||
var qq: Long = 0
|
||||
lateinit var message: String
|
||||
lateinit var messageType: MessageType
|
||||
|
||||
@ -58,9 +58,10 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
|
||||
OTHER,
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
override fun decode() {
|
||||
groupNumber = this.input.goto(51).readInt()
|
||||
qq = this.input.goto(56).readInt()
|
||||
groupNumber = this.input.goto(51).readInt().toLong()
|
||||
qq = this.input.goto(56).readLong().toUInt().toLong()
|
||||
val fontLength = this.input.goto(108).readShort()
|
||||
//println(this.input.goto(110 + fontLength).readNBytesAt(2).toUHexString())//always 00 00
|
||||
|
||||
@ -142,7 +143,7 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
|
||||
}
|
||||
|
||||
class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
|
||||
var qq: Int = 0
|
||||
var qq: Long = 0
|
||||
lateinit var message: MessageChain
|
||||
|
||||
|
||||
@ -153,7 +154,7 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
|
||||
println(input.readAllBytes().toUHexString())
|
||||
input.goto(0)
|
||||
|
||||
qq = input.readIntAt(0)
|
||||
qq = input.readIntAt(0).toLong()
|
||||
val msgLength = input.readShortAt(22)
|
||||
val fontLength = input.readShortAt(93 + msgLength)
|
||||
val offset = msgLength + fontLength
|
||||
@ -164,6 +165,11 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@ -171,7 +177,7 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
|
||||
backup
|
||||
|
||||
class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
|
||||
var qq: Int = 0
|
||||
var qq: Long = 0
|
||||
lateinit var message: String
|
||||
|
||||
|
||||
|
@ -3,7 +3,6 @@ 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.network.packet.verification.ServerVerificationCodePacketEncrypted
|
||||
import net.mamoe.mirai.utils.getAllDeclaredFields
|
||||
import net.mamoe.mirai.utils.hexToBytes
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
@ -150,6 +149,15 @@ fun <N : Number> DataInputStream.readNBytesAt(position: N, length: Int): ByteArr
|
||||
return this.readNBytes(length)
|
||||
}
|
||||
|
||||
fun <N : Number> DataInputStream.readNBytes(length: N): ByteArray {
|
||||
return this.readNBytes(length.toInt())
|
||||
}
|
||||
|
||||
fun DataInputStream.readNBytesIn(range: IntRange): ByteArray {
|
||||
this.goto(range.first)
|
||||
return this.readNBytes(range.last - range.first + 1)
|
||||
}
|
||||
|
||||
fun <N : Number> DataInputStream.readIntAt(position: N): Int {
|
||||
this.goto(position)
|
||||
return this.readInt();
|
||||
|
@ -14,7 +14,7 @@ import java.net.InetAddress
|
||||
@ExperimentalUnsignedTypes
|
||||
@PacketId("08 28 04 34")
|
||||
class ClientSessionRequestPacket(
|
||||
private val qq: Int,
|
||||
private val qq: Long,
|
||||
private val serverIp: String,
|
||||
private val loginIP: String,
|
||||
private val md5_32: ByteArray,
|
||||
|
@ -76,7 +76,7 @@ class ServerTouchResponsePacketEncrypted(private val type: ServerTouchResponsePa
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
@PacketId("08 25 31 01")
|
||||
class ClientTouchPacket(val qq: Int, val serverIp: String) : ClientPacket() {
|
||||
class ClientTouchPacket(val qq: Long, val serverIp: String) : ClientPacket() {
|
||||
@ExperimentalUnsignedTypes
|
||||
@Throws(IOException::class)
|
||||
override fun encode() {
|
||||
@ -108,7 +108,7 @@ class ClientTouchPacket(val qq: Int, val serverIp: String) : ClientPacket() {
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
@PacketId("08 25 31 02")
|
||||
class ClientServerRedirectionPacket(private val serverIP: String, private val qq: Int) : ClientPacket() {
|
||||
class ClientServerRedirectionPacket(private val serverIP: String, private val qq: Long) : ClientPacket() {
|
||||
@ExperimentalUnsignedTypes
|
||||
override fun encode() {
|
||||
this.writeQQ(qq)
|
||||
|
@ -0,0 +1,98 @@
|
||||
package net.mamoe.mirai.network.packet
|
||||
|
||||
import net.mamoe.mirai.network.Protocol
|
||||
import net.mamoe.mirai.utils.*
|
||||
import java.io.DataInputStream
|
||||
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
@PacketId("00 BA 31")
|
||||
class ClientVerificationCodeTransmissionRequestPacket(//todo 这个包可能有问题.
|
||||
private val count: Int,
|
||||
private val qq: Long,
|
||||
private val token0825: ByteArray,
|
||||
private val verificationSequence: Int,
|
||||
private val token00BA: ByteArray
|
||||
) : ClientPacket() {
|
||||
override fun encode() {
|
||||
this.writeByte(count)//part of packet id
|
||||
|
||||
this.writeQQ(qq)
|
||||
this.writeHex(Protocol._fixVer)
|
||||
this.writeHex(Protocol._00BaKey)
|
||||
this.encryptAndWrite(Protocol._00BaKey) {
|
||||
it.writeHex("00 02 00 00 08 04 01 E0")
|
||||
it.writeHex(Protocol._0825data2)
|
||||
it.writeHex("00 00 38")
|
||||
it.write(token0825)
|
||||
it.writeHex("01 03 00 19")
|
||||
it.writeHex(Protocol.publicKey)
|
||||
it.writeHex("13 00 05 00 00 00 00")
|
||||
it.writeByte(verificationSequence)
|
||||
it.writeHex("00 28")
|
||||
it.write(token00BA)
|
||||
it.writeHex("00 10")
|
||||
it.writeHex(Protocol._00BaFixKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
class ServerVerificationCodeTransmissionPacket(input: DataInputStream, val dataSize: Int, val packetId: ByteArray) : ServerVerificationCodePacket(input) {
|
||||
|
||||
lateinit var verificationCodePart2: ByteArray
|
||||
lateinit var verificationToken: ByteArray//56bytes
|
||||
var transmissionCompleted: Boolean = false//验证码是否已经传输完成
|
||||
lateinit var token00BA: ByteArray//40 bytes
|
||||
var count: Int = 0
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
override fun decode() {
|
||||
this.verificationToken = this.input.readNBytesAt(10, 56)
|
||||
|
||||
val length = this.input.readShortAt(66)
|
||||
this.verificationCodePart2 = this.input.readNBytes(length)
|
||||
|
||||
this.input.skip(2)
|
||||
this.transmissionCompleted = this.input.readBoolean()
|
||||
|
||||
this.token00BA = this.input.readNBytesAt(dataSize - 57, 40)
|
||||
this.count = byteArrayOf(0, 0, packetId[2], packetId[3]).toUHexString().hexToInt()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
class ServerVerificationCodeRepeatPacket(input: DataInputStream) : ServerVerificationCodePacket(input) {
|
||||
|
||||
lateinit var token00BA: ByteArray//56 bytes
|
||||
lateinit var tgtgtKeyUpdate: ByteArray
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
override fun decode() {
|
||||
token00BA = this.input.readNBytesAt(10, 56)
|
||||
tgtgtKeyUpdate = getRandomKey(16)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input)
|
||||
|
||||
class ServerVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) {
|
||||
override fun decode() {
|
||||
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
fun decrypt(): ServerVerificationCodePacket {
|
||||
this.input goto 14
|
||||
val data = TEACryptor.decrypt(Protocol._00BaKey.hexToBytes(), this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) })
|
||||
return if (data.size == 95) {
|
||||
ServerVerificationCodeRepeatPacket(data.dataInputStream())
|
||||
} else {
|
||||
ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4))
|
||||
}
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ import java.io.DataOutputStream
|
||||
@ExperimentalUnsignedTypes
|
||||
@TestedSuccessfully
|
||||
class ClientPasswordSubmissionPacket(
|
||||
private val qq: Int,
|
||||
private val qq: Long,
|
||||
private val password: String,
|
||||
private val loginTime: Int,
|
||||
private val loginIP: String,
|
||||
@ -43,17 +43,22 @@ class ClientPasswordSubmissionPacket(
|
||||
|
||||
@PacketId("08 36 31 04")
|
||||
@ExperimentalUnsignedTypes
|
||||
class ClientLoginResendPacket3104(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null)
|
||||
class ClientLoginResendPacket3104(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null)
|
||||
: ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv_0006_encr)
|
||||
|
||||
@PacketId("08 36 31 05")
|
||||
@ExperimentalUnsignedTypes
|
||||
class ClientLoginResendPacket3105(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray)
|
||||
: ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, null)
|
||||
|
||||
@PacketId("08 36 31 06")
|
||||
@ExperimentalUnsignedTypes
|
||||
class ClientLoginResendPacket3106(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null)
|
||||
class ClientLoginResendPacket3106(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null)
|
||||
: ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv_0006_encr)
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
open class ClientLoginResendPacket internal constructor(
|
||||
val qq: Int,
|
||||
val qq: Long,
|
||||
val password: String,
|
||||
val loginTime: Int,
|
||||
val loginIP: String,
|
||||
@ -91,7 +96,7 @@ open class ClientLoginResendPacket internal constructor(
|
||||
* @author Him188moe
|
||||
*/
|
||||
@ExperimentalUnsignedTypes
|
||||
private fun DataOutputStream.writePart1(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, tlv_0006_encr: ByteArray? = null) {
|
||||
private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, tlv_0006_encr: ByteArray? = null) {
|
||||
|
||||
//this.writeInt(System.currentTimeMillis().toInt())
|
||||
this.writeHex("01 12")//tag
|
||||
|
@ -10,7 +10,7 @@ import net.mamoe.mirai.utils.ClientLoginStatus
|
||||
@ExperimentalUnsignedTypes
|
||||
@PacketId("00 EC")
|
||||
class ClientLoginStatusPacket(
|
||||
private val qq: Int,
|
||||
private val qq: Long,
|
||||
private val sessionKey: ByteArray,
|
||||
private val loginStatus: ClientLoginStatus
|
||||
|
||||
|
@ -1,41 +0,0 @@
|
||||
package net.mamoe.mirai.network.packet.login
|
||||
|
||||
import net.mamoe.mirai.network.Protocol
|
||||
import net.mamoe.mirai.network.packet.*
|
||||
import net.mamoe.mirai.utils.ByteArrayDataOutputStream
|
||||
import net.mamoe.mirai.utils.TEACryptor
|
||||
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
@PacketId("00 BA 31 01")
|
||||
@ExperimentalUnsignedTypes
|
||||
class ClientLoginVerificationCodePacket(
|
||||
private val qq: Int,
|
||||
private val token0825: ByteArray,
|
||||
private val sequence: Int,
|
||||
private val token00BA: ByteArray
|
||||
) : ClientPacket() {
|
||||
override fun encode() {
|
||||
this.writeQQ(qq)
|
||||
this.writeHex(Protocol.fixVer)
|
||||
this.writeHex(Protocol._00BaKey)
|
||||
this.write(TEACryptor.CRYPTOR_00BAKEY.encrypt(object : ByteArrayDataOutputStream() {
|
||||
override fun toByteArray(): ByteArray {
|
||||
this.writeHex("00 02 00 00 08 04 01 E0")
|
||||
this.writeHex(Protocol._0825data2)
|
||||
this.writeHex("00 00 38")
|
||||
this.write(token0825)
|
||||
this.writeHex("01 03 00 19")
|
||||
this.writeHex(Protocol.publicKey)
|
||||
this.writeHex("13 00 05 00 00 00 00")
|
||||
this.writeVarInt(sequence.toUInt())
|
||||
this.writeHex("00 28")
|
||||
this.write(token00BA)
|
||||
this.writeHex("00 10")
|
||||
this.writeHex(Protocol._00BaFixKey)
|
||||
return super.toByteArray()
|
||||
}
|
||||
}.toByteArray()))
|
||||
}
|
||||
}
|
@ -7,19 +7,22 @@ import net.mamoe.mirai.utils.TEACryptor
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* 收到这个包意味着需要验证码登录, 并且能得到验证码图片文件的一半
|
||||
*
|
||||
* @author Him188moe
|
||||
*/
|
||||
class ServerLoginResponseVerificationCodePacket(input: DataInputStream, private val packetLength: Int) : ServerPacket(input) {
|
||||
class ServerLoginResponseVerificationCodeInitPacket(input: DataInputStream, private val packetLength: Int) : ServerPacket(input) {
|
||||
|
||||
lateinit var verifyCode: ByteArray
|
||||
lateinit var verifyCodePart1: ByteArray
|
||||
lateinit var token00BA: ByteArray
|
||||
var unknownBoolean: Boolean? = null
|
||||
//todo 也有可能这个包有问题, 也有可能 ClientVerificationCodeTransmissionRequestPacket. 检查
|
||||
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
override fun decode() {
|
||||
val verifyCodeLength = this.input.goto(78).readShort()//2bytes
|
||||
this.verifyCode = this.input.readNBytes(verifyCodeLength.toInt())
|
||||
this.verifyCodePart1 = this.input.readNBytes(verifyCodeLength.toInt())
|
||||
|
||||
this.input.skip(1)
|
||||
|
||||
@ -34,9 +37,9 @@ class ServerLoginResponseVerificationCodePacketEncrypted(input: DataInputStream)
|
||||
|
||||
}
|
||||
|
||||
fun decrypt(): ServerLoginResponseVerificationCodePacket {
|
||||
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 ServerLoginResponseVerificationCodePacket(data.dataInputStream(), data.size)
|
||||
return ServerLoginResponseVerificationCodeInitPacket(data.dataInputStream(), data.size)
|
||||
}
|
||||
}
|
@ -11,10 +11,10 @@ import java.io.DataInputStream
|
||||
@PacketId("00 CD")
|
||||
@ExperimentalUnsignedTypes
|
||||
class ClientSendFriendMessagePacket(
|
||||
val robotQQ: Int,
|
||||
val targetQQ: Int,
|
||||
val sessionKey: ByteArray,
|
||||
val message: String
|
||||
private val robotQQ: Long,
|
||||
private val targetQQ: Long,
|
||||
private val sessionKey: ByteArray,
|
||||
private val message: String
|
||||
) : ClientPacket() {
|
||||
override fun encode() {
|
||||
this.writeRandom(2)//part of packet id
|
||||
@ -52,7 +52,7 @@ class ClientSendFriendMessagePacket(
|
||||
it.writeByte(0x01)
|
||||
it.writeShort(bytes.size)
|
||||
it.write(bytes)
|
||||
}//todo check
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ import java.io.DataInputStream
|
||||
@PacketId("00 02")
|
||||
@ExperimentalUnsignedTypes
|
||||
class ClientSendGroupMessagePacket(
|
||||
private val groupId: Int,//不是 number
|
||||
private val qq: Int,
|
||||
private val groupId: Long,//不是 number
|
||||
private val qq: Long,
|
||||
private val sessionKey: ByteArray,
|
||||
private val message: String
|
||||
) : ClientPacket() {
|
||||
@ -25,7 +25,7 @@ class ClientSendGroupMessagePacket(
|
||||
this.encryptAndWrite(sessionKey) {
|
||||
val bytes = message.toByteArray()
|
||||
it.writeByte(0x2A)
|
||||
it.writeInt(groupId)
|
||||
it.writeGroup(groupId)
|
||||
it.writeShort(56 + bytes.size)
|
||||
|
||||
it.writeHex("00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00")
|
||||
|
@ -1,44 +0,0 @@
|
||||
package net.mamoe.mirai.network.packet.verification
|
||||
|
||||
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.utils.TEACryptor
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input) {
|
||||
|
||||
lateinit var verifyCode: ByteArray
|
||||
lateinit var verifyToken: ByteArray
|
||||
var unknownBoolean: Boolean? = null
|
||||
lateinit var token00BA: ByteArray
|
||||
var count: Int = 0
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
override fun decode() {
|
||||
TODO()
|
||||
val verifyCodeLength = this.input.goto(78).readShort()//2bytes
|
||||
this.verifyCode = this.input.readNBytes(verifyCodeLength.toInt())
|
||||
|
||||
this.input.skip(1)
|
||||
|
||||
this.unknownBoolean = this.input.readByte().toInt() == 1
|
||||
|
||||
//this.token00BA = this.input.goto(packetLength - 60).readNBytesAt(40)
|
||||
}
|
||||
}
|
||||
|
||||
class ServerVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) {
|
||||
override fun decode() {
|
||||
|
||||
}
|
||||
|
||||
fun decrypt(token00BA: ByteArray): ServerVerificationCodePacket {
|
||||
this.input goto 14
|
||||
val data = TEACryptor.decrypt(token00BA, this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) });
|
||||
return ServerVerificationCodePacket(data.dataInputStream())
|
||||
}
|
||||
}
|
@ -6,5 +6,5 @@ import net.mamoe.mirai.utils.config.MiraiSynchronizedLinkedListMap;
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
public class ContactList<C extends Contact> extends MiraiSynchronizedLinkedListMap<Integer, C> {
|
||||
public class ContactList<C extends Contact> extends MiraiSynchronizedLinkedListMap<Long, C> {
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ fun ByteArray.toHexString(separator: String = " "): String = this.joinToString(s
|
||||
@ExperimentalUnsignedTypes
|
||||
fun ByteArray.toUHexString(separator: String = " "): String = this.toUByteArray().toUHexString(separator)
|
||||
|
||||
fun ByteArray.__toUHexString(separator: String = " "): String = this.toUByteArray().toUHexString(separator)
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
fun ByteArray.toUHexString(): String = this.toUByteArray().toUHexString()
|
||||
|
||||
|
@ -126,10 +126,10 @@ public class MiraiConfigSection<T> extends MiraiSynchronizedLinkedListMap<String
|
||||
return result==null?defaultV:result.toString();
|
||||
}
|
||||
|
||||
public String getStringOrThrow(String key, Callable<Throwable> throwableCallable) throws Throwable {
|
||||
public String getStringOrThrow(String key, Supplier<Throwable> exceptionSupplier) throws Throwable {
|
||||
Object result = this.getOrDefault(key, null);
|
||||
if(result == null){
|
||||
throw throwableCallable.call();
|
||||
throw exceptionSupplier.get();
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
@ -3,11 +3,17 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import net.mamoe.mirai.network.Protocol;
|
||||
import net.mamoe.mirai.network.packet.ClientPacketKt;
|
||||
import net.mamoe.mirai.utils.UtilsKt;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiConsumer;
|
||||
@ -32,15 +38,24 @@ public class HexComparator {
|
||||
|
||||
private static final String BLUE = "\033[34m";
|
||||
|
||||
public static final List<HexReader> consts = new LinkedList<>(){{
|
||||
public static final List<HexReader> consts = new LinkedList<>() {{
|
||||
add(new HexReader("90 5E 39 DF 00 02 76 E4 B8 DD 00"));
|
||||
}};
|
||||
|
||||
private static class ConstMatcher {
|
||||
private static final List<Field> CONST_FIELDS = new LinkedList<>() {{
|
||||
List.of(Protocol.class).forEach(aClass -> Arrays.stream(aClass.getDeclaredFields()).peek(this::add).forEach(Field::trySetAccessible));
|
||||
List.of(TestConsts.class).forEach(aClass -> Arrays.stream(aClass.getDeclaredFields()).peek(this::add).forEach(Field::trySetAccessible));
|
||||
}};
|
||||
|
||||
@SuppressWarnings({"unused", "NonAsciiCharacters"})
|
||||
private static class TestConsts {
|
||||
private static final String 牛逼 = UtilsKt.__toUHexString("牛逼".getBytes(), " ");
|
||||
private static final String _1994701021 = ClientPacketKt.toHexString(1994701021, " ");
|
||||
private static final String _1040400290 = ClientPacketKt.toHexString(1040400290, " ");
|
||||
private static final String _580266363 = ClientPacketKt.toHexString(580266363, " ");
|
||||
}
|
||||
|
||||
private final List<Match> matches = new LinkedList<>();
|
||||
|
||||
private ConstMatcher(String hex) {
|
||||
@ -89,6 +104,23 @@ public class HexComparator {
|
||||
}
|
||||
}
|
||||
|
||||
private static void buildConstNameChain(int length, ConstMatcher constMatcher, StringBuilder constNameBuilder) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
constNameBuilder.append(" ");
|
||||
String match = constMatcher.getMatchedConstName(i / 4);
|
||||
if (match != null) {
|
||||
int appendedNameLength = match.length();
|
||||
constNameBuilder.append(match);
|
||||
while (constMatcher.getMatchedConstName(i++ / 4) != null) {
|
||||
if (appendedNameLength-- <= 0) {
|
||||
constNameBuilder.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String compare(String hex1s, String hex2s) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
@ -105,10 +137,17 @@ public class HexComparator {
|
||||
|
||||
|
||||
StringBuilder numberLine = new StringBuilder();
|
||||
StringBuilder hex1ConstName = new StringBuilder();
|
||||
StringBuilder hex1b = new StringBuilder();
|
||||
StringBuilder hex2b = new StringBuilder();
|
||||
StringBuilder hex2ConstName = new StringBuilder();
|
||||
int dif = 0;
|
||||
|
||||
int length = Math.max(hex1.length, hex2.length) * 4;
|
||||
buildConstNameChain(length, constMatcher1, hex1ConstName);
|
||||
buildConstNameChain(length, constMatcher2, hex2ConstName);
|
||||
|
||||
|
||||
for (int i = 0; i < Math.max(hex1.length, hex2.length); ++i) {
|
||||
String h1 = null;
|
||||
String h2 = null;
|
||||
@ -152,7 +191,7 @@ public class HexComparator {
|
||||
}
|
||||
}
|
||||
|
||||
numberLine.append(UNKNOWN).append(getNumber(i)).append(" ");
|
||||
numberLine.append(UNKNOWN).append(getFixedNumber(i)).append(" ");
|
||||
hex1b.append(" ").append(h1).append(" ");
|
||||
hex2b.append(" ").append(h2).append(" ");
|
||||
if (isDif) {
|
||||
@ -165,42 +204,46 @@ public class HexComparator {
|
||||
|
||||
return (builder.append(" ").append(dif).append(" 个不同").append("\n")
|
||||
.append(numberLine).append("\n")
|
||||
.append(hex1ConstName).append("\n")
|
||||
.append(hex1b).append("\n")
|
||||
.append(hex2b))
|
||||
.append(hex2b).append("\n")
|
||||
.append(hex2ConstName).append("\n")
|
||||
)
|
||||
.toString();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static void doConstReplacement(StringBuilder builder){
|
||||
private static void doConstReplacement(StringBuilder builder) {
|
||||
String mirror = builder.toString();
|
||||
HexReader hexs = new HexReader(mirror);
|
||||
for (AtomicInteger i=new AtomicInteger(0);i.get()<builder.length();i.addAndGet(1)){
|
||||
for (AtomicInteger i = new AtomicInteger(0); i.get() < builder.length(); i.addAndGet(1)) {
|
||||
hexs.setTo(i.get());
|
||||
consts.forEach(a -> {
|
||||
hexs.setTo(i.get());
|
||||
List<Integer> posToPlaceColor = new LinkedList<>();
|
||||
AtomicBoolean is = new AtomicBoolean(false);
|
||||
|
||||
a.readFully((c,d) -> {
|
||||
if(c.equals(hexs.readHex())){
|
||||
a.readFully((c, d) -> {
|
||||
if (c.equals(hexs.readHex())) {
|
||||
posToPlaceColor.add(d);
|
||||
}else{
|
||||
} else {
|
||||
is.set(false);
|
||||
}
|
||||
});
|
||||
|
||||
if(is.get()){
|
||||
if (is.get()) {
|
||||
AtomicInteger adder = new AtomicInteger();
|
||||
posToPlaceColor.forEach(e -> {
|
||||
builder.insert(e + adder.getAndAdd(BLUE.length()),BLUE);
|
||||
builder.insert(e + adder.getAndAdd(BLUE.length()), BLUE);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
private static String getNumber(int number) {
|
||||
|
||||
private static String getFixedNumber(int number) {
|
||||
if (number < 10) {
|
||||
return "00" + number;
|
||||
}
|
||||
@ -210,8 +253,31 @@ public class HexComparator {
|
||||
return String.valueOf(number);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
private static String getClipboardString() {
|
||||
Transferable trans = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
|
||||
if (trans.isDataFlavorSupported(DataFlavor.stringFlavor)) {
|
||||
try {
|
||||
return (String) trans.getTransferData(DataFlavor.stringFlavor);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
while (true) {
|
||||
System.out.println("Hex1: ");
|
||||
var hex1 = scanner.nextLine();
|
||||
System.out.println("Hex2: ");
|
||||
var hex2 = scanner.nextLine();
|
||||
System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
|
||||
System.out.println(HexComparator.compare(hex1, hex2));
|
||||
System.out.println();
|
||||
}
|
||||
/*
|
||||
System.out.println(HexComparator.compare(
|
||||
//mirai
|
||||
|
||||
@ -230,66 +296,63 @@ public class HexComparator {
|
||||
"6F 0B DF 92 00 02 76 E4 B8 DD 00 00 04 53 00 00 00 01 00 00 15 85 00 00 01 55 35 05 8E C9 BA 16 D0 01 63 5B 59 4B 59 52 31 01 B9 00 00 00 00 00 00 00 00 00 00 00 00 00 E9 E9 E9 E9 00 00 00 00 00 00 00 00 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B AA BB CC DD EE FF AA BB CC\n\n\n"
|
||||
));*/
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class HexReader{
|
||||
class HexReader {
|
||||
private String s;
|
||||
private int pos = 0;
|
||||
private int lastHaxPos = 0;
|
||||
|
||||
|
||||
public HexReader(String s){
|
||||
public HexReader(String s) {
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
public String readHex(){
|
||||
public String readHex() {
|
||||
boolean isStr = false;
|
||||
String next = "";
|
||||
for (;pos<s.length()-2;++pos){
|
||||
for (; pos < s.length() - 2; ++pos) {
|
||||
|
||||
char s1 = ' ';
|
||||
if(pos != 0){
|
||||
if (pos != 0) {
|
||||
s1 = this.s.charAt(0);
|
||||
}
|
||||
char s2 = this.s.charAt(pos+1);
|
||||
char s3 = this.s.charAt(pos+2);
|
||||
char s2 = this.s.charAt(pos + 1);
|
||||
char s3 = this.s.charAt(pos + 2);
|
||||
char s4 = ' ';
|
||||
if(this.s.length() != (this.pos+3)){
|
||||
s4 = this.s.charAt(pos+3);
|
||||
if (this.s.length() != (this.pos + 3)) {
|
||||
s4 = this.s.charAt(pos + 3);
|
||||
}
|
||||
if(
|
||||
if (
|
||||
Character.isSpaceChar(s1) && Character.isSpaceChar(s4)
|
||||
&&
|
||||
&&
|
||||
(Character.isDigit(s2) || Character.isAlphabetic(s2))
|
||||
&&
|
||||
(Character.isDigit(s3) || Character.isAlphabetic(s3))
|
||||
){
|
||||
this.pos+=2;
|
||||
this.lastHaxPos = this.pos+1;
|
||||
return String.valueOf(s2) + String.valueOf(s3);
|
||||
) {
|
||||
this.pos += 2;
|
||||
this.lastHaxPos = this.pos + 1;
|
||||
return String.valueOf(s2) + s3;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public void readFully(BiConsumer<String, Integer> processor){
|
||||
public void readFully(BiConsumer<String, Integer> processor) {
|
||||
this.reset();
|
||||
String nextHax = this.readHex();
|
||||
while (!nextHax.equals(" ")){
|
||||
processor.accept(nextHax,this.lastHaxPos);
|
||||
while (!nextHax.equals(" ")) {
|
||||
processor.accept(nextHax, this.lastHaxPos);
|
||||
nextHax = this.readHex();
|
||||
}
|
||||
}
|
||||
|
||||
public void setTo(int pos){
|
||||
public void setTo(int pos) {
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
public void reset(){
|
||||
public void reset() {
|
||||
this.pos = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
8
mirai-core/src/test/java/TestKt.kt
Normal file
8
mirai-core/src/test/java/TestKt.kt
Normal file
@ -0,0 +1,8 @@
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
|
||||
/**
|
||||
* @author Him188moe
|
||||
*/
|
||||
fun main() {
|
||||
println("牛逼".toByteArray().toUHexString())
|
||||
}
|
Loading…
Reference in New Issue
Block a user