This commit is contained in:
Him188moe 2019-08-16 00:04:39 +08:00
parent 6673bada67
commit 97b90b08c8
10 changed files with 184 additions and 35 deletions

View File

@ -5,7 +5,7 @@ package net.mamoe.mirai.contact
* *
* @author Him188moe @ Mirai Project * @author Him188moe @ Mirai Project
*/ */
abstract class Contact(number: Long) { abstract class Contact(val number: Long) {
/** /**
* Async * Async

View File

@ -19,7 +19,7 @@ class QQ(number: Long) : Contact(number) {
/** /**
* At(@) this account. * At(@) this account.
*/ */
open fun at(): String { fun at(): String {
return "[@" + this.number + "]" return "[@$number]"
} }
} }

View File

@ -1,8 +0,0 @@
package net.mamoe.mirai.network;
/**
* @author Him188moe @ Mirai Project
*/
public class BinaryStream {
}

View File

@ -11,8 +11,46 @@ import net.mamoe.mirai.network.packet.server.ServerPacket
*/ */
@Log4j2 @Log4j2
class ClientHandler(val robot: Robot) : SimpleChannelInboundHandler<ByteArray>() { class ClientHandler(val robot: Robot) : SimpleChannelInboundHandler<ByteArray>() {
override fun channelRead0(ctx: ChannelHandlerContext?, bytes: ByteArray?) { private object Reader {
private var length: Int? = null
private lateinit var bytes: ByteArray
fun init(bytes: ByteArray) {
this.length = length
this.bytes = bytes
}
/**
* Reads bytes, combining them to create a packet, returning remaining bytes.
*/
fun read(bytes: ByteArray): ByteArray? {
checkNotNull(this.length)
val needSize = length!! - this.bytes.size;//How many bytes we need
if (needSize == bytes.size || needSize > bytes.size) {
this.bytes += bytes
return null;
}
//We got more than we need
this.bytes += bytes.copyOfRange(0, needSize)
return bytes.copyOfRange(needSize, bytes.size - needSize)//We got remaining bytes, that is of another packet
}
fun isPacketAvailable() = this.length == this.bytes.size
fun toServerPacket(): ServerPacket {
return ServerPacket.ofByteArray(this.bytes)
}
}
override fun channelRead0(ctx: ChannelHandlerContext?, bytes: ByteArray) {
try { try {
/*val remaining = Reader.read(bytes);
if (Reader.isPacketAvailable()) {
robot.onPacketReceived(Reader.toServerPacket())
Reader.init()
remaining
}*/
robot.onPacketReceived(ServerPacket.ofByteArray(bytes)) robot.onPacketReceived(ServerPacket.ofByteArray(bytes))
} catch (e: Exception) { } catch (e: Exception) {
MiraiServer.getLogger().catching(e) MiraiServer.getLogger().catching(e)

View File

@ -1,12 +1,16 @@
package net.mamoe.mirai.network package net.mamoe.mirai.network
import net.mamoe.mirai.network.packet.Packet import net.mamoe.mirai.network.packet.Packet
import net.mamoe.mirai.network.packet.client.Client0825ResponsePacket
import net.mamoe.mirai.network.packet.server.Server0825Packet
import net.mamoe.mirai.network.packet.server.ServerPacket import net.mamoe.mirai.network.packet.server.ServerPacket
/** /**
* [number] is a QQ number.
*
* @author Him188moe @ Mirai Project * @author Him188moe @ Mirai Project
*/ */
open class Robot() { class Robot(val number: Long) {
internal fun onPacketReceived(packet: Packet) { internal fun onPacketReceived(packet: Packet) {
if (packet !is ServerPacket) { if (packet !is ServerPacket) {
@ -14,5 +18,12 @@ open class Robot() {
} }
packet.decode() packet.decode()
if (packet is Server0825Packet) {//todo 检查是否需要修改 UDP 连接???
sendPacket(Client0825ResponsePacket(packet.serverIP, number));
}
}
internal fun sendPacket(packet: Packet) {
TODO()
} }
} }

View File

@ -0,0 +1,32 @@
package net.mamoe.mirai.network.packet.client
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.network.packet.PacketId
import net.mamoe.mirai.util.TEAEncryption
import java.io.IOException
/**
* @author Him188moe @ Mirai Project
*/
@PacketId(0x08_25_31_02)
class Client0825ResponsePacket(private val serverIP: String, private val qq: Long) : ClientPacket() {
override fun encode() {
this.writeQQ(qq)
this.writeHex(Protocol.fixVer)
this.writeHex(Protocol.redirectionKey)
//TEA 加密
this.write(TEAEncryption.encrypt(object : ClientPacket() {
@Throws(IOException::class)
override fun encode() {
this.writeHex(Protocol._0825data0)
this.writeHex(Protocol._0825data2)
this.writeQQ(qq)
this.writeHex("00 01 00 00 03 09 00 0C 00 01")
this.writeIp(serverIP)
this.writeHex("01 6F A1 58 22 01 00 36 00 12 00 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 14 00 1D 01 03 00 19")
this.writeHex(Protocol.publicKey)
}
}.encodeToByteArray(), Protocol.hexToBytes(Protocol.redirectionKey)))
}
}

View File

@ -0,0 +1,38 @@
package net.mamoe.mirai.network.packet.server
import net.mamoe.mirai.network.Protocol
import net.mamoe.mirai.util.TEAEncryption
import java.io.DataInputStream
/**
* A packet received when logging in, used to redirect server address
*
* @author Him188moe @ Mirai Project
*/
class Server0825Packet(private val type: Type, inputStream: DataInputStream) : ServerPacket(inputStream) {
lateinit var serverIP: String;
enum class Type {
TYPE_08_25_31_01,
TYPE_08_25_31_02,
}
override fun decode() {
input.skip(43 - 11)//todo: check
val data = DataInputStream(TEAEncryption.decrypt(input.readAllBytes().let { it.copyOfRange(0, it.size - 45) }, when (type) {
Type.TYPE_08_25_31_01 -> Protocol.redirectionKey.toByteArray()
Type.TYPE_08_25_31_02 -> Protocol._0825key.toByteArray()
}).inputStream());
when (data.readByte().toInt()) {
0xFE -> {
serverIP = data.readIP()
}
0X00 -> {
}
else -> {
}
}
}
}

View File

@ -0,0 +1,11 @@
package net.mamoe.mirai.network.packet.server
import java.io.DataInputStream
/**
* @author Him188moe @ Mirai Project
*/
class ServerLoginSucceedPacket(inputStream: DataInputStream) : ServerPacket(inputStream) {
override fun decode() {
}
}

View File

@ -1,28 +1,55 @@
package net.mamoe.mirai.network.packet.server; package net.mamoe.mirai.network.packet.server
import net.mamoe.mirai.network.packet.Packet; import net.mamoe.mirai.network.packet.Packet
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayInputStream; import java.io.DataInputStream
import java.io.DataInputStream;
import java.io.InputStream;
/** /**
* @author Him188moe @ Mirai Project * @author Him188moe @ Mirai Project
*/ */
public abstract class ServerPacket extends DataInputStream implements Packet { abstract class ServerPacket(val input: DataInputStream) : Packet {
public static ServerPacket ofByteArray(byte[] bytes) {
// TODO: 2019/8/15 process bytes abstract fun decode()
companion object {
fun ofByteArray(bytes: ByteArray): ServerPacket {
val stream = DataInputStream(bytes.inputStream())
stream.skipUntil(10)
val idBytes = stream.readUntil(11)
val id = idBytes.map { it.toString(16) }.joinToString("")
return when (id) {
"08 25 31 01" -> Server0825Packet(Server0825Packet.Type.TYPE_08_25_31_01, stream);
"08 25 31 02" -> Server0825Packet(Server0825Packet.Type.TYPE_08_25_31_02, stream);
else -> throw UnsupportedOperationException();
}
}
}
} }
fun DataInputStream.skipUntil(byte: Byte) {
public ServerPacket(@NotNull InputStream in) { while (readByte() != byte);
super(in);
} }
public ServerPacket(@NotNull byte[] in) { fun DataInputStream.readUntil(byte: Byte): ByteArray {
this(new ByteArrayInputStream(in)); var buff = byteArrayOf()
var b: Byte
b = readByte()
while (b != byte) {
buff += b
b = readByte()
}
return buff
} }
public abstract void decode(); fun DataInputStream.readIP(): String {
var buff = "";
for (i in 0..12) {//todo: check that
buff += readByte().toInt();
}
return buff;
} }

View File

@ -8,11 +8,11 @@ public final class TEAEncryption {
return new _TEAEncryption().encrypt(source, key); return new _TEAEncryption().encrypt(source, key);
} }
public byte[] decrypt(byte[] source, byte[] key) { public static byte[] decrypt(byte[] source, byte[] key) {
return new _TEAEncryption().decrypt(source, key); return new _TEAEncryption().decrypt(source, key);
} }
public byte[] decrypt(byte[] source, int offset, int length, byte[] key) { public static byte[] decrypt(byte[] source, int offset, int length, byte[] key) {
return new _TEAEncryption().decrypt(source, offset, length, key); return new _TEAEncryption().decrypt(source, offset, length, key);
} }