Gather all platform-specified utilities into a MiraiPlatformUtils

This commit is contained in:
Him188 2020-03-08 21:14:41 +08:00
parent 9f988e7d04
commit 243b2ea731
20 changed files with 271 additions and 187 deletions

View File

@ -78,6 +78,7 @@ internal class QQImpl(
return MessageReceipt(source, this, null)
}
@OptIn(MiraiInternalAPI::class)
override suspend fun uploadImage(image: ExternalImage): OfflineFriendImage = try {
if (BeforeImageUploadEvent(this, image).broadcast().isCancelled) {
throw EventCancelledException("cancelled by BeforeImageUploadEvent.ToGroup")
@ -111,7 +112,7 @@ internal class QQImpl(
ImageUploadEvent.Succeed(this@QQImpl, image, it).broadcast()
}
is LongConn.OffPicUp.Response.RequireUpload -> {
Http.postImage(
MiraiPlatformUtils.Http.postImage(
"0x6ff0070",
bot.uin,
null,

View File

@ -222,7 +222,7 @@ internal abstract class QQAndroidBotBase constructor(
}
override suspend fun openChannel(image: Image): ByteReadChannel {
return Http.get<HttpResponse>(queryImageUrl(image)).content.toKotlinByteReadChannel()
return MiraiPlatformUtils.Http.get<HttpResponse>(queryImageUrl(image)).content.toKotlinByteReadChannel()
}
}

View File

@ -9,18 +9,14 @@
package net.mamoe.mirai.qqandroid.message
import kotlinx.io.core.buildPacket
import kotlinx.io.core.discardExact
import kotlinx.io.core.readBytes
import kotlinx.io.core.readUInt
import kotlinx.io.core.*
import net.mamoe.mirai.LowLevelAPI
import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgComm
import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.MiraiDebugAPI
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.io.encodeToString
import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.read
import net.mamoe.mirai.utils.io.toByteArray
@ -222,7 +218,7 @@ private val atAllData = ImMsgBody.Elem(
)
)
@OptIn(MiraiInternalAPI::class)
@OptIn(MiraiInternalAPI::class, MiraiExperimentalAPI::class)
internal fun MessageChain.toRichTextElems(forGroup: Boolean): MutableList<ImMsgBody.Elem> {
val elements = mutableListOf<ImMsgBody.Elem>()
@ -243,6 +239,14 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean): MutableList<ImMsgB
elements.add(ImMsgBody.Elem(text = it.toJceData()))
elements.add(ImMsgBody.Elem(text = ImMsgBody.Text(str = " ")))
}
is RichMessage -> elements.add(
ImMsgBody.Elem(
richMsg = ImMsgBody.RichMsg(
serviceId = it.serviceId,
template1 = byteArrayOf(1) + MiraiPlatformUtils.zip(it.content.toByteArray())
)
)
)
is OfflineGroupImage -> elements.add(ImMsgBody.Elem(customFace = it.toJceData()))
is OnlineGroupImageImpl -> elements.add(ImMsgBody.Elem(customFace = it.delegate))
is OnlineFriendImageImpl -> elements.add(ImMsgBody.Elem(notOnlineImage = it.delegate))
@ -400,6 +404,28 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChainBuilde
}
}
}
it.richMsg != null -> {
when (it.richMsg.serviceId) {
60 -> message.add(
XMLMessage(
content = MiraiPlatformUtils.unzip(it.richMsg.template1, 1).encodeToString()
)
)
else -> {
@Suppress("DEPRECATION")
MiraiLogger.debug {
"unknown richMsg.serviceId: ${it.richMsg.serviceId}, content=${it.richMsg.template1.contentToString()}, \ntryUnzip=${
kotlin.runCatching {
MiraiPlatformUtils.unzip(it.richMsg.template1, 1).encodeToString()
}.getOrElse { "<failed>" }
}"
}
}
}
}
else -> {
println(it._miraiContentToString())
}
}
}

View File

@ -191,8 +191,9 @@ internal open class QQAndroidClient(
lateinit var t104: ByteArray
}
@OptIn(MiraiInternalAPI::class)
internal fun generateTgtgtKey(guid: ByteArray): ByteArray =
md5(getRandomByteArray(16) + guid)
MiraiPlatformUtils.md5(getRandomByteArray(16) + guid)
internal class ReserveUinInfo(

View File

@ -26,6 +26,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.io.*
import kotlinx.serialization.InternalSerializationApi
import net.mamoe.mirai.utils.MiraiPlatformUtils
@OptIn(MiraiInternalAPI::class, InternalSerializationApi::class)
internal fun createImageDataPacketSequence( // RequestDataTrans
@ -77,7 +78,7 @@ internal fun createImageDataPacketSequence( // RequestDataTrans
dataoffset = offset,
filesize = dataSize.toLong(),
serviceticket = uKey,
md5 = net.mamoe.mirai.utils.md5(chunkedInput.buffer, 0, chunkedInput.bufferSize),
md5 = MiraiPlatformUtils.md5(chunkedInput.buffer, 0, chunkedInput.bufferSize),
fileMd5 = fileMd5,
flag = 0,
rtcode = 0

View File

@ -342,7 +342,7 @@ internal object KnownPacketFactories {
1 -> {
input.discardExact(4)
input.useBytes { data, length ->
data.unzip(length = length).let {
MiraiPlatformUtils.unzip(data, 0, length).let {
val size = it.toInt()
if (size == it.size || size == it.size + 4) {
it.toReadPacket(offset = 4)

View File

@ -15,9 +15,10 @@ import kotlinx.io.core.toByteArray
import kotlinx.io.core.writeFully
import net.mamoe.mirai.qqandroid.network.protocol.LoginType
import net.mamoe.mirai.qqandroid.utils.NetworkType
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.MiraiPlatformUtils
import net.mamoe.mirai.utils.currentTimeMillis
import net.mamoe.mirai.utils.io.*
import net.mamoe.mirai.utils.md5
import kotlin.random.Random
/**
@ -76,6 +77,7 @@ fun BytePacketBuilder.t18(
} shouldEqualsTo 22
}
@OptIn(MiraiInternalAPI::class)
fun BytePacketBuilder.t106(
appId: Long = 16L,
subAppId: Long = 537062845L,
@ -96,7 +98,7 @@ fun BytePacketBuilder.t106(
guid?.requireSize(16)
writeShortLVPacket {
encryptAndWrite(md5(passwordMd5 + ByteArray(4) + (salt.takeIf { it != 0L } ?: uin).toInt().toByteArray())) {
encryptAndWrite(MiraiPlatformUtils.md5(passwordMd5 + ByteArray(4) + (salt.takeIf { it != 0L } ?: uin).toInt().toByteArray())) {
writeShort(4)//TGTGTVer
writeInt(Random.nextInt())
writeInt(5)//ssoVer
@ -321,12 +323,13 @@ fun BytePacketBuilder.t144(
}
}
@OptIn(MiraiInternalAPI::class)
fun BytePacketBuilder.t109(
androidId: ByteArray
) {
writeShort(0x109)
writeShortLVPacket {
writeFully(md5(androidId))
writeFully(MiraiPlatformUtils.md5(androidId))
} shouldEqualsTo 16
}
@ -556,21 +559,23 @@ fun BytePacketBuilder.t400(
}
}
@OptIn(MiraiInternalAPI::class)
fun BytePacketBuilder.t187(
macAddress: ByteArray
) {
writeShort(0x187)
writeShortLVPacket {
writeFully(md5(macAddress)) // may be md5
writeFully(MiraiPlatformUtils.md5(macAddress)) // may be md5
}
}
@OptIn(MiraiInternalAPI::class)
fun BytePacketBuilder.t188(
androidId: ByteArray
) {
writeShort(0x188)
writeShortLVPacket {
writeFully(md5(androidId))
writeFully(MiraiPlatformUtils.md5(androidId))
} shouldEqualsTo 16
}

View File

@ -23,9 +23,10 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket
import net.mamoe.mirai.qqandroid.utils.NetworkType
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.MiraiPlatformUtils
import net.mamoe.mirai.utils.io.encodeToString
import net.mamoe.mirai.utils.io.toReadPacket
import net.mamoe.mirai.utils.localIpAddress
@Suppress("EnumEntryName")
internal enum class RegPushReason {
@ -89,6 +90,7 @@ internal class StatSvc {
private const val subAppId = 537062845L
@OptIn(MiraiInternalAPI::class)
operator fun invoke(
client: QQAndroidClient,
regPushReason: RegPushReason = RegPushReason.appRegister
@ -138,7 +140,7 @@ internal class StatSvc {
strOSVer = client.device.version.release.encodeToString(),
uOldSSOIp = 0,
uNewSSOIp = localIpAddress().split(".").foldIndexed(0L) { index: Int, acc: Long, s: String ->
uNewSSOIp = MiraiPlatformUtils.localIpAddress().split(".").foldIndexed(0L) { index: Int, acc: Long, s: String ->
acc or ((s.toLong() shl (index * 16)))
},
strVendorName = "MIUI",

View File

@ -84,7 +84,7 @@ internal class WtLogin {
t8(2052)
t104(client.t104)
t116(150470524, 66560)
t401(md5(client.device.guid + "stMNokHgxZUGhsYp".toByteArray() + t402))
t401(MiraiPlatformUtils.md5(client.device.guid + "stMNokHgxZUGhsYp".toByteArray() + t402))
}
}
}

View File

@ -44,6 +44,7 @@ fun Bitmap.toExternalImage(formatName: String = "gif"): ExternalImage {
/**
* 读取文件头识别图片属性, 然后构造 [ExternalImage]
*/
@OptIn(MiraiInternalAPI::class)
@Throws(IOException::class)
fun File.toExternalImage(): ExternalImage {
val input = BitmapFactory.decodeFile(this.absolutePath)
@ -52,7 +53,7 @@ fun File.toExternalImage(): ExternalImage {
return ExternalImage(
width = input.width,
height = input.height,
md5 = this.inputStream().use { it.md5() },
md5 = this.inputStream().use { MiraiPlatformUtils.md5(it) },
imageFormat = this.nameWithoutExtension,
input = this.inputStream().asInput(IoBuffer.Pool),
inputSize = this.length(),

View File

@ -21,6 +21,8 @@ import kotlinx.serialization.Transient
import kotlinx.serialization.UnstableDefault
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import net.mamoe.mirai.utils.MiraiPlatformUtils.localIpAddress
import net.mamoe.mirai.utils.MiraiPlatformUtils.md5
import java.io.File
/**
@ -102,6 +104,7 @@ actual open class SystemDeviceInfo actual constructor() : DeviceInfo() {
(context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager).connectionInfo.ssid.toByteArray()
}.getOrElse { byteArrayOf() }
@OptIn(MiraiInternalAPI::class)
override val imsiMd5: ByteArray
@SuppressLint("HardwareIds")
get() = md5(kotlin.runCatching {
@ -117,6 +120,8 @@ actual open class SystemDeviceInfo actual constructor() : DeviceInfo() {
(context.applicationContext.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager).deviceId
}
}.getOrElse { "" }
@OptIn(MiraiInternalAPI::class)
override val ipAddress: ByteArray get() = localIpAddress().split(".").map { it.toByte() }.takeIf { it.size == 4 }?.toByteArray() ?: byteArrayOf()
override val androidId: ByteArray get() = Build.ID.toByteArray()
override val apn: ByteArray get() = "wifi".toByteArray()

View File

@ -10,7 +10,8 @@
package net.mamoe.mirai.utils.cryptor
import android.annotation.SuppressLint
import net.mamoe.mirai.utils.md5
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.MiraiPlatformUtils.md5
import java.security.*
import java.security.spec.ECGenParameterSpec
import java.security.spec.X509EncodedKeySpec
@ -71,6 +72,7 @@ actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) {
.genKeyPair())
}
@OptIn(MiraiInternalAPI::class)
actual fun calculateShareKey(
privateKey: ECDHPrivateKey,
publicKey: ECDHPublicKey

View File

@ -7,6 +7,8 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("NOTHING_TO_INLINE")
package net.mamoe.mirai.utils
import io.ktor.client.HttpClient
@ -15,88 +17,93 @@ import io.ktor.util.KtorExperimentalAPI
import kotlinx.io.pool.useInstance
import net.mamoe.mirai.utils.io.ByteArrayPool
import java.io.ByteArrayOutputStream
import java.io.DataInput
import java.io.EOFException
import java.io.InputStream
import java.net.InetAddress
import java.security.MessageDigest
import java.util.zip.Deflater
import java.util.zip.Inflater
/**
* Ktor HttpClient. 不同平台使用不同引擎.
*/
@OptIn(KtorExperimentalAPI::class)
actual val Http: HttpClient
get() = HttpClient(CIO)
/**
* Localhost 解析
*/
actual fun localIpAddress(): String = runCatching {
InetAddress.getLocalHost().hostAddress
}.getOrElse { "192.168.1.123" }
/**
* MD5 算法
*
* @return 16 bytes
*/
actual fun md5(byteArray: ByteArray, offset: Int, length: Int): ByteArray =
MessageDigest.getInstance("MD5").apply { update(byteArray, offset, length) }.digest()
fun InputStream.md5(): ByteArray {
val digest = MessageDigest.getInstance("md5")
digest.reset()
this.readInSequence {
digest.update(it.toByte())
}
return digest.digest()
}
fun DataInput.md5(): ByteArray {
val digest = MessageDigest.getInstance("md5")
digest.reset()
val buffer = byteArrayOf(1)
while (true) {
try {
this.readFully(buffer)
} catch (e: EOFException) {
break
}
digest.update(buffer[0])
}
return digest.digest()
}
private inline fun InputStream.readInSequence(block: (Int) -> Unit) {
var read: Int
while (this.read().also { read = it } != -1) {
block(read)
}
}
@OptIn(MiraiInternalAPI::class)
actual fun ByteArray.unzip(offset: Int, length: Int): ByteArray {
this.checkOffsetAndLength(offset, length)
if (length == 0) return ByteArray(0)
val inflater = Inflater()
inflater.reset()
ByteArrayOutputStream().use { output ->
inflater.setInput(this, offset, length)
ByteArrayPool.useInstance {
while (!inflater.finished()) {
output.write(it, 0, inflater.inflate(it))
}
}
inflater.end()
return output.toByteArray()
}
}
/**
* 时间戳
*/
actual val currentTimeMillis: Long get() = System.currentTimeMillis()
actual val currentTimeMillis: Long get() = System.currentTimeMillis()
@MiraiInternalAPI
actual object MiraiPlatformUtils {
actual fun unzip(data: ByteArray, offset: Int, length: Int): ByteArray {
data.checkOffsetAndLength(offset, length)
if (length == 0) return ByteArray(0)
val inflater = Inflater()
inflater.reset()
ByteArrayOutputStream().use { output ->
inflater.setInput(data, offset, length)
ByteArrayPool.useInstance {
while (!inflater.finished()) {
output.write(it, 0, inflater.inflate(it))
}
}
inflater.end()
return output.toByteArray()
}
}
actual fun zip(data: ByteArray, offset: Int, length: Int): ByteArray {
data.checkOffsetAndLength(offset, length)
if (length == 0) return ByteArray(0)
val inflater = Deflater()
inflater.reset()
ByteArrayOutputStream().use { output ->
inflater.setInput(data, offset, length)
ByteArrayPool.useInstance {
while (!inflater.finished()) {
output.write(it, 0, inflater.deflate(it))
}
}
inflater.end()
return output.toByteArray()
}
}
actual fun md5(data: ByteArray, offset: Int, length: Int): ByteArray {
data.checkOffsetAndLength(offset, length)
return MessageDigest.getInstance("MD5").apply { update(data, offset, length) }.digest()
}
actual inline fun md5(str: String): ByteArray = md5(str.toByteArray())
/**
* Ktor HttpClient. 不同平台使用不同引擎.
*/
@OptIn(KtorExperimentalAPI::class)
actual val Http: HttpClient
get() = HttpClient(CIO)
/**
* Localhost 解析
*/
actual fun localIpAddress(): String = runCatching {
InetAddress.getLocalHost().hostAddress
}.getOrElse { "192.168.1.123" }
fun md5(stream: InputStream): ByteArray {
val digest = MessageDigest.getInstance("md5")
digest.reset()
stream.readInSequence {
digest.update(it.toByte())
}
return digest.digest()
}
private inline fun InputStream.readInSequence(block: (Int) -> Unit) {
var read: Int
while (this.read().also { read = it } != -1) {
block(read)
}
}
}

View File

@ -14,7 +14,7 @@ package net.mamoe.mirai
import kotlinx.io.core.toByteArray
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.md5
import net.mamoe.mirai.utils.MiraiPlatformUtils
import kotlin.annotation.AnnotationTarget.*
@MiraiInternalAPI
@ -28,7 +28,7 @@ data class BotAccount(
@MiraiInternalAPI
val passwordMd5: ByteArray // md5
) {
constructor(id: Long, passwordPlainText: String) : this(id, md5(passwordPlainText.toByteArray()))
constructor(id: Long, passwordPlainText: String) : this(id, MiraiPlatformUtils.md5(passwordPlainText.toByteArray()))
override fun equals(other: Any?): Boolean {
if (this === other) return true

View File

@ -94,6 +94,7 @@ abstract class DeviceInfo {
}
}
@OptIn(MiraiInternalAPI::class)
@Serializable
class DeviceInfoData(
override val display: ByteArray,
@ -122,7 +123,8 @@ class DeviceInfoData(
@OptIn(ExperimentalUnsignedTypes::class)
override val ipAddress: ByteArray
get() = localIpAddress().split(".").map { it.toUByte().toByte() }.takeIf { it.size == 4 }?.toByteArray()
get() = MiraiPlatformUtils.localIpAddress().split(".").map { it.toUByte().toByte() }.takeIf { it.size == 4 }
?.toByteArray()
?: byteArrayOf()
override val androidId: ByteArray get() = display
@ -138,7 +140,9 @@ class DeviceInfoData(
/**
* Defaults "%4;7t>;28<fc.5*6".toByteArray()
*/
fun generateGuid(androidId: ByteArray, macAddress: ByteArray): ByteArray = md5(androidId + macAddress)
@OptIn(MiraiInternalAPI::class)
fun generateGuid(androidId: ByteArray, macAddress: ByteArray): ByteArray =
MiraiPlatformUtils.md5(androidId + macAddress)
/*
fun DeviceInfo.toOidb0x769DeviceInfo() : Oidb0x769.DeviceInfo = Oidb0x769.DeviceInfo(

View File

@ -12,7 +12,6 @@
package net.mamoe.mirai.utils
import io.ktor.client.HttpClient
import kotlinx.io.core.toByteArray
/**
* 时间戳
@ -21,30 +20,30 @@ expect val currentTimeMillis: Long
inline val currentTimeSeconds: Long get() = currentTimeMillis / 1000
/**
* zip 压缩
* 仅供内部使用的工具类.
* 不写为扩展是为了避免污染命名空间.
*/
expect fun ByteArray.unzip(offset: Int = 0, length: Int = this.size - offset): ByteArray
@MiraiInternalAPI
expect object MiraiPlatformUtils {
fun unzip(data: ByteArray, offset: Int = 0, length: Int = data.size - offset): ByteArray
/**
* MD5 算法
*
* @return 16 bytes
*/
expect fun md5(byteArray: ByteArray, offset: Int = 0, length: Int = byteArray.size - offset): ByteArray
fun zip(data: ByteArray, offset: Int = 0, length: Int = data.size - offset): ByteArray
inline fun md5(str: String): ByteArray = md5(str.toByteArray())
/**
* Localhost 解析
*/
expect fun localIpAddress(): String
fun md5(data: ByteArray, offset: Int = 0, length: Int = data.size - offset): ByteArray
inline fun md5(str: String): ByteArray
fun localIpAddress(): String
/**
* Ktor HttpClient. 不同平台使用不同引擎.
*/
@MiraiInternalAPI
val Http: HttpClient
}
/**
* Ktor HttpClient. 不同平台使用不同引擎.
*/
expect val Http: HttpClient
@Suppress("DuplicatedCode") // false positive. `this` is not the same for `List<Byte>` and `ByteArray`
internal fun ByteArray.checkOffsetAndLength(offset: Int, length: Int) {

View File

@ -11,8 +11,8 @@
package net.mamoe.mirai.utils
import kotlinx.coroutines.io.ByteReadChannel
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.io.ByteReadChannel
import kotlinx.coroutines.withContext
import kotlinx.io.core.Input
import kotlinx.io.core.buildPacket
@ -60,6 +60,7 @@ suspend inline fun BufferedImage.suspendToExternalImage(): ExternalImage = withC
/**
* 读取文件头识别图片属性, 然后构造 [ExternalImage]
*/
@OptIn(MiraiInternalAPI::class)
@Throws(IOException::class)
fun File.toExternalImage(): ExternalImage {
val input = ImageIO.createImageInputStream(this)
@ -71,7 +72,7 @@ fun File.toExternalImage(): ExternalImage {
return ExternalImage(
width = image.getWidth(0),
height = image.getHeight(0),
md5 = this.inputStream().md5(), // dont change
md5 = MiraiPlatformUtils.md5(this.inputStream()), // dont change
imageFormat = image.formatName,
input = this.inputStream(),
filename = this.name

View File

@ -7,78 +7,103 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("EXPERIMENTAL_API_USAGE")
@file:Suppress("EXPERIMENTAL_API_USAGE", "NOTHING_TO_INLINE")
package net.mamoe.mirai.utils
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.util.KtorExperimentalAPI
import kotlinx.io.pool.useInstance
import net.mamoe.mirai.utils.io.ByteArrayPool
import java.io.*
import java.io.ByteArrayOutputStream
import java.io.InputStream
import java.io.OutputStream
import java.net.InetAddress
import java.security.MessageDigest
import java.util.zip.Deflater
import java.util.zip.Inflater
actual fun md5(byteArray: ByteArray, offset: Int, length: Int): ByteArray =
MessageDigest.getInstance("MD5").apply { update(byteArray, offset, length) }.digest()
fun InputStream.md5(): ByteArray = this.use {
val digest = MessageDigest.getInstance("md5")
digest.reset()
this.use { input ->
object : OutputStream() {
override fun write(b: Int) {
digest.update(b.toByte())
}
}.use { output ->
input.copyTo(output)
}
}
return digest.digest()
}
fun DataInput.md5(): ByteArray {
val digest = MessageDigest.getInstance("md5")
digest.reset()
val buffer = byteArrayOf(1)
while (true) {
try {
this.readFully(buffer)
} catch (e: EOFException) {
break
}
digest.update(buffer[0])
}
return digest.digest()
}
actual fun localIpAddress(): String = InetAddress.getLocalHost().hostAddress
actual val Http: HttpClient get() = HttpClient(CIO)
@OptIn(MiraiInternalAPI::class)
actual fun ByteArray.unzip(offset: Int, length: Int): ByteArray {
this.checkOffsetAndLength(offset, length)
if (length == 0) return ByteArray(0)
val inflater = Inflater()
inflater.reset()
ByteArrayOutputStream().use { output ->
inflater.setInput(this, offset, length)
ByteArrayPool.useInstance {
while (!inflater.finished()) {
output.write(it, 0, inflater.inflate(it))
}
}
inflater.end()
return output.toByteArray()
}
}
/**
* 时间戳
*/
actual val currentTimeMillis: Long
get() = System.currentTimeMillis()
get() = System.currentTimeMillis()
@MiraiInternalAPI
actual object MiraiPlatformUtils {
actual fun unzip(data: ByteArray, offset: Int, length: Int): ByteArray {
data.checkOffsetAndLength(offset, length)
if (length == 0) return ByteArray(0)
val inflater = Inflater()
inflater.reset()
ByteArrayOutputStream().use { output ->
inflater.setInput(data, offset, length)
ByteArrayPool.useInstance {
while (!inflater.finished()) {
output.write(it, 0, inflater.inflate(it))
}
}
inflater.end()
return output.toByteArray()
}
}
actual fun zip(data: ByteArray, offset: Int, length: Int): ByteArray {
data.checkOffsetAndLength(offset, length)
if (length == 0) return ByteArray(0)
val inflater = Deflater()
inflater.reset()
ByteArrayOutputStream().use { output ->
inflater.setInput(data, offset, length)
ByteArrayPool.useInstance {
while (!inflater.finished()) {
output.write(it, 0, inflater.deflate(it))
}
}
inflater.end()
return output.toByteArray()
}
}
actual fun md5(data: ByteArray, offset: Int, length: Int): ByteArray {
data.checkOffsetAndLength(offset, length)
return MessageDigest.getInstance("MD5").apply { update(data, offset, length) }.digest()
}
actual inline fun md5(str: String): ByteArray = md5(str.toByteArray())
/**
* Ktor HttpClient. 不同平台使用不同引擎.
*/
@OptIn(KtorExperimentalAPI::class)
actual val Http: HttpClient
get() = HttpClient(CIO)
/**
* Localhost 解析
*/
actual fun localIpAddress(): String = runCatching {
InetAddress.getLocalHost().hostAddress
}.getOrElse { "192.168.1.123" }
fun md5(stream: InputStream): ByteArray {
val digest = MessageDigest.getInstance("md5")
digest.reset()
stream.use { input ->
object : OutputStream() {
override fun write(b: Int) {
digest.update(b.toByte())
}
}.use { output ->
input.copyTo(output)
}
}
return digest.digest()
}
}

View File

@ -15,6 +15,8 @@ import kotlinx.serialization.Transient
import kotlinx.serialization.UnstableDefault
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import net.mamoe.mirai.utils.MiraiPlatformUtils.localIpAddress
import net.mamoe.mirai.utils.MiraiPlatformUtils.md5
import net.mamoe.mirai.utils.io.getRandomByteArray
import net.mamoe.mirai.utils.io.getRandomString
import java.io.File
@ -37,7 +39,7 @@ fun File.loadAsDeviceInfo(context: Context = ContextImpl()): DeviceInfo {
private val JSON = Json(JsonConfiguration.Stable)
@Serializable
@OptIn(ExperimentalUnsignedTypes::class)
@OptIn(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
actual open class SystemDeviceInfo actual constructor() : DeviceInfo() {
actual constructor(context: Context) : this() {
this.context = context

View File

@ -9,7 +9,8 @@
package net.mamoe.mirai.utils.cryptor
import net.mamoe.mirai.utils.md5
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.MiraiPlatformUtils
import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.security.*
import java.security.spec.ECGenParameterSpec
@ -58,6 +59,7 @@ actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) {
.genKeyPair())
}
@OptIn(MiraiInternalAPI::class)
actual fun calculateShareKey(
privateKey: ECDHPrivateKey,
publicKey: ECDHPublicKey
@ -65,7 +67,7 @@ actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) {
val instance = KeyAgreement.getInstance("ECDH", "BC")
instance.init(privateKey)
instance.doPhase(publicKey, true)
return md5(instance.generateSecret())
return MiraiPlatformUtils.md5(instance.generateSecret())
}
actual fun constructPublicKey(key: ByteArray): ECDHPublicKey {