Skip to content

Instantly share code, notes, and snippets.

@Mahoney
Created December 17, 2020 09:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Mahoney/8979e520b7477c9a9771fe3e1da3472a to your computer and use it in GitHub Desktop.
Save Mahoney/8979e520b7477c9a9771fe3e1da3472a to your computer and use it in GitHub Desktop.
/*
NOTE - you need a file
META-INF/services/javax.script.ScriptEngineFactory
with contents
org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory
And the following dependencies on the classpath:
runtimeOnly(kotlin("script-runtime"))
runtimeOnly(kotlin("script-util"))
runtimeOnly(kotlin("compiler-embeddable"))
runtimeOnly(kotlin("scripting-compiler-embeddable"))
runtimeOnly("net.java.dev.jna:jna:4.2.2")
*/
package uk.org.lidalia.kotlingradlelibrary
import java.io.FilePermission
import java.io.Reader
import java.lang.reflect.ReflectPermission
import java.security.Permission
import java.util.*
import javax.script.ScriptEngine
import javax.script.ScriptEngineManager
class KtsObjectLoader(
classLoader: ClassLoader? = Thread.currentThread().contextClassLoader
) {
val engine: ScriptEngine = loadEngine(classLoader)
private fun loadEngine(classLoader: ClassLoader?): ScriptEngine {
val engineByExtension = ScriptEngineManager(classLoader).getEngineByExtension("kts")
// warm up with the simplest script possible, needing no security
engineByExtension.eval("true")
return engineByExtension
}
inline fun <reified T> load(reader: Reader): T {
val text = reader.readText()
return KtScriptSafeSecurityManager.with {
engine.eval(text) as T
}
}
}
class KtScriptSafeSecurityManager private constructor() : SecurityManager() {
@Volatile
private var secure = true
override fun checkPermission(perm: Permission) {
if (permitted.none { this.it(perm) }) {
throw SecurityException("Forbidden: $perm")
}
}
companion object {
private val permitted: Set<KtScriptSafeSecurityManager.(Permission) -> Boolean> = setOf(
{ it is FilePermission && it.actions == "read" },
{ it is PropertyPermission && it.actions == "read" },
{ !secure && it is RuntimePermission && it.name == "setSecurityManager" },
{ it is RuntimePermission && it.name == "createClassLoader" },
{ it is RuntimePermission && it.name == "setContextClassLoader" },
{ it is RuntimePermission && it.name == "accessDeclaredMembers" },
{ it is ReflectPermission && it.name == "suppressAccessChecks" },
)
fun <T> with(task: () -> T): T {
val initialManager = System.getSecurityManager()
val ktScriptSafeSecurityManager = KtScriptSafeSecurityManager()
System.setSecurityManager(ktScriptSafeSecurityManager)
return try {
task()
} finally {
ktScriptSafeSecurityManager.secure = false
System.setSecurityManager(initialManager)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment