diff --git a/app/src/main/java/moe/fuqiuluo/shamrock/ui/app/ShamrockConfig.kt b/app/src/main/java/moe/fuqiuluo/shamrock/ui/app/ShamrockConfig.kt index 66e4c63..1f9f772 100644 --- a/app/src/main/java/moe/fuqiuluo/shamrock/ui/app/ShamrockConfig.kt +++ b/app/src/main/java/moe/fuqiuluo/shamrock/ui/app/ShamrockConfig.kt @@ -239,11 +239,21 @@ object ShamrockConfig { return preferences.getBoolean("enable_auto_start", false) } + fun allowShell(ctx: Context): Boolean { + val preferences = ctx.getSharedPreferences("config", 0) + return preferences.getBoolean("shell", false) + } + fun setAutoStart(ctx: Context, v: Boolean) { val preferences = ctx.getSharedPreferences("config", 0) preferences.edit().putBoolean("enable_auto_start", v).apply() } + fun setShellStatus(ctx: Context, v: Boolean) { + val preferences = ctx.getSharedPreferences("config", 0) + preferences.edit().putBoolean("shell", v).apply() + } + fun enableSelfMsg(ctx: Context): Boolean { val preferences = ctx.getSharedPreferences("config", 0) return preferences.getBoolean("enable_self_msg", false) @@ -288,6 +298,7 @@ object ShamrockConfig { "key_store" to preferences.getString("key_store", ""), "enable_self_msg" to preferences.getBoolean("enable_self_msg", false), "echo_number" to preferences.getBoolean("echo_number", false), + "shell" to preferences.getBoolean("shell", false), ) } diff --git a/app/src/main/java/moe/fuqiuluo/shamrock/ui/fragment/LabFragment.kt b/app/src/main/java/moe/fuqiuluo/shamrock/ui/fragment/LabFragment.kt index cb47a92..14fd899 100644 --- a/app/src/main/java/moe/fuqiuluo/shamrock/ui/fragment/LabFragment.kt +++ b/app/src/main/java/moe/fuqiuluo/shamrock/ui/fragment/LabFragment.kt @@ -100,7 +100,7 @@ fun LabFragment() { Function( title = "自动清理QQ垃圾", - desc = "也许会导致奇怪的问题。", + desc = "也许会导致奇怪的问题(无效)。", descColor = it, isSwitch = ShamrockConfig.isAutoClean(ctx) ) { @@ -129,6 +129,16 @@ fun LabFragment() { ShamrockConfig.setAutoStart(ctx, it) return@Function true } + + Function( + title = "开启Shell接口", + desc = "可能导致设备被入侵,请勿随意开启。", + descColor = it, + isSwitch = ShamrockConfig.allowShell(ctx) + ) { + ShamrockConfig.setShellStatus(ctx, it) + return@Function true + } } } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/OtherAction.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/OtherAction.kt index 09c1d2e..972b94d 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/OtherAction.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/OtherAction.kt @@ -8,6 +8,11 @@ import io.ktor.server.request.receiveMultipart import io.ktor.server.response.respondText import io.ktor.server.routing.Routing import io.ktor.server.routing.post +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.coroutines.withTimeout +import kotlinx.coroutines.withTimeoutOrNull +import kotlinx.serialization.json.JsonObject import moe.fuqiuluo.shamrock.remote.action.handlers.CleanCache import moe.fuqiuluo.shamrock.remote.action.handlers.DownloadFile import moe.fuqiuluo.shamrock.remote.action.handlers.GetDeviceBattery @@ -15,15 +20,58 @@ import moe.fuqiuluo.shamrock.remote.action.handlers.GetVersionInfo import moe.fuqiuluo.shamrock.remote.action.handlers.RestartMe import moe.fuqiuluo.shamrock.remote.entries.Status import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig +import moe.fuqiuluo.shamrock.tools.asString import moe.fuqiuluo.shamrock.tools.fetchOrNull import moe.fuqiuluo.shamrock.tools.fetchOrThrow +import moe.fuqiuluo.shamrock.tools.fetchPostJsonArray import moe.fuqiuluo.shamrock.tools.getOrPost +import moe.fuqiuluo.shamrock.tools.isJsonArray import moe.fuqiuluo.shamrock.tools.respond import moe.fuqiuluo.shamrock.utils.FileUtils import moe.fuqiuluo.shamrock.utils.MD5 +import java.io.File +import java.util.concurrent.TimeUnit fun Routing.otherAction() { + if (ShamrockConfig.allowShell()) { + getOrPost("/shell") { + val runtime = Runtime.getRuntime() + val dir = fetchOrThrow("dir") + val out = StringBuilder() + withTimeoutOrNull(5000L) { + if (isJsonArray("cmd")) { + val cmd = fetchPostJsonArray("cmd").map { + if (it is JsonObject) it.toString() else it.asString + }.toTypedArray() + withContext(Dispatchers.IO) { + runtime.exec(cmd, null, File(dir)).apply { waitFor() } + } + } else { + val cmd = fetchOrThrow("cmd") + withContext(Dispatchers.IO) { + runtime.exec(cmd, null, File(dir)).apply { waitFor() } + } + } + }.also { + if (it == null) { + respond(false, Status.IAmTired, "执行超时") + } else { + it.inputStream.use { + out.append("stdout:\n") + out.append(it.readBytes().toString(Charsets.UTF_8)) + } + it.errorStream.use { + out.append("\nstderr:\n") + out.append(it.readBytes().toString(Charsets.UTF_8)) + } + } + } + + call.respondText(out.toString()) + } + } + getOrPost("/get_version_info") { call.respondText(GetVersionInfo()) } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/config/ShamrockConfig.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/config/ShamrockConfig.kt index c557046..78dd0bd 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/config/ShamrockConfig.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/config/ShamrockConfig.kt @@ -67,6 +67,7 @@ internal object ShamrockConfig { putBoolean("auto_clear", intent.getBooleanExtra("auto_clear", false)) // 自动清理 putBoolean("enable_self_msg", intent.getBooleanExtra("enable_self_msg", false)) // 推送自己发的消息 + putBoolean("shell", intent.getBooleanExtra("shell", false)) // 开启Shell接口 putBoolean("isInit", true) } @@ -212,4 +213,9 @@ internal object ShamrockConfig { fun isAntiTrace(): Boolean { return Config.antiTrace } + + fun allowShell(): Boolean { + val mmkv = MMKVFetcher.mmkvWithId("shamrock_config") + return mmkv.getBoolean("shell", false) + } } \ No newline at end of file