Skip to content

Commit

Permalink
feat: encrypted message
Browse files Browse the repository at this point in the history
  • Loading branch information
fuqiuluo committed Jul 23, 2024
1 parent da544d8 commit e2dba99
Show file tree
Hide file tree
Showing 19 changed files with 1,292 additions and 30 deletions.
11 changes: 11 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,20 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:$serializationVersion")
implementation("com.google.protobuf:protobuf-java:4.26.1")
implementation("androidx.core:core-ktx:1.13.1")

implementation(ktor("client", "core"))
implementation(ktor("client", "content-negotiation"))
implementation(ktor("client", "cio"))
implementation(ktor("serialization", "kotlinx-json"))
implementation(ktor("network", "tls-certificates"))

testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test:core:1.5.0")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test:runner:1.5.2")
androidTestImplementation("androidx.test:rules:1.5.0")
}

fun ktor(target: String, name: String): String {
return "io.ktor:ktor-$target-$name:2.3.3"
}
72 changes: 72 additions & 0 deletions app/src/main/java/moe/fuqiuluo/MsfHandler.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package moe.fuqiuluo

import com.tencent.qphone.base.remote.FromServiceMsg
import com.tencent.qphone.base.remote.ToServiceMsg
import de.robv.android.xposed.XposedBridge
import kotlinx.atomicfu.atomic
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.coroutines.resume

typealias MsfPush = (FromServiceMsg) -> Unit
typealias MsfResp = CancellableContinuation<Pair<ToServiceMsg, FromServiceMsg>>

internal object MSFHandler {
private val mPushHandlers = hashMapOf<String, MsfPush>()
private val mRespHandler = hashMapOf<Int, MsfResp>()
private val mPushLock = Mutex()
private val mRespLock = Mutex()

private val seq = atomic(0)

fun nextSeq(): Int {
seq.compareAndSet(0xFFFFFFF, 0)
return seq.incrementAndGet()
}

suspend fun registerPush(cmd: String, push: MsfPush) {
mPushLock.withLock {
mPushHandlers[cmd] = push
}
}

suspend fun unregisterPush(cmd: String) {
mPushLock.withLock {
mPushHandlers.remove(cmd)
}
}

suspend fun registerResp(cmd: Int, resp: MsfResp) {
mRespLock.withLock {
mRespHandler[cmd] = resp
}
}

suspend fun unregisterResp(cmd: Int) {
mRespLock.withLock {
mRespHandler.remove(cmd)
}
}

fun onPush(fromServiceMsg: FromServiceMsg) {
val cmd = fromServiceMsg.serviceCmd
if (cmd == "trpc.msg.olpush.OlPushService.MsgPush") {
//PrimitiveListener.onPush(fromServiceMsg)
} else {
val push = mPushHandlers[cmd]
push?.invoke(fromServiceMsg)
}
}

fun onResp(toServiceMsg: ToServiceMsg, fromServiceMsg: FromServiceMsg) {
runCatching {
val cmd = toServiceMsg.getAttribute("qwq_uid") as? Int?
?: return@runCatching
val resp = mRespHandler[cmd]
resp?.resume(toServiceMsg to fromServiceMsg)
}.onFailure {
XposedBridge.log("[QwQ] MSF.onResp failed: ${it.message}")
}
}
}
136 changes: 136 additions & 0 deletions app/src/main/java/moe/fuqiuluo/QQInterfaces.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package moe.fuqiuluo

import android.os.Bundle
import com.tencent.common.app.AppInterface
import com.tencent.mobileqq.pb.ByteStringMicro
import com.tencent.qphone.base.remote.FromServiceMsg
import com.tencent.qphone.base.remote.ToServiceMsg
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withTimeoutOrNull
import kotlinx.serialization.encodeToByteArray
import kotlinx.serialization.protobuf.ProtoBuf
import moe.fuqiuluo.entries.TrpcOidb
import moe.qwq.miko.tools.PlatformTools
import moe.qwq.miko.tools.PlatformTools.app
import mqq.app.MobileQQ
import tencent.im.oidb.oidb_sso
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

abstract class QQInterfaces {

companion object {
fun sendToServiceMsg(to: ToServiceMsg) {
app.sendToService(to)
}

suspend fun sendToServiceMsgAW(
to: ToServiceMsg,
timeout: Duration = 30.seconds
): FromServiceMsg? {
val seq = MSFHandler.nextSeq()
to.addAttribute("qwq_uid", seq)
val resp: Pair<ToServiceMsg, FromServiceMsg>? = withTimeoutOrNull(timeout) {
suspendCancellableCoroutine { continuation ->
GlobalScope.launch {
MSFHandler.registerResp(seq, continuation)
sendToServiceMsg(to)
}
}
}
if (resp == null) {
MSFHandler.unregisterResp(seq)
}
return resp?.second
}

fun sendExtra(cmd: String, builder: (Bundle) -> Unit) {
val toServiceMsg = createToServiceMsg(cmd)
builder(toServiceMsg.extraData)
app.sendToService(toServiceMsg)
}

fun createToServiceMsg(cmd: String): ToServiceMsg {
return ToServiceMsg("mobileqq.service", app.currentAccountUin, cmd)
}

fun sendOidb(cmd: String, command: Int, service: Int, data: ByteArray, trpc: Boolean = false) {
val to = createToServiceMsg(cmd)
if (trpc) {
val oidb = TrpcOidb(
cmd = command,
service = service,
buffer = data,
flag = 1
)
to.putWupBuffer(ProtoBuf.encodeToByteArray(oidb))
} else {
val oidb = oidb_sso.OIDBSSOPkg()
oidb.uint32_command.set(command)
oidb.uint32_service_type.set(service)
oidb.bytes_bodybuffer.set(ByteStringMicro.copyFrom(data))
oidb.str_client_version.set(PlatformTools.getClientVersion(MobileQQ.getContext()))
to.putWupBuffer(oidb.toByteArray())
}
to.addAttribute("req_pb_protocol_flag", true)
app.sendToService(to)
}

fun sendBuffer(
cmd: String,
isProto: Boolean,
data: ByteArray,
) {
val toServiceMsg = createToServiceMsg(cmd)
toServiceMsg.putWupBuffer(data)
toServiceMsg.addAttribute("req_pb_protocol_flag", isProto)
sendToServiceMsg(toServiceMsg)
}

@DelicateCoroutinesApi
suspend fun sendBufferAW(
cmd: String,
isProto: Boolean,
data: ByteArray,
timeout: Duration = 30.seconds
): FromServiceMsg? {
val toServiceMsg = createToServiceMsg(cmd)
toServiceMsg.putWupBuffer(data)
toServiceMsg.addAttribute("req_pb_protocol_flag", isProto)
return sendToServiceMsgAW(toServiceMsg, timeout)
}

@DelicateCoroutinesApi
suspend fun sendOidbAW(
cmd: String,
command: Int,
service: Int,
data: ByteArray,
trpc: Boolean = false,
timeout: Duration = 30.seconds
): FromServiceMsg? {
val to = createToServiceMsg(cmd)
if (trpc) {
val oidb = TrpcOidb(
cmd = command,
service = service,
buffer = data,
flag = 1
)
to.putWupBuffer(ProtoBuf.encodeToByteArray(oidb))
} else {
val oidb = oidb_sso.OIDBSSOPkg()
oidb.uint32_command.set(command)
oidb.uint32_service_type.set(service)
oidb.bytes_bodybuffer.set(ByteStringMicro.copyFrom(data))
oidb.str_client_version.set(PlatformTools.getClientVersion(MobileQQ.getContext()))
to.putWupBuffer(oidb.toByteArray())
}
to.addAttribute("req_pb_protocol_flag", true)
return sendToServiceMsgAW(to, timeout)
}
}
}
2 changes: 1 addition & 1 deletion app/src/main/java/moe/fuqiuluo/entries/MessagePush.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ data class Message(

@Serializable
data class MessageHead(
@ProtoNumber(1) val peerId: Long = Long.MIN_VALUE,
@ProtoNumber(1) val peerId: ULong = ULong.MIN_VALUE,
@ProtoNumber(2) val peerUid: String? = null,
@ProtoNumber(5) val targetId: Long = Long.MIN_VALUE,
@ProtoNumber(6) val targetUid: String? = null
Expand Down
Loading

0 comments on commit e2dba99

Please sign in to comment.