mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 13:12:17 +08:00
Shamrock
: 实现鉴权
Signed-off-by: 白池 <whitechi73@outlook.com>
This commit is contained in:
parent
1afc0ac6a6
commit
bbdfb7c04e
2
kritor
2
kritor
@ -1 +1 @@
|
|||||||
Subproject commit f4fa15754e266182b5f2c08c54c88c21c61eb065
|
Subproject commit 505d80b2eec8d5f226ed28390fb15f4ca41b4c70
|
64
xposed/src/main/java/kritor/auth/AuthInterceptor.kt
Normal file
64
xposed/src/main/java/kritor/auth/AuthInterceptor.kt
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package kritor.auth
|
||||||
|
|
||||||
|
import io.grpc.ForwardingServerCallListener
|
||||||
|
import io.grpc.Metadata
|
||||||
|
import io.grpc.ServerCall
|
||||||
|
import io.grpc.ServerCallHandler
|
||||||
|
import io.grpc.ServerInterceptor
|
||||||
|
import moe.fuqiuluo.shamrock.config.ActiveTicket
|
||||||
|
import moe.fuqiuluo.shamrock.config.ShamrockConfig
|
||||||
|
|
||||||
|
object AuthInterceptor: ServerInterceptor {
|
||||||
|
/**
|
||||||
|
* Intercept [ServerCall] dispatch by the `next` [ServerCallHandler]. General
|
||||||
|
* semantics of [ServerCallHandler.startCall] apply and the returned
|
||||||
|
* [io.grpc.ServerCall.Listener] must not be `null`.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* If the implementation throws an exception, `call` will be closed with an error.
|
||||||
|
* Implementations must not throw an exception if they started processing that may use `call` on another thread.
|
||||||
|
*
|
||||||
|
* @param call object to receive response messages
|
||||||
|
* @param headers which can contain extra call metadata from [ClientCall.start],
|
||||||
|
* e.g. authentication credentials.
|
||||||
|
* @param next next processor in the interceptor chain
|
||||||
|
* @return listener for processing incoming messages for `call`, never `null`.
|
||||||
|
*/
|
||||||
|
override fun <ReqT : Any?, RespT : Any?> interceptCall(
|
||||||
|
call: ServerCall<ReqT, RespT>,
|
||||||
|
headers: Metadata?,
|
||||||
|
next: ServerCallHandler<ReqT, RespT>
|
||||||
|
): ServerCall.Listener<ReqT> {
|
||||||
|
val methodName = call.methodDescriptor.fullMethodName
|
||||||
|
val ticket = getAllTicket()
|
||||||
|
if (ticket.isNotEmpty() && !methodName.startsWith("Auth")) {
|
||||||
|
val ticketHeader = headers?.get(Metadata.Key.of("ticket", Metadata.ASCII_STRING_MARSHALLER))
|
||||||
|
if (ticketHeader == null || ticketHeader !in ticket) {
|
||||||
|
call.close(io.grpc.Status.UNAUTHENTICATED.withDescription("Invalid ticket"), Metadata())
|
||||||
|
return object: ServerCall.Listener<ReqT>() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return object: ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(next.startCall(call, headers)) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAllTicket(): List<String> {
|
||||||
|
val result = arrayListOf<String>()
|
||||||
|
val activeTicketName = ActiveTicket.name()
|
||||||
|
var index = 0
|
||||||
|
while (true) {
|
||||||
|
val ticket = ShamrockConfig.getProperty(activeTicketName + if (index == 0) "" else ".$index", null)
|
||||||
|
if (ticket.isNullOrEmpty()) {
|
||||||
|
if (index == 0) {
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.add(ticket)
|
||||||
|
}
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
@ -3,11 +3,10 @@ package kritor.server
|
|||||||
|
|
||||||
import io.grpc.Grpc
|
import io.grpc.Grpc
|
||||||
import io.grpc.InsecureServerCredentials
|
import io.grpc.InsecureServerCredentials
|
||||||
import io.grpc.ServerBuilder
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.asExecutor
|
||||||
import kritor.service.*
|
import kritor.service.*
|
||||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
@ -16,7 +15,9 @@ class KritorServer(
|
|||||||
private val port: Int
|
private val port: Int
|
||||||
): CoroutineScope {
|
): CoroutineScope {
|
||||||
private val server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create())
|
private val server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create())
|
||||||
|
.executor(Dispatchers.IO.asExecutor())
|
||||||
.addService(Authentication)
|
.addService(Authentication)
|
||||||
|
.addService(ContactService)
|
||||||
.build()!!
|
.build()!!
|
||||||
|
|
||||||
fun start(block: Boolean = false) {
|
fun start(block: Boolean = false) {
|
||||||
|
47
xposed/src/main/java/kritor/service/ContactService.kt
Normal file
47
xposed/src/main/java/kritor/service/ContactService.kt
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package kritor.service
|
||||||
|
|
||||||
|
import io.grpc.Status
|
||||||
|
import io.grpc.StatusRuntimeException
|
||||||
|
import io.kritor.AuthCode
|
||||||
|
import io.kritor.authRsp
|
||||||
|
import io.kritor.contact.ContactServiceGrpcKt
|
||||||
|
import io.kritor.contact.ProfileCard
|
||||||
|
import io.kritor.contact.ProfileCardRequest
|
||||||
|
import io.kritor.contact.profileCard
|
||||||
|
import moe.fuqiuluo.shamrock.config.ActiveTicket
|
||||||
|
import moe.fuqiuluo.shamrock.config.ShamrockConfig
|
||||||
|
import qq.service.contact.ContactHelper
|
||||||
|
|
||||||
|
object ContactService: ContactServiceGrpcKt.ContactServiceCoroutineImplBase() {
|
||||||
|
override suspend fun getProfileCard(request: ProfileCardRequest): ProfileCard {
|
||||||
|
val uin = if (request.hasUin()) request.uin
|
||||||
|
else ContactHelper.getUinByUidAsync(request.uid).toLong()
|
||||||
|
val contact = ContactHelper.getProfileCard(uin)
|
||||||
|
|
||||||
|
contact.onFailure {
|
||||||
|
throw StatusRuntimeException(Status.INTERNAL
|
||||||
|
.withDescription(it.stackTraceToString())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
contact.onSuccess {
|
||||||
|
return profileCard {
|
||||||
|
this.uin = it.uin.toLong()
|
||||||
|
this.uid = if (request.hasUid()) request.uid
|
||||||
|
else ContactHelper.getUidByUinAsync(it.uin.toLong())
|
||||||
|
this.name = it.strNick ?: ""
|
||||||
|
this.remark = it.strReMark ?: ""
|
||||||
|
this.level = it.iQQLevel
|
||||||
|
this.birthday = it.lBirthday
|
||||||
|
this.loginDay = it.lLoginDays.toInt()
|
||||||
|
this.voteCnt = it.lVoteCount.toInt()
|
||||||
|
this.qid = it.qid ?: ""
|
||||||
|
this.isSchoolVerified = it.schoolVerifiedFlag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw StatusRuntimeException(Status.INTERNAL
|
||||||
|
.withDescription("logic failed")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -1,32 +0,0 @@
|
|||||||
package moe.fuqiuluo.shamrock.helper
|
|
||||||
|
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
|
||||||
import moe.fuqiuluo.shamrock.internals.NTServiceFetcher
|
|
||||||
import kotlin.coroutines.resume
|
|
||||||
|
|
||||||
internal object ContactHelper {
|
|
||||||
suspend fun getUinByUidAsync(uid: String): String {
|
|
||||||
if (uid.isBlank() || uid == "0") {
|
|
||||||
return "0"
|
|
||||||
}
|
|
||||||
|
|
||||||
val kernelService = NTServiceFetcher.kernelService
|
|
||||||
val sessionService = kernelService.wrapperSession
|
|
||||||
|
|
||||||
return suspendCancellableCoroutine { continuation ->
|
|
||||||
sessionService.uixConvertService.getUin(hashSetOf(uid)) {
|
|
||||||
continuation.resume(it)
|
|
||||||
}
|
|
||||||
}[uid]?.toString() ?: "0"
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getUidByUinAsync(peerId: Long): String {
|
|
||||||
val kernelService = NTServiceFetcher.kernelService
|
|
||||||
val sessionService = kernelService.wrapperSession
|
|
||||||
return suspendCancellableCoroutine { continuation ->
|
|
||||||
sessionService.uixConvertService.getUid(hashSetOf(peerId)) {
|
|
||||||
continuation.resume(it)
|
|
||||||
}
|
|
||||||
}[peerId]!!
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,7 +8,7 @@ import com.arthenica.ffmpegkit.FFmpegKit
|
|||||||
import com.arthenica.ffmpegkit.FFprobeKit
|
import com.arthenica.ffmpegkit.FFprobeKit
|
||||||
import com.arthenica.ffmpegkit.ReturnCode
|
import com.arthenica.ffmpegkit.ReturnCode
|
||||||
import com.tencent.qqnt.kernel.nativeinterface.QQNTWrapperUtil
|
import com.tencent.qqnt.kernel.nativeinterface.QQNTWrapperUtil
|
||||||
import qq.service.contact.LocalCacheHelper
|
import qq.service.internals.LocalCacheHelper
|
||||||
import moe.fuqiuluo.shamrock.helper.Level
|
import moe.fuqiuluo.shamrock.helper.Level
|
||||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
87
xposed/src/main/java/qq/service/contact/ContactHelper.kt
Normal file
87
xposed/src/main/java/qq/service/contact/ContactHelper.kt
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package qq.service.contact
|
||||||
|
|
||||||
|
import com.tencent.common.app.AppInterface
|
||||||
|
import com.tencent.mobileqq.data.Card
|
||||||
|
import com.tencent.mobileqq.profilecard.api.IProfileDataService
|
||||||
|
import com.tencent.mobileqq.profilecard.api.IProfileProtocolService
|
||||||
|
import com.tencent.mobileqq.profilecard.observer.ProfileCardObserver
|
||||||
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import moe.fuqiuluo.shamrock.internals.NTServiceFetcher
|
||||||
|
import qq.service.QQInterfaces
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
|
||||||
|
object ContactHelper: QQInterfaces() {
|
||||||
|
private val refreshCardLock by lazy { Mutex() }
|
||||||
|
|
||||||
|
suspend fun getProfileCard(uin: Long): Result<Card> {
|
||||||
|
return getProfileCardFromCache(uin).onFailure {
|
||||||
|
return refreshAndGetProfileCard(uin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getProfileCardFromCache(uin: Long): Result<Card> {
|
||||||
|
val profileDataService = app
|
||||||
|
.getRuntimeService(IProfileDataService::class.java, "all")
|
||||||
|
val card = profileDataService.getProfileCard(uin.toString(), true)
|
||||||
|
return if (card == null || card.strNick.isNullOrEmpty()) {
|
||||||
|
Result.failure(Exception("unable to fetch profile card"))
|
||||||
|
} else {
|
||||||
|
Result.success(card)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun refreshAndGetProfileCard(uin: Long): Result<Card> {
|
||||||
|
require(app is AppInterface)
|
||||||
|
val dataService = app
|
||||||
|
.getRuntimeService(IProfileDataService::class.java, "all")
|
||||||
|
val card = refreshCardLock.withLock {
|
||||||
|
suspendCancellableCoroutine {
|
||||||
|
app.addObserver(object: ProfileCardObserver() {
|
||||||
|
override fun onGetProfileCard(success: Boolean, obj: Any) {
|
||||||
|
app.removeObserver(this)
|
||||||
|
if (!success || obj !is Card) {
|
||||||
|
it.resume(null)
|
||||||
|
} else {
|
||||||
|
dataService.saveProfileCard(obj)
|
||||||
|
it.resume(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
app.getRuntimeService(IProfileProtocolService::class.java, "all")
|
||||||
|
.requestProfileCard(app.currentUin, uin.toString(), 12, 0L, 0.toByte(), 0L, 0L, null, "", 0L, 10004, null, 0.toByte())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return if (card == null || card.strNick.isNullOrEmpty()) {
|
||||||
|
Result.failure(Exception("unable to fetch profile card"))
|
||||||
|
} else {
|
||||||
|
Result.success(card)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getUinByUidAsync(uid: String): String {
|
||||||
|
if (uid.isBlank() || uid == "0") {
|
||||||
|
return "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
val kernelService = NTServiceFetcher.kernelService
|
||||||
|
val sessionService = kernelService.wrapperSession
|
||||||
|
|
||||||
|
return suspendCancellableCoroutine { continuation ->
|
||||||
|
sessionService.uixConvertService.getUin(hashSetOf(uid)) {
|
||||||
|
continuation.resume(it)
|
||||||
|
}
|
||||||
|
}[uid]?.toString() ?: "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getUidByUinAsync(peerId: Long): String {
|
||||||
|
val kernelService = NTServiceFetcher.kernelService
|
||||||
|
val sessionService = kernelService.wrapperSession
|
||||||
|
return suspendCancellableCoroutine { continuation ->
|
||||||
|
sessionService.uixConvertService.getUid(hashSetOf(peerId)) {
|
||||||
|
continuation.resume(it)
|
||||||
|
}
|
||||||
|
}[peerId]!!
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package qq.service.contact
|
package qq.service.internals
|
||||||
|
|
||||||
import moe.fuqiuluo.shamrock.utils.FileUtils
|
import moe.fuqiuluo.shamrock.utils.FileUtils
|
||||||
import mqq.app.MobileQQ
|
import mqq.app.MobileQQ
|
Loading…
x
Reference in New Issue
Block a user