diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/PushNotifyPack.kt b/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/PushNotifyPack.kt index 12ddbff03..3d45060cd 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/PushNotifyPack.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/PushNotifyPack.kt @@ -12,6 +12,10 @@ package net.mamoe.mirai.internal.network.protocol.data.jce import kotlinx.serialization.Serializable import net.mamoe.mirai.internal.network.Packet import net.mamoe.mirai.internal.utils.io.JceStruct +import net.mamoe.mirai.internal.utils.io.NestedStructure +import net.mamoe.mirai.internal.utils.io.NestedStructureDesensitizer +import net.mamoe.mirai.internal.utils.io.ProtocolStruct +import net.mamoe.mirai.internal.utils.io.serialization.loadAs import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId import net.mamoe.mirai.utils.EMPTY_BYTE_ARRAY @@ -46,6 +50,7 @@ internal class MsgInfo( @TarsId(3) @JvmField val shMsgSeq: Short, @TarsId(4) @JvmField val strMsg: String?, @TarsId(5) @JvmField val uRealMsgTime: Int?, + @param:NestedStructure(VMsgDesensitizationSerializer::class) @TarsId(6) @JvmField val vMsg: ByteArray, @TarsId(7) @JvmField val uAppShareID: Long?, @TarsId(8) @JvmField val vMsgCookies: ByteArray? = EMPTY_BYTE_ARRAY, @@ -62,6 +67,15 @@ internal class MsgInfo( //@SerialId(19) @JvmField val stC2CTmpMsgHead: TempMsgHead? ) : JceStruct +internal object VMsgDesensitizationSerializer : NestedStructureDesensitizer<MsgInfo, ProtocolStruct> { + override fun deserialize(context: MsgInfo, byteArray: ByteArray): ProtocolStruct? { + return when (context.shMsgType.toUShort().toInt()) { + 0x210 -> byteArray.loadAs(MsgType0x210.serializer()) + else -> null + } + } +} + @Serializable internal class ShareData( diff --git a/mirai-core/src/commonMain/kotlin/utils/io/ProtocolStruct.kt b/mirai-core/src/commonMain/kotlin/utils/io/ProtocolStruct.kt index e741b48b8..c3692f328 100644 --- a/mirai-core/src/commonMain/kotlin/utils/io/ProtocolStruct.kt +++ b/mirai-core/src/commonMain/kotlin/utils/io/ProtocolStruct.kt @@ -9,6 +9,18 @@ package net.mamoe.mirai.internal.utils.io +import kotlin.reflect.KClass + internal interface ProtocolStruct internal interface ProtoBuf : ProtocolStruct -internal interface JceStruct : ProtocolStruct \ No newline at end of file +internal interface JceStruct : ProtocolStruct + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.VALUE_PARAMETER) +internal annotation class NestedStructure( + val serializer: KClass<out NestedStructureDesensitizer<*, *>> +) + +internal interface NestedStructureDesensitizer<in C : ProtocolStruct, T : ProtocolStruct> { + fun deserialize(context: C, byteArray: ByteArray): T? +} \ No newline at end of file diff --git a/mirai-core/src/commonTest/kotlin/notice/Desensitizer.kt b/mirai-core/src/commonTest/kotlin/notice/Desensitizer.kt index 4df3cfcfc..179ab9721 100644 --- a/mirai-core/src/commonTest/kotlin/notice/Desensitizer.kt +++ b/mirai-core/src/commonTest/kotlin/notice/Desensitizer.kt @@ -11,11 +11,17 @@ package net.mamoe.mirai.internal.notice import kotlinx.serialization.decodeFromString import net.mamoe.mirai.Mirai +import net.mamoe.mirai.internal.notice.Desensitizer.Companion.generateAndDesensitize import net.mamoe.mirai.internal.utils.codegen.* +import net.mamoe.mirai.internal.utils.io.NestedStructure +import net.mamoe.mirai.internal.utils.io.NestedStructureDesensitizer +import net.mamoe.mirai.internal.utils.io.ProtocolStruct import net.mamoe.mirai.utils.* import net.mamoe.yamlkt.Yaml import net.mamoe.yamlkt.YamlBuilder import kotlin.reflect.KType +import kotlin.reflect.full.createInstance +import kotlin.reflect.full.findAnnotation import kotlin.reflect.typeOf private val logger: MiraiLogger by lazy { MiraiLogger.Factory.create(Desensitizer::class) } @@ -179,4 +185,20 @@ private class DesensitizationVisitor( desc.value = desensitizer.desensitize(desc.value as ByteArray) } } + + override fun <T : Any> visitClass(desc: ClassValueDesc<T>) { + super.visitClass(desc) + desc.properties.replaceAll() { key, value -> + val annotation = key.findAnnotation<NestedStructure>() + if (annotation != null && value.origin is ByteArray) { + val instance = annotation.serializer.objectInstance ?: annotation.serializer.createInstance() + + val result = instance.cast<NestedStructureDesensitizer<ProtocolStruct, ProtocolStruct>>() + .deserialize(desc.origin as ProtocolStruct, value.origin as ByteArray) + + val generate = ConstructorCallCodegenFacade.generateAndDesensitize(result) + PlainValueDesc(desc, "$generate.toByteArray()", value.origin) + } else value + } + } } \ No newline at end of file diff --git a/mirai-core/src/commonTest/kotlin/utils/codegen/ConstructorCallCodegenFacade.kt b/mirai-core/src/commonTest/kotlin/utils/codegen/ConstructorCallCodegenFacade.kt index 647fd5c47..60bdbdd6d 100644 --- a/mirai-core/src/commonTest/kotlin/utils/codegen/ConstructorCallCodegenFacade.kt +++ b/mirai-core/src/commonTest/kotlin/utils/codegen/ConstructorCallCodegenFacade.kt @@ -25,7 +25,7 @@ object ConstructorCallCodegenFacade { * Analyze [value] and give its correspondent [ValueDesc]. */ fun analyze(value: Any?, type: KType): ValueDesc { - if (value == null) return PlainValueDesc("null", null) + if (value == null) return PlainValueDesc(null, "null", null) val clazz = value::class @@ -43,14 +43,15 @@ object ConstructorCallCodegenFacade { prop.cast<KProperty1<Any, Any?>>() map[valueParameter] = analyze(prop.get(value), prop.returnType) } - return ClassValueDesc(value, map) + return ClassValueDesc(null, value, map) } - ArrayValueDesc.createOrNull(value, type)?.let { return it } + ArrayValueDesc.createOrNull(value, type, null)?.let { return it } if (value is Collection<*>) { - return CollectionValueDesc(value, arrayType = type, elementType = type.arguments.first().type!!) + return CollectionValueDesc(null, value, arrayType = type, elementType = type.arguments.first().type!!) } else if (value is Map<*, *>) { return MapValueDesc( + null, value.cast(), value.cast(), type, @@ -61,12 +62,12 @@ object ConstructorCallCodegenFacade { return when (value) { is CharSequence -> { - PlainValueDesc('"' + value.toString() + '"', value) + PlainValueDesc(null, '"' + value.toString() + '"', value) } is Char -> { - PlainValueDesc("'$value'", value) + PlainValueDesc(null, "'$value'", value) } - else -> PlainValueDesc(value.toString(), value) + else -> PlainValueDesc(null, value.toString(), value) } } diff --git a/mirai-core/src/commonTest/kotlin/utils/codegen/ValueDesc.kt b/mirai-core/src/commonTest/kotlin/utils/codegen/ValueDesc.kt index e9db2d249..767cf6926 100644 --- a/mirai-core/src/commonTest/kotlin/utils/codegen/ValueDesc.kt +++ b/mirai-core/src/commonTest/kotlin/utils/codegen/ValueDesc.kt @@ -17,10 +17,23 @@ import kotlin.reflect.typeOf sealed interface ValueDesc { val origin: Any? + val parent: ValueDesc? fun accept(visitor: ValueDescVisitor) } +val ValueDesc.parents + get() = sequence { + var parent = parent + do { + parent ?: return@sequence + yield(parent) + parent = parent.parent + } while (true); + } + +inline fun <reified T : ValueDesc> ValueDesc.findParent(): T? = parents.filterIsInstance<T>().firstOrNull() + sealed interface ArrayValueDesc : ValueDesc { val value: Any @@ -30,17 +43,27 @@ sealed interface ArrayValueDesc : ValueDesc { companion object { @OptIn(ExperimentalStdlibApi::class) - fun createOrNull(array: Any, type: KType): ArrayValueDesc? { - if (array is Array<*>) return ObjectArrayValueDesc(array, arrayType = type) + fun createOrNull(array: Any, type: KType, parent: ValueDesc?): ArrayValueDesc? { + if (array is Array<*>) return ObjectArrayValueDesc(parent, array, arrayType = type) return when (array) { - is IntArray -> PrimitiveArrayValueDesc(array, arrayType = type, elementType = typeOf<Int>()) - is ByteArray -> PrimitiveArrayValueDesc(array, arrayType = type, elementType = typeOf<Byte>()) - is ShortArray -> PrimitiveArrayValueDesc(array, arrayType = type, elementType = typeOf<Short>()) - is CharArray -> PrimitiveArrayValueDesc(array, arrayType = type, elementType = typeOf<Char>()) - is LongArray -> PrimitiveArrayValueDesc(array, arrayType = type, elementType = typeOf<Long>()) - is FloatArray -> PrimitiveArrayValueDesc(array, arrayType = type, elementType = typeOf<Float>()) - is DoubleArray -> PrimitiveArrayValueDesc(array, arrayType = type, elementType = typeOf<Double>()) - is BooleanArray -> PrimitiveArrayValueDesc(array, arrayType = type, elementType = typeOf<Boolean>()) + is IntArray -> PrimitiveArrayValueDesc(parent, array, arrayType = type, elementType = typeOf<Int>()) + is ByteArray -> PrimitiveArrayValueDesc(parent, array, arrayType = type, elementType = typeOf<Byte>()) + is ShortArray -> PrimitiveArrayValueDesc(parent, array, arrayType = type, elementType = typeOf<Short>()) + is CharArray -> PrimitiveArrayValueDesc(parent, array, arrayType = type, elementType = typeOf<Char>()) + is LongArray -> PrimitiveArrayValueDesc(parent, array, arrayType = type, elementType = typeOf<Long>()) + is FloatArray -> PrimitiveArrayValueDesc(parent, array, arrayType = type, elementType = typeOf<Float>()) + is DoubleArray -> PrimitiveArrayValueDesc( + parent, + array, + arrayType = type, + elementType = typeOf<Double>() + ) + is BooleanArray -> PrimitiveArrayValueDesc( + parent, + array, + arrayType = type, + elementType = typeOf<Boolean>() + ) else -> return null } } @@ -48,10 +71,11 @@ sealed interface ArrayValueDesc : ValueDesc { } class ObjectArrayValueDesc( + override val parent: ValueDesc?, override var value: Array<*>, override val origin: Array<*> = value, override val arrayType: KType, - override val elementType: KType = arrayType.arguments.first().type ?: Any::class.createType() + override val elementType: KType = arrayType.arguments.first().type ?: Any::class.createType(), ) : ArrayValueDesc { override val elements: MutableList<ValueDesc> by lazy { value.mapTo(mutableListOf()) { @@ -65,6 +89,7 @@ class ObjectArrayValueDesc( } class CollectionValueDesc( + override val parent: ValueDesc?, override var value: Collection<*>, override val origin: Collection<*> = value, override val arrayType: KType, @@ -82,6 +107,7 @@ class CollectionValueDesc( } class MapValueDesc( + override val parent: ValueDesc?, var value: Map<Any?, Any?>, override val origin: Map<Any?, Any?> = value, val mapType: KType, @@ -103,6 +129,7 @@ class MapValueDesc( } class PrimitiveArrayValueDesc( + override val parent: ValueDesc?, override var value: Any, override val origin: Any = value, override val arrayType: KType, @@ -128,6 +155,7 @@ class PrimitiveArrayValueDesc( } class PlainValueDesc( + override val parent: ValueDesc?, var value: String, override val origin: Any? ) : ValueDesc { @@ -141,6 +169,7 @@ class PlainValueDesc( } class ClassValueDesc<T : Any>( + override val parent: ValueDesc?, override val origin: T, val properties: MutableMap<KParameter, ValueDesc>, ) : ValueDesc {