Image uploading

This commit is contained in:
Him188 2019-10-20 20:27:35 +08:00
parent d06197d346
commit 14722eb838
12 changed files with 107 additions and 67 deletions

View File

@ -30,7 +30,7 @@ abstract class ClientPacket : Packet(), Closeable {
/**
* 务必 [ByteReadPacket.close] [close] 或使用 [Closeable.use]
*/
internal var packet: ByteReadPacket = UninitializedByteReadPacket
var packet: ByteReadPacket = UninitializedByteReadPacket
get() {
if (field === UninitializedByteReadPacket) build()
return field

View File

@ -4,11 +4,11 @@ package net.mamoe.mirai.network.protocol.tim.packet
import kotlinx.io.core.*
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.session
import net.mamoe.mirai.qqAccount
import net.mamoe.mirai.utils.*
suspend fun Group.uploadImage(
image: PlatformImage
) = with(bot.network.session) {
@ -110,54 +110,79 @@ class GroupImageIdRequestPacket(
// 78 03
// 80 01 00
/*
writeQQ(bot)
writeHex(TIMProtocol.version0x04)
encryptAndWrite(sessionKey) {
writeHex("00 00 00 07 00 00 00")
writeUVarintLVPacket(lengthOffset = { it - 6 }) {
writeUVarintLVPacket {
writeByte(0x08)
writeHex("01 12 03 98 01 01 10 01 1A")
writeUVarintLVPacket(lengthOffset = { it + 1 }) {
writeUVarInt(groupId)
writeUVarInt(bot)
writeUVarintLVPacket(lengthOffset = { it + 7 }) {
writeTUVarint(0x08u, groupId)
writeTUVarint(0x10u, bot)
writeTV(0x1800u)
writeTLV(0x22u, image.md5)
writeTUVarint(0x28u, image.fileSize.toUInt())
writeUVarintLVPacket(tag = 0x32u) {
writeTV(0x31_00u)
writeTV(0x35_00u)
writeTV(0x4C_00u)
writeTV(0x5B_00u)
writeTV(0x40_00u)
writeTV(0x33_00u)
writeTV(0x48_00u)
writeTV(0x5F_00u)
writeTV(0x58_00u)
writeTV(0x46_00u)
writeTV(0x51_00u)
writeTV(0x45_00u)
writeTV(0x51_00u)
writeTV(0x40_00u)
writeTV(0x24_00u)
writeTV(0x40_00u)
writeTV(0x5B_00u)
writeTV(0x4D_00u)
writeTV(0x5B_00u)
writeTV(0x39_00u)
writeTV(0x39_00u)
writeTV(0x40_00u)
writeTV(0x57_00u)
writeTV(0x5D_00u)
writeTV(0x4F_00u)
}
writeTV(0x38_01u)
writeTV(0x48_01u)
writeTUVarint(0x50u, image.imageWidth.toUInt())
writeTUVarint(0x58u, image.imageHeight.toUInt())
writeTV(0x60_02u)
writeTLV(0x6Au, value0x6A)
writeTV(0x70_00u)
writeTV(0x78_03u)
writeTV(0x80_01u)
writeUByte(0u)
writeTByteArray(0x6Au, value0x6A)
}
}
writeTV(0x70_00u)
writeTV(0x78_03u)
writeTV(0x80_01u)
writeUByte(0u)
// this.debugColorizedPrintThis(compareTo = "00 00 00 07 00 00 00 5D 08 01 12 03 98 01 01 10 01 1A 59 08 FB D2 D8 94 02 10 A2 FF 8C F0 03 18 00 22 10 1D D2 2B 9B BC F2 10 83 DC 99 D2 2E 20 39 CC 0E 28 8A 03 32 1A 5B 00 40 00 33 00 48 00 5F 00 58 00 46 00 51 00 45 00 51 00 40 00 24 00 4F 00 38 01 48 01 50 EF 01 58 C2 01 60 02 6A 05 32 36 39 33 33 70 00 78 03 80 01 00")
}*/
writeQQ(bot)
writeHex("04 00 00 00 01 01 01 00 00 68 20 00 00 00 00 00 00 00 00")
encryptAndWrite(sessionKey) {
writeHex("00 00 00 07 00 00 00 5E 08 01 12 03 98 01 01 10 01 1A")
writeHex("5A 08")
writeUVarInt(groupId)
writeUByte(0x10u)
writeUVarInt(bot)
writeHex("18 00 22 10")
writeFully(image.md5)
writeUByte(0x28u)
writeUVarInt(image.fileSize.toUInt())
writeHex("32 1A 37 00 4D 00 32 00 25 00 4C 00 31 00 56 00 32 00 7B 00 39 00 30 00 29 00 52 00")
writeHex("38 01 48 01 50")
writeUVarInt(image.width.toUInt())
writeUByte(0x58u)
writeUVarInt(image.height.toUInt())
writeHex("60 04 6A 05 32 36 36 35 36 70 00 78 03 80 01 00")
}
}
companion object {
private val value0x6A: UByteArray = ubyteArrayOf(32u, 36u, 39u, 33u, 33u)
private val value0x6A: UByteArray = ubyteArrayOf(0x05u, 0x32u, 0x36u, 0x39u, 0x33u, 0x33u)
}
@PacketId(0x0388u)
@ -189,7 +214,7 @@ class GroupImageIdRequestPacket(
}
fun main() {
("12 03 98 01 01").hexToBytes().read {
("8E 4B").hexToBytes().read {
println(readUnsignedVarInt())
}

View File

@ -119,8 +119,7 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
}
/**
* 忽略的事件.
* 00 79: 总是与 01 12 一起发生, 00 79 却没多大意义
* 忽略的事件
*/
@Suppress("unused")
class IgnoredServerEventPacket(val eventId: ByteArray, private val showData: Boolean = false, input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {

View File

@ -3,7 +3,7 @@ package net.mamoe.mirai.utils
import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.message.ImageId
data class PlatformImage(
class PlatformImage(
val width: Int,
val height: Int,
val md5: ByteArray,
@ -14,30 +14,7 @@ data class PlatformImage(
val id: ImageId by lazy { ImageId("{${md5[0..4]}-${md5[0..2]}-${md5[0..2]}-${md5[0..2]}-${md5[0..6]}}.$format") }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is PlatformImage) return false
if (width != other.width) return false
if (height != other.height) return false
if (!md5.contentEquals(other.md5)) return false
if (format != other.format) return false
if (fileData != other.fileData) return false
if (fileSize != other.fileSize) return false
return true
}
override fun hashCode(): Int {
var result = width
result = 31 * result + height
result = 31 * result + md5.contentHashCode()
result = 31 * result + format.hashCode()
result = 31 * result + fileData.hashCode()
result = 31 * result + fileSize.hashCode()
return result
}
override fun toString(): String = "[PlatformImage(${width}x${height} $format)]"
}
private operator fun ByteArray.get(range: IntRange): String = buildString {

View File

@ -45,6 +45,13 @@ internal fun BytePacketBuilder.debugColorizedPrintThis(name: String = "") {
this.writeFully(data)
}
@Deprecated("Low efficiency, only for debug purpose", ReplaceWith(" "))
internal fun BytePacketBuilder.debugColorizedPrintThis(name: String = "", compareTo: String? = null) {
val data = this.build().readBytes()
data.printColorizedHex(name, compareTo = compareTo)
this.writeFully(data)
}
@Deprecated("Low efficiency, only for debug purpose", ReplaceWith(" "))
internal fun BytePacketBuilder.debugPrintThis(name: String = "") {
val data = this.build().readBytes()
@ -57,14 +64,18 @@ internal fun String.printStringFromHex() {
}
internal fun ByteArray.printColorizedHex(name: String = "", ignoreUntilFirstConst: Boolean = false) {
internal fun ByteArray.printColorizedHex(name: String = "", ignoreUntilFirstConst: Boolean = false, compareTo: String? = null) {
println("Hex比较 `$name`")
println(toUHexString().colorize(ignoreUntilFirstConst))
if (compareTo != null) {
println(printCompareHex(toUHexString(), compareTo))
} else {
println(toUHexString().printColorize(ignoreUntilFirstConst))
}
println()
}
expect fun compareHex(hex1s: String, hex2s: String): String
expect fun String.colorize(ignoreUntilFirstConst: Boolean = false): String
expect fun printCompareHex(hex1s: String, hex2s: String): String
expect fun String.printColorize(ignoreUntilFirstConst: Boolean = false): String
fun main() {

View File

@ -92,6 +92,11 @@ fun BytePacketBuilder.writeTByteArray(tag: UByte, value: ByteArray) {
this.writeFully(value)
}
fun BytePacketBuilder.writeTByteArray(tag: UByte, value: UByteArray) {
this.writeUByte(tag)
this.writeFully(value)
}
fun BytePacketBuilder.encryptAndWrite(key: IoBuffer, encoder: BytePacketBuilder.() -> Unit) = encryptAndWrite(key.readBytes(), encoder)
fun BytePacketBuilder.encryptAndWrite(key: ByteArray, encoder: BytePacketBuilder.() -> Unit) = writeFully(TEA.encrypt(BytePacketBuilder().apply(encoder).use { it.build().readBytes() }, key))
fun BytePacketBuilder.encryptAndWrite(keyHex: String, encoder: BytePacketBuilder.() -> Unit) = encryptAndWrite(keyHex.hexToBytes(), encoder)

View File

@ -74,8 +74,8 @@ internal object HexCache {
}
internal fun hexToUBytes(hex: String): UByteArray =
hex.split(" ").dropLastWhile { it.isEmpty() }.toTypedArray()
.map { value -> value.trim { it <= ' ' } }
hex.split(" ")
.filterNot { it.isEmpty() }
.map { s -> s.toUByte(16) }
.toUByteArray()
}

View File

@ -286,5 +286,5 @@ internal object HexComparator {
}
actual fun String.colorize(ignoreUntilFirstConst: Boolean): String = with(HexComparator) { colorize(ignoreUntilFirstConst) }
actual fun compareHex(hex1s: String, hex2s: String): String = with(HexComparator) { compare(hex1s, hex2s) }
actual fun String.printColorize(ignoreUntilFirstConst: Boolean): String = with(HexComparator) { colorize(ignoreUntilFirstConst) }
actual fun printCompareHex(hex1s: String, hex2s: String): String = with(HexComparator) { compare(hex1s, hex2s) }

View File

@ -8,7 +8,7 @@ import java.io.OutputStream
import java.security.MessageDigest
import javax.imageio.ImageIO
fun BufferedImage.toPlatformImage(formatName: String = "PNG"): PlatformImage {
fun BufferedImage.toPlatformImage(formatName: String = "png"): PlatformImage {
val digest = MessageDigest.getInstance("md5")
digest.reset()

View File

@ -0,0 +1,23 @@
@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS")
import net.mamoe.mirai.network.protocol.tim.packet.GroupImageIdRequestPacket
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.readRemainingBytes
import net.mamoe.mirai.utils.toPlatformImage
import net.mamoe.mirai.utils.toUHexString
import java.io.File
import javax.imageio.ImageIO
val sessionKey: ByteArray = "F1 ED F2 BC 55 17 7B FE CC CC F3 08 D1 8D A7 0E".hexToBytes()
fun main() = println({
val image = ImageIO.read(File("C:\\Users\\Him18\\Desktop\\test2.png").readBytes().inputStream()).toPlatformImage("png")
// File("C:\\Users\\Him18\\Desktop\\test2.jpg").writeBytes(image.fileData.readBytes())
GroupImageIdRequestPacket(
1994701021u,
580266363u,
image,
sessionKey
).packet.readRemainingBytes().toUHexString()
}())

View File

@ -1,11 +1,11 @@
@file:Suppress("ObjectPropertyName", "unused", "NonAsciiCharacters", "MayBeConstant")
import net.mamoe.mirai.utils.compareHex
import net.mamoe.mirai.utils.printCompareHex
import java.util.*
fun main() {
// println(HexComparator.colorize("00 00 00 25 00 08 00 02 00 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD E7 86 74 F2 64 55 AD 9A EB 2F B9 DF F1 7F 8C 28 00 0B 78 14 5D A2 F5 CB 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A2 F5 CA 9D 26 CB 5E 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E4 BD A0 E5 A5 BD 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00"))
// println(HexComparator.printColorize("00 00 00 25 00 08 00 02 00 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD E7 86 74 F2 64 55 AD 9A EB 2F B9 DF F1 7F 8C 28 00 0B 78 14 5D A2 F5 CB 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A2 F5 CA 9D 26 CB 5E 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E4 BD A0 E5 A5 BD 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00"))
val scanner = Scanner(System.`in`)
while (true) {
println("Hex1: ")
@ -13,7 +13,7 @@ fun main() {
println("Hex2: ")
val hex2 = scanner.nextLine()
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")
println(compareHex(hex1, hex2))
println(printCompareHex(hex1, hex2))
println()
}
/*

View File

@ -81,14 +81,14 @@ suspend fun main() {
"上传好友图片" in it.message -> withTimeoutOrNull(3000) {
val id = QQ(bot, 1040400290u)
.uploadImage(withContext(Dispatchers.IO) { ImageIO.read(File("C:\\Users\\Him18\\Desktop\\lemon.png").readBytes().inputStream()) }.toPlatformImage("PNG"))
.uploadImage(withContext(Dispatchers.IO) { ImageIO.read(File("C:\\Users\\Him18\\Desktop\\lemon.png").readBytes().inputStream()) }.toPlatformImage("png"))
it.reply(id.value)
delay(1000)
it.reply(Image(id))
}
"上传群图片" in it.message -> withTimeoutOrNull(3000) {
val image = withContext(Dispatchers.IO) { ImageIO.read(File("C:\\Users\\Him18\\Desktop\\lemon.png").readBytes().inputStream()) }.toPlatformImage("PNG")
val image = withContext(Dispatchers.IO) { ImageIO.read(File("C:\\Users\\Him18\\Desktop\\lemon.png").readBytes().inputStream()) }.toPlatformImage("png")
Group(bot, 580266363u).uploadImage(image)
it.reply(image.id.value)
delay(1000)