优化
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
package io.legado.app
|
package io.legado.app
|
||||||
|
|
||||||
import io.legado.app.rhino.Rhino
|
import com.script.SimpleBindings
|
||||||
import io.legado.app.rhino.putBinding
|
import com.script.rhino.RhinoScriptEngine
|
||||||
import org.intellij.lang.annotations.Language
|
import org.intellij.lang.annotations.Language
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -36,17 +36,13 @@ class AndroidJsTest {
|
|||||||
var queryStringWithSign = "Signature=" + signStr + "&" + query;
|
var queryStringWithSign = "Signature=" + signStr + "&" + query;
|
||||||
queryStringWithSign
|
queryStringWithSign
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
Rhino.use {
|
RhinoScriptEngine.eval(js)
|
||||||
evaluateString(it, js, "yy", 1, null)
|
|
||||||
}
|
|
||||||
@Language("js")
|
@Language("js")
|
||||||
val js1 = """
|
val js1 = """
|
||||||
var returnData = new Packages.io.legado.app.api.ReturnData()
|
var returnData = new Packages.io.legado.app.api.ReturnData()
|
||||||
returnData.getErrorMsg()
|
returnData.getErrorMsg()
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val result1 = Rhino.use {
|
val result1 = RhinoScriptEngine.eval(js1)
|
||||||
evaluateString(it, js1, "xx", 1, null)
|
|
||||||
}
|
|
||||||
Assert.assertEquals(result1, "未知错误,请联系开发者!").let {
|
Assert.assertEquals(result1, "未知错误,请联系开发者!").let {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -55,20 +51,15 @@ class AndroidJsTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testMap() {
|
fun testMap() {
|
||||||
val map = hashMapOf("id" to "3242532321")
|
val map = hashMapOf("id" to "3242532321")
|
||||||
|
val bindings = SimpleBindings()
|
||||||
|
bindings["result"] = map
|
||||||
@Language("js")
|
@Language("js")
|
||||||
val jsMap = "$=result;id=$.id;id"
|
val jsMap = "$=result;id=$.id;id"
|
||||||
val result = Rhino.use {
|
val result = RhinoScriptEngine.eval(jsMap, bindings)
|
||||||
it.putBinding("result", map)
|
|
||||||
evaluateString(it, jsMap, "xxx", 1, null)
|
|
||||||
}
|
|
||||||
Assert.assertEquals("3242532321", result)
|
Assert.assertEquals("3242532321", result)
|
||||||
@Language("js")
|
@Language("js")
|
||||||
val jsMap1 = """result.get("id")"""
|
val jsMap1 = """result.get("id")"""
|
||||||
val result1 = Rhino.use {
|
val result1 = RhinoScriptEngine.eval(jsMap1, bindings)
|
||||||
it.putBinding("result", map)
|
|
||||||
evaluateString(it, jsMap1, "xxx", 1, null)
|
|
||||||
}
|
|
||||||
Assert.assertEquals("3242532321", result1)
|
Assert.assertEquals("3242532321", result1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import io.legado.app.help.JsExtensions
|
|||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.help.http.CookieStore
|
import io.legado.app.help.http.CookieStore
|
||||||
import io.legado.app.model.SharedJsScope
|
import io.legado.app.model.SharedJsScope
|
||||||
import io.legado.app.rhino.Bindings
|
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import org.intellij.lang.annotations.Language
|
import org.intellij.lang.annotations.Language
|
||||||
import org.mozilla.javascript.Scriptable
|
import org.mozilla.javascript.Scriptable
|
||||||
@@ -228,22 +227,15 @@ interface BaseSource : JsExtensions {
|
|||||||
* 执行JS
|
* 执行JS
|
||||||
*/
|
*/
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun evalJS(jsStr: String, bindingsConfig: Bindings.() -> Unit = {}): Any? {
|
fun evalJS(jsStr: String, bindingsConfig: SimpleBindings.() -> Unit = {}): Any? {
|
||||||
val bindings = Bindings()
|
val bindings = SimpleBindings()
|
||||||
bindings.apply(bindingsConfig)
|
bindings.apply(bindingsConfig)
|
||||||
bindings["java"] = this
|
bindings["java"] = this
|
||||||
bindings["source"] = this
|
bindings["source"] = this
|
||||||
bindings["baseUrl"] = getKey()
|
bindings["baseUrl"] = getKey()
|
||||||
bindings["cookie"] = CookieStore
|
bindings["cookie"] = CookieStore
|
||||||
bindings["cache"] = CacheManager
|
bindings["cache"] = CacheManager
|
||||||
// return Rhino.use { scope ->
|
val context = RhinoScriptEngine.getScriptContext(bindings)
|
||||||
// scope.putBindings(bindings)
|
|
||||||
// getShareScope()?.let {
|
|
||||||
// scope.prototype = it
|
|
||||||
// }
|
|
||||||
// eval(scope, jsStr)
|
|
||||||
// }
|
|
||||||
val context = RhinoScriptEngine.getScriptContext(SimpleBindings(bindings))
|
|
||||||
val scope = RhinoScriptEngine.getRuntimeScope(context)
|
val scope = RhinoScriptEngine.getRuntimeScope(context)
|
||||||
getShareScope()?.let {
|
getShareScope()?.let {
|
||||||
scope.prototype = it
|
scope.prototype = it
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
package io.legado.app.help.book
|
package io.legado.app.help.book
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import com.script.SimpleBindings
|
||||||
|
import com.script.rhino.RhinoScriptEngine
|
||||||
import io.legado.app.constant.*
|
import io.legado.app.constant.*
|
||||||
import io.legado.app.data.appDb
|
import io.legado.app.data.appDb
|
||||||
import io.legado.app.data.entities.BaseBook
|
import io.legado.app.data.entities.BaseBook
|
||||||
@@ -10,9 +12,6 @@ import io.legado.app.data.entities.Book
|
|||||||
import io.legado.app.data.entities.BookSource
|
import io.legado.app.data.entities.BookSource
|
||||||
import io.legado.app.exception.NoStackTraceException
|
import io.legado.app.exception.NoStackTraceException
|
||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.rhino.Bindings
|
|
||||||
import io.legado.app.rhino.Rhino
|
|
||||||
import io.legado.app.rhino.putBindings
|
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -236,14 +235,11 @@ fun Book.getExportFileName(suffix: String): String {
|
|||||||
if (jsStr.isNullOrBlank()) {
|
if (jsStr.isNullOrBlank()) {
|
||||||
return "$name 作者:${getRealAuthor()}.$suffix"
|
return "$name 作者:${getRealAuthor()}.$suffix"
|
||||||
}
|
}
|
||||||
val bindings = Bindings()
|
val bindings = SimpleBindings()
|
||||||
bindings["name"] = name
|
bindings["name"] = name
|
||||||
bindings["author"] = getRealAuthor()
|
bindings["author"] = getRealAuthor()
|
||||||
return kotlin.runCatching {
|
return kotlin.runCatching {
|
||||||
Rhino.use {
|
RhinoScriptEngine.eval(jsStr, bindings).toString() + "." + suffix
|
||||||
it.putBindings(bindings)
|
|
||||||
evaluateString(it, jsStr, "name&author", 1, null)
|
|
||||||
}.toString() + "." + suffix
|
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
AppLog.put("导出书名规则错误,使用默认规则\n${it.localizedMessage}", it)
|
AppLog.put("导出书名规则错误,使用默认规则\n${it.localizedMessage}", it)
|
||||||
}.getOrDefault("${name} 作者:${getRealAuthor()}.$suffix")
|
}.getOrDefault("${name} 作者:${getRealAuthor()}.$suffix")
|
||||||
|
|||||||
@@ -109,9 +109,13 @@ object Backup {
|
|||||||
writeListToJson(appDb.httpTTSDao.all, "httpTTS.json", backupPath)
|
writeListToJson(appDb.httpTTSDao.all, "httpTTS.json", backupPath)
|
||||||
writeListToJson(appDb.keyboardAssistsDao.all, "keyboardAssists.json", backupPath)
|
writeListToJson(appDb.keyboardAssistsDao.all, "keyboardAssists.json", backupPath)
|
||||||
writeListToJson(appDb.dictRuleDao.all, "dictRule.json", backupPath)
|
writeListToJson(appDb.dictRuleDao.all, "dictRule.json", backupPath)
|
||||||
aes.encryptBase64(GSON.toJson(appDb.serverDao.all)).let {
|
GSON.toJson(appDb.serverDao.all).let { json ->
|
||||||
FileUtils.createFileIfNotExist(backupPath + File.separator + "servers.json")
|
aes.runCatching {
|
||||||
.writeText(it)
|
encryptBase64(json)
|
||||||
|
}.getOrDefault(json).let {
|
||||||
|
FileUtils.createFileIfNotExist(backupPath + File.separator + "servers.json")
|
||||||
|
.writeText(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ensureActive()
|
ensureActive()
|
||||||
GSON.toJson(ReadBookConfig.configList).let {
|
GSON.toJson(ReadBookConfig.configList).let {
|
||||||
@@ -137,7 +141,9 @@ object Backup {
|
|||||||
if (BackupConfig.keyIsNotIgnore(key)) {
|
if (BackupConfig.keyIsNotIgnore(key)) {
|
||||||
when (key) {
|
when (key) {
|
||||||
PreferKey.webDavPassword -> {
|
PreferKey.webDavPassword -> {
|
||||||
edit.putString(key, aes.encryptBase64(value.toString()))
|
edit.putString(key, aes.runCatching {
|
||||||
|
encryptBase64(value.toString())
|
||||||
|
}.getOrDefault(value.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> when (value) {
|
else -> when (value) {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package io.legado.app.model
|
package io.legado.app.model
|
||||||
|
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
|
import com.script.SimpleBindings
|
||||||
|
import com.script.rhino.RhinoScriptEngine
|
||||||
import io.legado.app.exception.NoStackTraceException
|
import io.legado.app.exception.NoStackTraceException
|
||||||
import io.legado.app.help.http.newCallStrResponse
|
import io.legado.app.help.http.newCallStrResponse
|
||||||
import io.legado.app.help.http.okHttpClient
|
import io.legado.app.help.http.okHttpClient
|
||||||
import io.legado.app.rhino.Rhino
|
|
||||||
import io.legado.app.utils.ACache
|
import io.legado.app.utils.ACache
|
||||||
import io.legado.app.utils.GSON
|
import io.legado.app.utils.GSON
|
||||||
import io.legado.app.utils.MD5Utils
|
import io.legado.app.utils.MD5Utils
|
||||||
@@ -31,39 +32,39 @@ object SharedJsScope {
|
|||||||
val key = MD5Utils.md5Encode(jsLib)
|
val key = MD5Utils.md5Encode(jsLib)
|
||||||
var scope = scopeMap[key]?.get()
|
var scope = scopeMap[key]?.get()
|
||||||
if (scope == null) {
|
if (scope == null) {
|
||||||
Rhino.use {
|
scope = RhinoScriptEngine.run {
|
||||||
scope = it
|
getRuntimeScope(getScriptContext(SimpleBindings()))
|
||||||
if (jsLib.isJsonObject()) {
|
}
|
||||||
val jsMap: Map<String, String> = GSON.fromJson(
|
if (jsLib.isJsonObject()) {
|
||||||
jsLib,
|
val jsMap: Map<String, String> = GSON.fromJson(
|
||||||
TypeToken.getParameterized(
|
jsLib,
|
||||||
Map::class.java,
|
TypeToken.getParameterized(
|
||||||
String::class.java,
|
Map::class.java,
|
||||||
String::class.java
|
String::class.java,
|
||||||
).type
|
String::class.java
|
||||||
)
|
).type
|
||||||
jsMap.values.forEach { value ->
|
)
|
||||||
if (value.isAbsUrl()) {
|
jsMap.values.forEach { value ->
|
||||||
val fileName = MD5Utils.md5Encode(value)
|
if (value.isAbsUrl()) {
|
||||||
var js = aCache.getAsString(fileName)
|
val fileName = MD5Utils.md5Encode(value)
|
||||||
if (js == null) {
|
var js = aCache.getAsString(fileName)
|
||||||
js = runBlocking {
|
if (js == null) {
|
||||||
okHttpClient.newCallStrResponse {
|
js = runBlocking {
|
||||||
url(value)
|
okHttpClient.newCallStrResponse {
|
||||||
}.body
|
url(value)
|
||||||
}
|
}.body
|
||||||
if (js !== null) {
|
}
|
||||||
aCache.put(fileName, js)
|
if (js !== null) {
|
||||||
} else {
|
aCache.put(fileName, js)
|
||||||
throw NoStackTraceException("下载jsLib-${value}失败")
|
} else {
|
||||||
}
|
throw NoStackTraceException("下载jsLib-${value}失败")
|
||||||
}
|
}
|
||||||
evaluateString(scope, js, "jsLib", 1, null)
|
|
||||||
}
|
}
|
||||||
|
RhinoScriptEngine.eval(js, scope)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
evaluateString(scope, jsLib, "jsLib", 1, null)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
RhinoScriptEngine.eval(jsLib, scope)
|
||||||
}
|
}
|
||||||
scopeMap[key] = WeakReference(scope)
|
scopeMap[key] = WeakReference(scope)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import io.legado.app.help.CacheManager
|
|||||||
import io.legado.app.help.JsExtensions
|
import io.legado.app.help.JsExtensions
|
||||||
import io.legado.app.help.http.CookieStore
|
import io.legado.app.help.http.CookieStore
|
||||||
import io.legado.app.model.webBook.WebBook
|
import io.legado.app.model.webBook.WebBook
|
||||||
import io.legado.app.rhino.Bindings
|
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withTimeout
|
import kotlinx.coroutines.withTimeout
|
||||||
@@ -698,7 +697,7 @@ class AnalyzeRule(
|
|||||||
* 执行JS
|
* 执行JS
|
||||||
*/
|
*/
|
||||||
fun evalJS(jsStr: String, result: Any? = null): Any? {
|
fun evalJS(jsStr: String, result: Any? = null): Any? {
|
||||||
val bindings = Bindings()
|
val bindings = SimpleBindings()
|
||||||
bindings["java"] = this
|
bindings["java"] = this
|
||||||
bindings["cookie"] = CookieStore
|
bindings["cookie"] = CookieStore
|
||||||
bindings["cache"] = CacheManager
|
bindings["cache"] = CacheManager
|
||||||
@@ -710,14 +709,7 @@ class AnalyzeRule(
|
|||||||
bindings["title"] = chapter?.title
|
bindings["title"] = chapter?.title
|
||||||
bindings["src"] = content
|
bindings["src"] = content
|
||||||
bindings["nextChapterUrl"] = nextChapterUrl
|
bindings["nextChapterUrl"] = nextChapterUrl
|
||||||
// return Rhino.use { scope ->
|
val context = RhinoScriptEngine.getScriptContext(bindings)
|
||||||
// scope.putBindings(bindings)
|
|
||||||
// source?.getShareScope()?.let {
|
|
||||||
// scope.prototype = it
|
|
||||||
// }
|
|
||||||
// eval(scope, jsStr)
|
|
||||||
// }
|
|
||||||
val context = RhinoScriptEngine.getScriptContext(SimpleBindings(bindings))
|
|
||||||
val scope = RhinoScriptEngine.getRuntimeScope(context)
|
val scope = RhinoScriptEngine.getRuntimeScope(context)
|
||||||
source?.getShareScope()?.let {
|
source?.getShareScope()?.let {
|
||||||
scope.prototype = it
|
scope.prototype = it
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import io.legado.app.help.JsExtensions
|
|||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.help.glide.GlideHeaders
|
import io.legado.app.help.glide.GlideHeaders
|
||||||
import io.legado.app.help.http.*
|
import io.legado.app.help.http.*
|
||||||
import io.legado.app.rhino.Bindings
|
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
@@ -255,7 +254,7 @@ class AnalyzeUrl(
|
|||||||
* 执行JS
|
* 执行JS
|
||||||
*/
|
*/
|
||||||
fun evalJS(jsStr: String, result: Any? = null): Any? {
|
fun evalJS(jsStr: String, result: Any? = null): Any? {
|
||||||
val bindings = Bindings()
|
val bindings = SimpleBindings()
|
||||||
bindings["java"] = this
|
bindings["java"] = this
|
||||||
bindings["baseUrl"] = baseUrl
|
bindings["baseUrl"] = baseUrl
|
||||||
bindings["cookie"] = CookieStore
|
bindings["cookie"] = CookieStore
|
||||||
@@ -267,14 +266,7 @@ class AnalyzeUrl(
|
|||||||
bindings["book"] = ruleData as? Book
|
bindings["book"] = ruleData as? Book
|
||||||
bindings["source"] = source
|
bindings["source"] = source
|
||||||
bindings["result"] = result
|
bindings["result"] = result
|
||||||
// return Rhino.use { scope ->
|
val context = RhinoScriptEngine.getScriptContext(bindings)
|
||||||
// scope.putBindings(bindings)
|
|
||||||
// source?.getShareScope()?.let {
|
|
||||||
// scope.prototype = it
|
|
||||||
// }
|
|
||||||
// eval(scope, jsStr)
|
|
||||||
// }
|
|
||||||
val context = RhinoScriptEngine.getScriptContext(SimpleBindings(bindings))
|
|
||||||
val scope = RhinoScriptEngine.getRuntimeScope(context)
|
val scope = RhinoScriptEngine.getRuntimeScope(context)
|
||||||
source?.getShareScope()?.let {
|
source?.getShareScope()?.let {
|
||||||
scope.prototype = it
|
scope.prototype = it
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package io.legado.app.model.localBook
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
|
import com.script.SimpleBindings
|
||||||
|
import com.script.rhino.RhinoScriptEngine
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.constant.*
|
import io.legado.app.constant.*
|
||||||
import io.legado.app.data.appDb
|
import io.legado.app.data.appDb
|
||||||
@@ -19,9 +21,6 @@ import io.legado.app.help.config.AppConfig
|
|||||||
import io.legado.app.lib.webdav.WebDav
|
import io.legado.app.lib.webdav.WebDav
|
||||||
import io.legado.app.lib.webdav.WebDavException
|
import io.legado.app.lib.webdav.WebDavException
|
||||||
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
||||||
import io.legado.app.rhino.Rhino
|
|
||||||
import io.legado.app.rhino.eval
|
|
||||||
import io.legado.app.rhino.putBinding
|
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.jsoup.nodes.Entities
|
import org.jsoup.nodes.Entities
|
||||||
@@ -271,9 +270,10 @@ object LocalBook {
|
|||||||
val js =
|
val js =
|
||||||
AppConfig.bookImportFileName + "\nJSON.stringify({author:author,name:name})"
|
AppConfig.bookImportFileName + "\nJSON.stringify({author:author,name:name})"
|
||||||
//在脚本中定义如何分解文件名成书名、作者名
|
//在脚本中定义如何分解文件名成书名、作者名
|
||||||
val jsonStr = Rhino.use {
|
val jsonStr = RhinoScriptEngine.run {
|
||||||
it.putBinding("src", tempFileName)
|
val bindings = SimpleBindings()
|
||||||
eval(it, js)
|
bindings["src"] = tempFileName
|
||||||
|
eval(js, bindings)
|
||||||
}.toString()
|
}.toString()
|
||||||
val bookMess = GSON.fromJsonObject<HashMap<String, String>>(jsonStr)
|
val bookMess = GSON.fromJsonObject<HashMap<String, String>>(jsonStr)
|
||||||
.getOrThrow()
|
.getOrThrow()
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* Decompiled with CFR 0.152.
|
|
||||||
*/
|
|
||||||
package io.legado.app.rhino
|
|
||||||
|
|
||||||
class Bindings @JvmOverloads constructor(
|
|
||||||
private val map: MutableMap<String, Any?> = HashMap()
|
|
||||||
) : MutableMap<String, Any?> {
|
|
||||||
|
|
||||||
override fun put(key: String, value: Any?): Any? {
|
|
||||||
return map.put(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun putAll(from: Map<out String, Any?>) {
|
|
||||||
map.putAll(from)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun clear() {
|
|
||||||
map.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun containsKey(key: String): Boolean {
|
|
||||||
return map.containsKey(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun containsValue(value: Any?): Boolean {
|
|
||||||
return map.containsValue(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val entries: MutableSet<MutableMap.MutableEntry<String, Any?>>
|
|
||||||
get() = map.entries
|
|
||||||
|
|
||||||
override operator fun get(key: String): Any? {
|
|
||||||
return map[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isEmpty(): Boolean {
|
|
||||||
return map.isEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
override val keys: MutableSet<String>
|
|
||||||
get() = map.keys
|
|
||||||
|
|
||||||
override fun remove(key: String): Any? {
|
|
||||||
return map.remove(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val size: Int
|
|
||||||
get() = map.size
|
|
||||||
|
|
||||||
override val values: MutableCollection<Any?>
|
|
||||||
get() = map.values
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package io.legado.app.rhino
|
|
||||||
|
|
||||||
import org.mozilla.javascript.Context
|
|
||||||
import org.mozilla.javascript.ImporterTopLevel
|
|
||||||
import org.mozilla.javascript.Scriptable
|
|
||||||
import org.mozilla.javascript.Undefined
|
|
||||||
import org.mozilla.javascript.Wrapper
|
|
||||||
|
|
||||||
object Rhino {
|
|
||||||
|
|
||||||
inline fun <T> use(block: Context.(Scriptable) -> T): T {
|
|
||||||
return try {
|
|
||||||
val cx = Context.enter()
|
|
||||||
val scope = cx.initStandardObjects(ImporterTopLevel(cx))
|
|
||||||
block.invoke(cx, scope)
|
|
||||||
} 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)
|
|
||||||
// return cx
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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<Any, Any>()
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
package io.legado.app.rhino
|
package io.legado.app.rhino
|
||||||
|
|
||||||
|
import com.script.Bindings
|
||||||
import org.mozilla.javascript.Context
|
import org.mozilla.javascript.Context
|
||||||
import org.mozilla.javascript.Scriptable
|
import org.mozilla.javascript.Scriptable
|
||||||
import org.mozilla.javascript.ScriptableObject
|
import org.mozilla.javascript.ScriptableObject
|
||||||
@@ -14,9 +15,7 @@ fun Context.eval(
|
|||||||
lineno: Int = 1,
|
lineno: Int = 1,
|
||||||
securityDomain: Any? = null
|
securityDomain: Any? = null
|
||||||
): Any? {
|
): Any? {
|
||||||
return Rhino.unwrapReturnValue(
|
return evaluateString(scope, source, sourceName, lineno, securityDomain)
|
||||||
evaluateString(scope, source, sourceName, lineno, securityDomain)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.eval(
|
fun Context.eval(
|
||||||
@@ -26,9 +25,7 @@ fun Context.eval(
|
|||||||
lineno: Int = 1,
|
lineno: Int = 1,
|
||||||
securityDomain: Any? = null
|
securityDomain: Any? = null
|
||||||
): Any? {
|
): Any? {
|
||||||
return Rhino.unwrapReturnValue(
|
return evaluateReader(scope, reader, sourceName, lineno, securityDomain)
|
||||||
evaluateReader(scope, reader, sourceName, lineno, securityDomain)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Scriptable.putBinding(key: String, value: Any?) {
|
fun Scriptable.putBinding(key: String, value: Any?) {
|
||||||
|
|||||||
@@ -1,25 +1,20 @@
|
|||||||
package io.legado.app.utils
|
package io.legado.app.utils
|
||||||
|
|
||||||
|
import com.script.SimpleBindings
|
||||||
|
import com.script.rhino.RhinoScriptEngine
|
||||||
import io.legado.app.constant.AppPattern.EXP_PATTERN
|
import io.legado.app.constant.AppPattern.EXP_PATTERN
|
||||||
import io.legado.app.rhino.Bindings
|
|
||||||
import io.legado.app.rhino.Rhino
|
|
||||||
import io.legado.app.rhino.eval
|
|
||||||
import io.legado.app.rhino.putBindings
|
|
||||||
|
|
||||||
object JsUtils {
|
object JsUtils {
|
||||||
|
|
||||||
fun evalJs(js: String, bindingsFun: ((Bindings) -> Unit)? = null): String {
|
fun evalJs(js: String, bindingsFun: ((SimpleBindings) -> Unit)? = null): String {
|
||||||
val bindings = Bindings()
|
val bindings = SimpleBindings()
|
||||||
bindingsFun?.invoke(bindings)
|
bindingsFun?.invoke(bindings)
|
||||||
if (js.contains("{{") && js.contains("}}")) {
|
if (js.contains("{{") && js.contains("}}")) {
|
||||||
val sb = StringBuffer()
|
val sb = StringBuffer()
|
||||||
val expMatcher = EXP_PATTERN.matcher(js)
|
val expMatcher = EXP_PATTERN.matcher(js)
|
||||||
while (expMatcher.find()) {
|
while (expMatcher.find()) {
|
||||||
val result = expMatcher.group(1)?.let { js1 ->
|
val result = expMatcher.group(1)?.let { js1 ->
|
||||||
Rhino.use {
|
RhinoScriptEngine.eval(js1, bindings)
|
||||||
it.putBindings(bindings)
|
|
||||||
eval(it, js1)
|
|
||||||
}
|
|
||||||
} ?: ""
|
} ?: ""
|
||||||
if (result is String) {
|
if (result is String) {
|
||||||
expMatcher.appendReplacement(sb, result)
|
expMatcher.appendReplacement(sb, result)
|
||||||
@@ -32,10 +27,7 @@ object JsUtils {
|
|||||||
expMatcher.appendTail(sb)
|
expMatcher.appendTail(sb)
|
||||||
return sb.toString()
|
return sb.toString()
|
||||||
}
|
}
|
||||||
return Rhino.use {
|
return RhinoScriptEngine.eval(js, bindings).toString()
|
||||||
it.putBindings(bindings)
|
|
||||||
eval(it, js)
|
|
||||||
}.toString()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
package io.legado.app.utils
|
package io.legado.app.utils
|
||||||
|
|
||||||
import androidx.core.os.postDelayed
|
import androidx.core.os.postDelayed
|
||||||
|
import com.script.SimpleBindings
|
||||||
|
import com.script.rhino.RhinoScriptEngine
|
||||||
import io.legado.app.exception.RegexTimeoutException
|
import io.legado.app.exception.RegexTimeoutException
|
||||||
import io.legado.app.help.CrashHandler
|
import io.legado.app.help.CrashHandler
|
||||||
import io.legado.app.help.coroutine.Coroutine
|
import io.legado.app.help.coroutine.Coroutine
|
||||||
import io.legado.app.rhino.Rhino
|
|
||||||
import io.legado.app.rhino.eval
|
|
||||||
import io.legado.app.rhino.putBinding
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
@@ -31,9 +30,10 @@ fun CharSequence.replace(regex: Regex, replacement: String, timeout: Long): Stri
|
|||||||
val stringBuffer = StringBuffer()
|
val stringBuffer = StringBuffer()
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
if (isJs) {
|
if (isJs) {
|
||||||
val jsResult = Rhino.use {
|
val jsResult = RhinoScriptEngine.run {
|
||||||
it.putBinding("result", matcher.group())
|
val bindings = SimpleBindings()
|
||||||
eval(it, replacement1)
|
bindings["result"] = matcher.group()
|
||||||
|
eval(replacement1, bindings)
|
||||||
}.toString()
|
}.toString()
|
||||||
matcher.appendReplacement(stringBuffer, jsResult)
|
matcher.appendReplacement(stringBuffer, jsResult)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package io.legado.app
|
package io.legado.app
|
||||||
|
|
||||||
import com.script.SimpleBindings
|
import com.script.SimpleBindings
|
||||||
|
import com.script.rhino.RhinoScriptEngine
|
||||||
import io.legado.app.data.entities.BookChapter
|
import io.legado.app.data.entities.BookChapter
|
||||||
import io.legado.app.rhino.Rhino
|
|
||||||
import io.legado.app.rhino.eval
|
|
||||||
import io.legado.app.rhino.putBinding
|
|
||||||
import org.intellij.lang.annotations.Language
|
import org.intellij.lang.annotations.Language
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -30,29 +28,24 @@ class JsTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testMap() {
|
fun testMap() {
|
||||||
val map = hashMapOf("id" to "3242532321")
|
val map = hashMapOf("id" to "3242532321")
|
||||||
|
val bindings = SimpleBindings()
|
||||||
|
bindings["result"] = map
|
||||||
@Language("js")
|
@Language("js")
|
||||||
val jsMap = "$=result;id=$.id;id"
|
val jsMap = "$=result;id=$.id;id"
|
||||||
val result = Rhino.use {
|
val result = RhinoScriptEngine.eval(jsMap, bindings)
|
||||||
val scope = initStandardObjects()
|
|
||||||
scope.putBinding("result", map)
|
|
||||||
evaluateString(scope, jsMap, "xxx", 1, null)
|
|
||||||
}
|
|
||||||
Assert.assertEquals("3242532321", result)
|
Assert.assertEquals("3242532321", result)
|
||||||
@Language("js")
|
@Language("js")
|
||||||
val jsMap1 = """result.get("id")"""
|
val jsMap1 = """result.get("id")"""
|
||||||
val result1 = Rhino.use {
|
val result1 = RhinoScriptEngine.eval(jsMap1, bindings)
|
||||||
it.putBinding("result", map)
|
|
||||||
evaluateString(it, jsMap1, "xxx", 1, null)
|
|
||||||
}
|
|
||||||
Assert.assertEquals("3242532321", result1)
|
Assert.assertEquals("3242532321", result1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testFor() {
|
fun testFor() {
|
||||||
val scope = Rhino.use {
|
val scope = RhinoScriptEngine.run {
|
||||||
evaluateString(it, printJs, "print", 1, null)
|
val scope = getRuntimeScope(getScriptContext(SimpleBindings()))
|
||||||
it
|
eval(printJs, scope)
|
||||||
|
scope
|
||||||
}
|
}
|
||||||
|
|
||||||
@Language("js")
|
@Language("js")
|
||||||
@@ -74,18 +67,13 @@ class JsTest {
|
|||||||
}
|
}
|
||||||
result
|
result
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val result = Rhino.use {
|
val result = RhinoScriptEngine.eval(jsFor, scope)
|
||||||
it.prototype = scope
|
|
||||||
evaluateString(it, jsFor, "jsFor", 1, null)
|
|
||||||
}
|
|
||||||
Assert.assertEquals("12012", result)
|
Assert.assertEquals("12012", result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testReturnNull() {
|
fun testReturnNull() {
|
||||||
val result = Rhino.use {
|
val result = RhinoScriptEngine.eval("null")
|
||||||
eval(it, "null")
|
|
||||||
}
|
|
||||||
Assert.assertEquals(null, result)
|
Assert.assertEquals(null, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,9 +89,10 @@ class JsTest {
|
|||||||
.replace(/\;/g,";")
|
.replace(/\;/g,";")
|
||||||
.replace(/\:/g,":")
|
.replace(/\:/g,":")
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val result = Rhino.use {
|
val result = RhinoScriptEngine.run {
|
||||||
it.putBinding("result", ",.!?…;:")
|
val bindings = SimpleBindings()
|
||||||
eval(it, js)
|
bindings["result"] = ",.!?…;:"
|
||||||
|
eval(js)
|
||||||
}
|
}
|
||||||
Assert.assertEquals(result, ",。!?……;:")
|
Assert.assertEquals(result, ",。!?……;:")
|
||||||
}
|
}
|
||||||
@@ -116,27 +105,22 @@ class JsTest {
|
|||||||
bindings["chapter"] = chapter
|
bindings["chapter"] = chapter
|
||||||
@Language("js")
|
@Language("js")
|
||||||
val js = "chapter.title"
|
val js = "chapter.title"
|
||||||
val result = Rhino.use {
|
val result = RhinoScriptEngine.eval(js, bindings)
|
||||||
it.putBinding("chapter", chapter)
|
|
||||||
eval(it, js)
|
|
||||||
}
|
|
||||||
Assert.assertEquals(result, "xxxyyy")
|
Assert.assertEquals(result, "xxxyyy")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun javaListForEach() {
|
fun javaListForEach() {
|
||||||
val list = arrayListOf(1, 2, 3)
|
val list = arrayListOf(1, 2, 3)
|
||||||
|
val bindings = SimpleBindings()
|
||||||
|
bindings["list"] = list
|
||||||
@Language("js")
|
@Language("js")
|
||||||
val js = """
|
val js = """
|
||||||
var result = 0
|
var result = 0
|
||||||
list.forEach(item => {result = result + item})
|
list.forEach(item => {result = result + item})
|
||||||
result
|
result
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val result = Rhino.use {
|
val result = RhinoScriptEngine.eval(js, bindings)
|
||||||
it.putBinding("list", list)
|
|
||||||
eval(it, js)
|
|
||||||
}
|
|
||||||
Assert.assertEquals(result, 6.0)
|
Assert.assertEquals(result, 6.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user