diff --git a/app/src/androidTest/java/io/legado/app/JsTest.kt b/app/src/androidTest/java/io/legado/app/AndroidJsTest.kt similarity index 81% rename from app/src/androidTest/java/io/legado/app/JsTest.kt rename to app/src/androidTest/java/io/legado/app/AndroidJsTest.kt index 9534472e6..daa8199f9 100644 --- a/app/src/androidTest/java/io/legado/app/JsTest.kt +++ b/app/src/androidTest/java/io/legado/app/AndroidJsTest.kt @@ -1,11 +1,11 @@ package io.legado.app -import io.legado.app.constant.SCRIPT_ENGINE +import io.legado.app.rhino.Rhino import org.intellij.lang.annotations.Language import org.junit.Assert import org.junit.Test -class JsTest { +class AndroidJsTest { @Test fun testPackages() { @@ -35,14 +35,26 @@ class JsTest { var queryStringWithSign = "Signature=" + signStr + "&" + query; queryStringWithSign """.trimIndent() - SCRIPT_ENGINE.eval(js) + Rhino.use { + evaluateString(initStandardObjects(), js, "yy", 1, null) + } @Language("js") val js1 = """ var returnData = new Packages.io.legado.app.api.ReturnData() returnData.getErrorMsg() """.trimIndent() - val result1 = SCRIPT_ENGINE.eval(js1) + val result1 = Rhino.use { + evaluateString(initStandardObjects(), js1, "xx", 1, null) + } Assert.assertEquals(result1, "未知错误,请联系开发者!") } + @Test + fun testReturnNull() { + val result = Rhino.use { + evaluateString(initStandardObjects(), "null", "xx", 1, null) + } + Assert.assertEquals(null, result) + } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/SharedJsScope.kt b/app/src/main/java/io/legado/app/model/SharedJsScope.kt index 98c8d720f..e7b8a7613 100644 --- a/app/src/main/java/io/legado/app/model/SharedJsScope.kt +++ b/app/src/main/java/io/legado/app/model/SharedJsScope.kt @@ -6,10 +6,10 @@ import io.legado.app.constant.SCRIPT_ENGINE import io.legado.app.exception.NoStackTraceException import io.legado.app.help.http.newCallStrResponse import io.legado.app.help.http.okHttpClient +import io.legado.app.rhino.Rhino import io.legado.app.utils.ACache import io.legado.app.utils.GSON import io.legado.app.utils.MD5Utils -import io.legado.app.utils.Rhino import io.legado.app.utils.isAbsUrl import io.legado.app.utils.isJsonObject import kotlinx.coroutines.runBlocking diff --git a/app/src/main/java/io/legado/app/rhino/Rhino.kt b/app/src/main/java/io/legado/app/rhino/Rhino.kt new file mode 100644 index 000000000..7e6eacb97 --- /dev/null +++ b/app/src/main/java/io/legado/app/rhino/Rhino.kt @@ -0,0 +1,44 @@ +package io.legado.app.rhino + +import com.script.RhinoContextFactory +import org.mozilla.javascript.Context +import org.mozilla.javascript.ContextFactory +import org.mozilla.javascript.Undefined +import org.mozilla.javascript.Wrapper + +object Rhino { + + inline fun use(block: Context.() -> Any?): Any? { + return try { + val cx = Context.enter() + val result = block.invoke(cx) + unwrapReturnValue(result) + } finally { + Context.exit() + } + } + + fun unwrapReturnValue(result: Any?): Any? { + var result1 = result + if (result1 is Wrapper) { + result1 = result1.unwrap() + } + return if (result1 is Undefined) null else result1 + } + + init { + ContextFactory.initGlobal(object : RhinoContextFactory() { + + override fun makeContext(): Context { + val cx = super.makeContext() + cx.languageVersion = 200 + cx.optimizationLevel = -1 + cx.setClassShutter(RhinoClassShutter) + //cx.wrapFactory = RhinoWrapFactory + return cx + } + + }) + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/rhino/RhinoClassShutter.kt b/app/src/main/java/io/legado/app/rhino/RhinoClassShutter.kt new file mode 100644 index 000000000..28425b030 --- /dev/null +++ b/app/src/main/java/io/legado/app/rhino/RhinoClassShutter.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package io.legado.app.rhino + +import org.mozilla.javascript.ClassShutter + +/** + * This class prevents script access to certain sensitive classes. + * Note that this class checks over and above SecurityManager. i.e., although + * a SecurityManager would pass, class shutter may still prevent access. + * + * @author A. Sundararajan + * @since 1.6 + */ +object RhinoClassShutter : ClassShutter { + + private val protectedClasses by lazy { + val protectedClasses = HashMap() + protectedClasses["java.lang.Runtime"] = java.lang.Boolean.TRUE + protectedClasses["java.io.File"] = java.lang.Boolean.TRUE + protectedClasses["java.security.AccessController"] = java.lang.Boolean.TRUE + protectedClasses + } + + override fun visibleToScripts(fullClassName: String): Boolean { + val sm = System.getSecurityManager() + if (sm != null) { + val i = fullClassName.lastIndexOf(".") + if (i != -1) { + try { + sm.checkPackageAccess(fullClassName.substring(0, i)) + } catch (e: SecurityException) { + return false + } + } + } + return protectedClasses[fullClassName] == null + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/Rhino.kt b/app/src/main/java/io/legado/app/utils/Rhino.kt deleted file mode 100644 index 83b235603..000000000 --- a/app/src/main/java/io/legado/app/utils/Rhino.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.legado.app.utils - -import org.mozilla.javascript.Context - -object Rhino { - - inline fun use(block: Context.() -> R): R { - return try { - block.invoke(Context.enter()) - } finally { - Context.exit() - } - } - -} \ No newline at end of file diff --git a/modules/rhino1.7.3/src/main/java/com/script/RhinoContextFactory.kt b/modules/rhino1.7.3/src/main/java/com/script/RhinoContextFactory.kt new file mode 100644 index 000000000..a5c8d3279 --- /dev/null +++ b/modules/rhino1.7.3/src/main/java/com/script/RhinoContextFactory.kt @@ -0,0 +1,7 @@ +package com.script + +import org.mozilla.javascript.ContextFactory + +open class RhinoContextFactory : ContextFactory() { + +} \ No newline at end of file diff --git a/modules/rhino1.7.4/src/main/java/com/script/RhinoContextFactory.kt b/modules/rhino1.7.4/src/main/java/com/script/RhinoContextFactory.kt new file mode 100644 index 000000000..809c2bb11 --- /dev/null +++ b/modules/rhino1.7.4/src/main/java/com/script/RhinoContextFactory.kt @@ -0,0 +1,15 @@ +package com.script + +import org.mozilla.javascript.Context +import org.mozilla.javascript.ContextFactory + +open class RhinoContextFactory : ContextFactory() { + + override fun hasFeature(cx: Context, featureIndex: Int): Boolean { + return when (featureIndex) { + Context.FEATURE_ENABLE_JAVA_MAP_ACCESS -> true + else -> super.hasFeature(cx, featureIndex) + } + } + +} \ No newline at end of file diff --git a/modules/rhino1.7.4/src/main/java/com/script/rhino/RhinoClassShutter.kt b/modules/rhino1.7.4/src/main/java/com/script/rhino/RhinoClassShutter.kt index 330b7d391..726963b8e 100644 --- a/modules/rhino1.7.4/src/main/java/com/script/rhino/RhinoClassShutter.kt +++ b/modules/rhino1.7.4/src/main/java/com/script/rhino/RhinoClassShutter.kt @@ -51,7 +51,7 @@ object RhinoClassShutter : ClassShutter { if (i != -1) { try { sm.checkPackageAccess(fullClassName.substring(0, i)) - } catch (var5: SecurityException) { + } catch (e: SecurityException) { return false } }