Shamrock: プロファイルロジックの変更

Signed-off-by: WhiteChi <whitechi73@outlook.com>
This commit is contained in:
WhiteChi 2023-10-31 00:19:51 +08:00
parent 3f8af384b0
commit 4adf2eb84a
7 changed files with 88 additions and 64 deletions

View File

@ -180,6 +180,7 @@ fun LabFragment() {
return@Function true return@Function true
} }
/*
Function( Function(
title = "使用纯数字ECHO", title = "使用纯数字ECHO",
desc = "在部分强类型语言框架,需要打开此开关。", desc = "在部分强类型语言框架,需要打开此开关。",
@ -189,7 +190,7 @@ fun LabFragment() {
ShamrockConfig.setEchoNumber(ctx, it) ShamrockConfig.setEchoNumber(ctx, it)
ShamrockConfig.pushUpdate(ctx) ShamrockConfig.pushUpdate(ctx)
return@Function true return@Function true
} }*/
} }
} }
} }

View File

@ -3,7 +3,7 @@ plugins {
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
//id("io.realm.kotlin") //id("io.realm.kotlin")
id("kotlin-kapt") id("kotlin-kapt")
kotlin("plugin.serialization") version "1.8.0" kotlin("plugin.serialization") version "1.8.10"
} }
android { android {
@ -59,7 +59,8 @@ dependencies {
//implementation("io.realm.kotlin:library-sync:1.11.0") //implementation("io.realm.kotlin:library-sync:1.11.0")
val ktorVersion = "2.3.3" val ktorVersion = "2.3.3"
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1") //implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
implementation("io.github.xn32:json5k:0.3.0")
implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:0.1.16") implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:0.1.16")
implementation("io.ktor:ktor-server-core:$ktorVersion") implementation("io.ktor:ktor-server-core:$ktorVersion")
implementation("io.ktor:ktor-server-host-common:$ktorVersion") implementation("io.ktor:ktor-server-host-common:$ktorVersion")

View File

@ -51,7 +51,7 @@ internal class WebSocketService(port: Int): WebSocketTransmitServlet(port) {
} }
override fun onOpen(conn: WebSocket, handshake: ClientHandshake) { override fun onOpen(conn: WebSocket, handshake: ClientHandshake) {
val token = ShamrockConfig.getToken() val token = ShamrockConfig.getActiveWebSocketConfig()?.token ?: ShamrockConfig.getToken()
if (token.isNotBlank()) { if (token.isNotBlank()) {
var accessToken = handshake.getFieldValue("access_token") var accessToken = handshake.getFieldValue("access_token")
.ifNullOrEmpty(handshake.getFieldValue("ticket")) .ifNullOrEmpty(handshake.getFieldValue("ticket"))
@ -60,7 +60,8 @@ internal class WebSocketService(port: Int): WebSocketTransmitServlet(port) {
if (accessToken.startsWith("Bearer ")) { if (accessToken.startsWith("Bearer ")) {
accessToken = accessToken.substring(7) accessToken = accessToken.substring(7)
} }
if (token != accessToken) { val tokenList = token.split(",", "|", "")
if (!tokenList.contains(accessToken)) {
conn.close() conn.close()
LogCenter.log({ "WSServer连接错误(${conn.remoteSocketAddress.address.hostAddress}:${conn.remoteSocketAddress.port}) 没有提供正确的token, $accessToken" }, Level.ERROR) LogCenter.log({ "WSServer连接错误(${conn.remoteSocketAddress.address.hostAddress}:${conn.remoteSocketAddress.port}) 没有提供正确的token, $accessToken" }, Level.ERROR)
return return

View File

@ -5,8 +5,23 @@ import kotlinx.serialization.Serializable
@Serializable @Serializable
data class ServiceConfig( data class ServiceConfig(
@SerialName("rules") val rules: Rules? = null,
@SerialName("default_token") var defaultToken: String? = null,
@SerialName("active_websocket") var activeWebSocket: ConnectionConfig? = null,
@SerialName("passive_websocket") var passiveWebSocket: MutableList<ConnectionConfig>? = null,
)
@Serializable
data class ConnectionConfig(
@SerialName("address") val address: String? = null,
@SerialName("port") var port: Int? = null,
@SerialName("token") val token: String? = null,
)
@Serializable
data class Rules(
@SerialName("group_rule") val groupRule: GroupRule? = null, @SerialName("group_rule") val groupRule: GroupRule? = null,
@SerialName("private_rule") val privateRule: PrivateRule? = null, @SerialName("private_rule") val privateRule: PrivateRule? = null
) )
@Serializable @Serializable

View File

@ -1,7 +1,9 @@
package moe.fuqiuluo.shamrock.remote.service.config package moe.fuqiuluo.shamrock.remote.service.config
import android.content.Intent import android.content.Intent
import moe.fuqiuluo.shamrock.tools.GlobalJson import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import moe.fuqiuluo.shamrock.tools.GlobalJson5
import moe.fuqiuluo.shamrock.utils.MMKVFetcher import moe.fuqiuluo.shamrock.utils.MMKVFetcher
import mqq.app.MobileQQ import mqq.app.MobileQQ
import java.io.File import java.io.File
@ -12,35 +14,51 @@ internal object ShamrockConfig {
if (it.exists()) it.delete() if (it.exists()) it.delete()
it.mkdirs() it.mkdirs()
} }
private val Config by lazy { private val Config: ServiceConfig
GlobalJson.decodeFromString<ServiceConfig>(ConfigDir.resolve("config.json").also { get() = GlobalJson5.decodeFromString(ConfigDir.resolve("config.json").also {
if (!it.exists()) it.writeText("{}") if (!it.exists()) it.writeText("{}")
}.readText()) }.readText())
}
fun isInit(): Boolean { fun isInit(): Boolean {
val mmkv = MMKVFetcher.mmkvWithId("shamrock_config") val mmkv = MMKVFetcher.mmkvWithId("shamrock_config")
return mmkv.getBoolean("isInit", false) return mmkv.getBoolean("isInit", false)
} }
fun updateConfig(config: ServiceConfig = Config) {
ConfigDir.resolve("config.json").writeText(GlobalJson5.encodeToString(config))
}
fun updateConfig(intent: Intent) { fun updateConfig(intent: Intent) {
val mmkv = MMKVFetcher.mmkvWithId("shamrock_config") val mmkv = MMKVFetcher.mmkvWithId("shamrock_config")
mmkv.apply { mmkv.apply {
putBoolean( "tablet", intent.getBooleanExtra("tablet", false)) // 强制平板模式 putBoolean( "tablet", intent.getBooleanExtra("tablet", false)) // 强制平板模式
putInt( "port", intent.getIntExtra("port", 5700)) // 主动HTTP端口 putInt( "port", intent.getIntExtra("port", 5700)) // 主动HTTP端口
putBoolean( "ws", intent.getBooleanExtra("ws", false)) // 主动WS开关 putBoolean( "ws", intent.getBooleanExtra("ws", false)) // 主动WS开关
putInt( "ws_port", intent.getIntExtra("ws_port", 5800)) // 主动WS端口
putBoolean( "http", intent.getBooleanExtra("http", false)) // HTTP回调开关 putBoolean( "http", intent.getBooleanExtra("http", false)) // HTTP回调开关
putString( "http_addr", intent.getStringExtra("http_addr")) // WebHook回调地址 putString( "http_addr", intent.getStringExtra("http_addr")) // WebHook回调地址
putBoolean( "ws_client", intent.getBooleanExtra("ws_client", false)) // 被动WS开关 putBoolean( "ws_client", intent.getBooleanExtra("ws_client", false)) // 被动WS开关
putBoolean( "use_cqcode", intent.getBooleanExtra("use_cqcode", false)) // 使用CQ码 putBoolean( "use_cqcode", intent.getBooleanExtra("use_cqcode", false)) // 使用CQ码
putString( "ws_addr", intent.getStringExtra("ws_addr")) // 被动WS地址
putBoolean( "pro_api", intent.getBooleanExtra("pro_api", false)) // 开发调试API开关
putBoolean( "inject_packet", intent.getBooleanExtra("inject_packet", false)) // 拦截无用包 putBoolean( "inject_packet", intent.getBooleanExtra("inject_packet", false)) // 拦截无用包
putBoolean( "debug", intent.getBooleanExtra("debug", false)) // 调试模式 putBoolean( "debug", intent.getBooleanExtra("debug", false)) // 调试模式
putString( "token", intent.getStringExtra("token")) // 鉴权
// 接收ssl配置 Config.defaultToken = intent.getStringExtra("token")
val wsPort = intent.getIntExtra("ws_port", 5800)
Config.activeWebSocket = if (Config.activeWebSocket == null) ConnectionConfig(
address = "0.0.0.0",
port = wsPort,
) else Config.activeWebSocket?.also {
it.port = wsPort
}
Config.passiveWebSocket = intent.getStringExtra("ws_addr")?.split(",", "|", "")?.filter { address ->
Config.passiveWebSocket?.any {
it.address == address
} == false
}?.map {
ConnectionConfig(address = it)
}?.toMutableList()
putString( "key_store", intent.getStringExtra("key_store")) // 证书路径 putString( "key_store", intent.getStringExtra("key_store")) // 证书路径
putString( "ssl_pwd", intent.getStringExtra("ssl_pwd")) // 证书密码 putString( "ssl_pwd", intent.getStringExtra("ssl_pwd")) // 证书密码
putString( "ssl_private_pwd", intent.getStringExtra("ssl_private_pwd")) // 证书私钥密码 putString( "ssl_private_pwd", intent.getStringExtra("ssl_private_pwd")) // 证书私钥密码
@ -51,33 +69,19 @@ internal object ShamrockConfig {
putBoolean("enable_self_msg", intent.getBooleanExtra("enable_self_msg", false)) // 推送自己发的消息 putBoolean("enable_self_msg", intent.getBooleanExtra("enable_self_msg", false)) // 推送自己发的消息
putBoolean("echo_number", intent.getBooleanExtra("echo_number", false)) // 将echo格式化为数字输出
putBoolean("isInit", true) putBoolean("isInit", true)
} }
} updateConfig()
fun isEchoNumber(): Boolean {
val mmkv = MMKVFetcher.mmkvWithId("shamrock_config")
return mmkv.getBoolean("echo_number", false)
}
/**
* 忽略所有推送事件
*/
fun isIgnoreAllEvent(): Boolean {
return false
} }
fun getGroupMsgRule(): GroupRule? { fun getGroupMsgRule(): GroupRule? {
return Config.groupRule return Config.rules?.groupRule
} }
fun getPrivateRule(): PrivateRule? { fun getPrivateRule(): PrivateRule? {
return Config.privateRule return Config.rules?.privateRule
} }
fun enableSelfMsg(): Boolean { fun enableSelfMsg(): Boolean {
val mmkv = MMKVFetcher.mmkvWithId("shamrock_config") val mmkv = MMKVFetcher.mmkvWithId("shamrock_config")
return mmkv.getBoolean("enable_self_msg", false) return mmkv.getBoolean("enable_self_msg", false)
@ -88,9 +92,8 @@ internal object ShamrockConfig {
return mmkv.getBoolean("ws_client", false) return mmkv.getBoolean("ws_client", false)
} }
fun getWebSocketClientAddress(): String { fun getWebSocketClientAddress(): List<ConnectionConfig> {
val mmkv = MMKVFetcher.mmkvWithId("shamrock_config") return Config.passiveWebSocket ?: emptyList()
return mmkv.getString("ws_addr", "") ?: ""
} }
fun openWebSocket(): Boolean { fun openWebSocket(): Boolean {
@ -98,14 +101,12 @@ internal object ShamrockConfig {
return mmkv.getBoolean("ws", false) return mmkv.getBoolean("ws", false)
} }
fun getWebSocketPort(): Int { fun getActiveWebSocketConfig(): ConnectionConfig? {
val mmkv = MMKVFetcher.mmkvWithId("shamrock_config") return Config.activeWebSocket
return mmkv.getInt("ws_port", 5800)
} }
fun getToken(): String { fun getToken(): String {
val mmkv = MMKVFetcher.mmkvWithId("shamrock_config") return Config.defaultToken ?: ""
return mmkv.getString("token", "") ?: ""
} }
fun useCQ(): Boolean { fun useCQ(): Boolean {
@ -133,11 +134,6 @@ internal object ShamrockConfig {
return mmkv.getInt("port", 5700) return mmkv.getInt("port", 5700)
} }
fun isPro(): Boolean {
val mmkv = MMKVFetcher.mmkvWithId("shamrock_config")
return mmkv.getBoolean("pro_api", false)
}
fun isInjectPacket(): Boolean { fun isInjectPacket(): Boolean {
val mmkv = MMKVFetcher.mmkvWithId("shamrock_config") val mmkv = MMKVFetcher.mmkvWithId("shamrock_config")
return mmkv.getBoolean("inject_packet", false) return mmkv.getBoolean("inject_packet", false)

View File

@ -1,5 +1,6 @@
package moe.fuqiuluo.shamrock.tools package moe.fuqiuluo.shamrock.tools
import io.github.xn32.json5k.Json5
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
@ -25,6 +26,15 @@ val GlobalJson = Json {
coerceInputValues = true // 强制输入值 coerceInputValues = true // 强制输入值
} }
val GlobalJson5 = Json5 {
prettyPrint = true
indentationWidth = 2
useSingleQuotes = true
quoteMemberNames = true
encodeDefaults = true
}
val String.asJson: JsonElement val String.asJson: JsonElement
get() = Json.parseToJsonElement(this) get() = Json.parseToJsonElement(this)

View File

@ -8,7 +8,6 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import moe.fuqiuluo.shamrock.remote.service.WebSocketClientService import moe.fuqiuluo.shamrock.remote.service.WebSocketClientService
import moe.fuqiuluo.shamrock.remote.service.WebSocketService import moe.fuqiuluo.shamrock.remote.service.WebSocketService
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
import moe.fuqiuluo.shamrock.utils.PlatformUtils import moe.fuqiuluo.shamrock.utils.PlatformUtils
import moe.fuqiuluo.shamrock.helper.Level import moe.fuqiuluo.shamrock.helper.Level
@ -45,23 +44,24 @@ internal class InitRemoteService : IAction {
if (ShamrockConfig.openWebSocketClient()) { if (ShamrockConfig.openWebSocketClient()) {
val runtime = AppRuntimeFetcher.appRuntime val runtime = AppRuntimeFetcher.appRuntime
val curUin = runtime.currentAccountUin val curUin = runtime.currentAccountUin
val wsHeaders = hashMapOf( val defaultToken = ShamrockConfig.getToken()
"X-Client-Role" to "Universal", ShamrockConfig.getWebSocketClientAddress().forEach { conn ->
"X-Self-ID" to curUin, if (!conn.address.isNullOrBlank()) {
"User-Agent" to "Shamrock/$ShamrockVersion", val token = conn.token ?: defaultToken
"X-QQ-Version" to PlatformUtils.getClientVersion(MobileQQ.getContext()), val wsHeaders = hashMapOf(
"X-OneBot-Version" to "11", "X-Client-Role" to "Universal",
"X-Impl" to "Shamrock", "X-Self-ID" to curUin,
"Sec-WebSocket-Protocol" to "11.Shamrock" "User-Agent" to "Shamrock/$ShamrockVersion",
) "X-QQ-Version" to PlatformUtils.getClientVersion(MobileQQ.getContext()),
val token = ShamrockConfig.getToken() "X-OneBot-Version" to "11",
if (token.isNotBlank()) { "X-Impl" to "Shamrock",
wsHeaders["authorization"] = "bearer $token" "Sec-WebSocket-Protocol" to "11.Shamrock"
//wsHeaders["bearer"] = token )
} if (token.isNotBlank()) {
ShamrockConfig.getWebSocketClientAddress().split(",", "|", "").forEach { url -> wsHeaders["authorization"] = "bearer $token"
if (url.isNotBlank()) }
startWebSocketClient(url, wsHeaders) startWebSocketClient(conn.address, wsHeaders)
}
} }
} }
} }
@ -69,7 +69,7 @@ internal class InitRemoteService : IAction {
private fun startWebSocketServer() { private fun startWebSocketServer() {
GlobalScope.launch { GlobalScope.launch {
try { try {
val server = WebSocketService(ShamrockConfig.getWebSocketPort()) val server = WebSocketService(ShamrockConfig.getActiveWebSocketConfig()?.port ?: 5700)
server.start() server.start()
} catch (e: Throwable) { } catch (e: Throwable) {
LogCenter.log(e.stackTraceToString(), Level.ERROR) LogCenter.log(e.stackTraceToString(), Level.ERROR)