diff --git a/addOns/kotlin/CHANGELOG.md b/addOns/kotlin/CHANGELOG.md new file mode 100644 index 00000000000..27e2f3386dc --- /dev/null +++ b/addOns/kotlin/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog +All notable changes to this add-on will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## Alpha + +- Kotlin scripting for the JVM \ No newline at end of file diff --git a/addOns/kotlin/kotlin.gradle.kts b/addOns/kotlin/kotlin.gradle.kts new file mode 100644 index 00000000000..0ec92e6a741 --- /dev/null +++ b/addOns/kotlin/kotlin.gradle.kts @@ -0,0 +1,27 @@ +import org.zaproxy.gradle.addon.AddOnStatus + +plugins { + kotlin("jvm") version "1.3.50" +} + +version = "1" +description = "Allows Kotlin to be used for ZAP scripting - templates included" + +zapAddOn { + addOnName.set("Kotlin Scripting") + addOnStatus.set(AddOnStatus.ALPHA) + zapVersion.set("2.9.0") + + manifest { + author.set("StackHawk Engineering") + } +} + +dependencies { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + implementation("org.jetbrains.kotlin:kotlin-compiler-embeddable") + implementation("org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable") + implementation("org.jetbrains.kotlin:kotlin-script-util") + + testImplementation(project(":testutils")) +} diff --git a/addOns/kotlin/src/main/kotlin/org/zaproxy/zap/extension/kotlin/ExtensionKotlin.kt b/addOns/kotlin/src/main/kotlin/org/zaproxy/zap/extension/kotlin/ExtensionKotlin.kt new file mode 100644 index 00000000000..5b00f505614 --- /dev/null +++ b/addOns/kotlin/src/main/kotlin/org/zaproxy/zap/extension/kotlin/ExtensionKotlin.kt @@ -0,0 +1,76 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2020 The ZAP Development Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.zaproxy.zap.extension.kotlin + +import org.apache.log4j.Logger +import org.parosproxy.paros.control.Control +import org.parosproxy.paros.extension.Extension +import org.parosproxy.paros.extension.ExtensionAdaptor +import org.parosproxy.paros.extension.ExtensionHook +import org.parosproxy.paros.view.View +import org.zaproxy.zap.ZAP +import org.zaproxy.zap.control.ExtensionFactory +import org.zaproxy.zap.extension.script.ExtensionScript +import javax.swing.ImageIcon + +class ExtensionKotlin : ExtensionAdaptor(NAME) { + + + companion object { + val NAME = "ExtensionKotlin" + val TEAM_NAME = "StackHawk Engineering" + val KOTLIN_ICON: ImageIcon? = if (View.isInitialised()) ImageIcon( + ExtensionKotlin::class.java.getResource( + "/org/zaproxy/zap/extension/kotlin/resources/kotlin.png")) else null + + val EXTENSION_DEPENDENCIES: List> = listOf(ExtensionScript::class.java) + private val LOGGER: Logger = Logger.getLogger(ExtensionKotlin::class.java) + } + + init { + order = 9999 + + } + + override fun hook(extensionHook: ExtensionHook?) { + super.hook(extensionHook) + + LOGGER.info("Hooking Kotlin Scripting Extension") + + val zapJar = ZAP::class.java.protectionDomain.codeSource.location.file + + LOGGER.info("Loading Kotlin engine...") + val cl = ExtensionFactory.getAddOnLoader() + cl.urLs.forEach { LOGGER.info(it) } + extScript + .registerScriptEngineWrapper( + KotlinEngineWrapper(KotlinScriptEngineFactory(cl, zapJar.toString()))) + LOGGER.info("Kotlin engine loaded.") + + } + + private val extScript: ExtensionScript by lazy { + Control.getSingleton() + .extensionLoader + .getExtension(ExtensionScript.NAME) as ExtensionScript + } + +} \ No newline at end of file diff --git a/addOns/kotlin/src/main/kotlin/org/zaproxy/zap/extension/kotlin/KotlinEngineWrapper.kt b/addOns/kotlin/src/main/kotlin/org/zaproxy/zap/extension/kotlin/KotlinEngineWrapper.kt new file mode 100644 index 00000000000..d1128e7eed9 --- /dev/null +++ b/addOns/kotlin/src/main/kotlin/org/zaproxy/zap/extension/kotlin/KotlinEngineWrapper.kt @@ -0,0 +1,64 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2020 The ZAP Development Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.zaproxy.zap.extension.kotlin + +import org.fife.ui.rsyntaxtextarea.SyntaxConstants +import org.parosproxy.paros.Constant +import org.parosproxy.paros.extension.Extension +import org.zaproxy.zap.extension.script.DefaultEngineWrapper +import javax.script.ScriptEngine +import javax.script.ScriptEngineFactory +import javax.swing.ImageIcon + +class KotlinEngineWrapper(scriptEngineFactory: ScriptEngineFactory): DefaultEngineWrapper(scriptEngineFactory) { + + override fun getExtensions(): MutableList { + return mutableListOf("kts") + } + + override fun getIcon(): ImageIcon? { + return ExtensionKotlin.KOTLIN_ICON + } + + override fun getEngine(): ScriptEngine { + return super.getEngine() + } + + override fun getSyntaxStyle(): String { + return SyntaxConstants.SYNTAX_STYLE_NONE + } + + fun getAuthor(): String { + return ExtensionKotlin.TEAM_NAME + } + + fun getDescription(): String { + return Constant.messages.getString("kotlin.desc") + } + + fun getDependencies(): List> { + return ExtensionKotlin.EXTENSION_DEPENDENCIES + } + + override fun isRawEngine(): Boolean { + return false + } +} \ No newline at end of file diff --git a/addOns/kotlin/src/main/kotlin/org/zaproxy/zap/extension/kotlin/KotlinScriptEngineFactory.kt b/addOns/kotlin/src/main/kotlin/org/zaproxy/zap/extension/kotlin/KotlinScriptEngineFactory.kt new file mode 100644 index 00000000000..e5ee130d713 --- /dev/null +++ b/addOns/kotlin/src/main/kotlin/org/zaproxy/zap/extension/kotlin/KotlinScriptEngineFactory.kt @@ -0,0 +1,55 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2020 The ZAP Development Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.zaproxy.zap.extension.kotlin + +import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineFactoryBase +import org.jetbrains.kotlin.cli.common.repl.ScriptArgsWithTypes +import org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngine +import org.jetbrains.kotlin.script.jsr223.KotlinStandardJsr223ScriptTemplate +import java.io.File +import javax.script.Bindings +import javax.script.ScriptContext +import javax.script.ScriptEngine +import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContextOrStdlib + +class KotlinScriptEngineFactory(private val classLoader: ClassLoader, + private val zapJar: String? = null) : KotlinJsr223JvmScriptEngineFactoryBase() { + override fun getScriptEngine(): ScriptEngine { + val clJars = scriptCompilationClasspathFromContextOrStdlib("kotlin-stdlib", + wholeClasspath = true, + classLoader = classLoader) + val jars = if (zapJar != null) { + clJars + File(zapJar) + } else { + clJars + } + return KotlinJsr223JvmLocalScriptEngine( + this, + jars, + KotlinStandardJsr223ScriptTemplate::class.qualifiedName!!, + { ctx, types -> + ScriptArgsWithTypes(arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)), types ?: emptyArray()) + }, + arrayOf(Bindings::class) + ) + } + +} \ No newline at end of file diff --git a/addOns/kotlin/src/main/resources/org/zaproxy/zap/extension/kotlin/resources/Messages.properties b/addOns/kotlin/src/main/resources/org/zaproxy/zap/extension/kotlin/resources/Messages.properties new file mode 100644 index 00000000000..bc4aa83d580 --- /dev/null +++ b/addOns/kotlin/src/main/resources/org/zaproxy/zap/extension/kotlin/resources/Messages.properties @@ -0,0 +1,3 @@ + +kotlin.desc = Allows Kotlin to be used for ZAP scripting +kotlin.options.title = Kotlin diff --git a/addOns/kotlin/src/main/resources/org/zaproxy/zap/extension/kotlin/resources/kotlin.png b/addOns/kotlin/src/main/resources/org/zaproxy/zap/extension/kotlin/resources/kotlin.png new file mode 100644 index 00000000000..ad3db01f817 Binary files /dev/null and b/addOns/kotlin/src/main/resources/org/zaproxy/zap/extension/kotlin/resources/kotlin.png differ diff --git a/addOns/kotlin/src/main/zapHomeFiles/scripts/templates/authentication/Authentication default template.kts b/addOns/kotlin/src/main/zapHomeFiles/scripts/templates/authentication/Authentication default template.kts new file mode 100644 index 00000000000..06683ab8fd0 --- /dev/null +++ b/addOns/kotlin/src/main/zapHomeFiles/scripts/templates/authentication/Authentication default template.kts @@ -0,0 +1,46 @@ + +import org.apache.commons.httpclient.URI +import org.parosproxy.paros.network.HttpHeader +import org.parosproxy.paros.network.HttpMessage +import org.parosproxy.paros.network.HttpRequestHeader +import org.zaproxy.zap.authentication.AuthenticationHelper +import org.zaproxy.zap.authentication.GenericAuthenticationCredentials + +val PARAM_TARGET_URL = "targetUrl" + +fun authenticate( + helper: AuthenticationHelper, + paramsValues: Map, + credentials: GenericAuthenticationCredentials): HttpMessage { + + println("Kotlin auth template") + + println("TARGET_URL: ${paramsValues[PARAM_TARGET_URL]}") + val msg = helper.prepareMessage() + msg.requestHeader = HttpRequestHeader(HttpRequestHeader.GET, URI(paramsValues[PARAM_TARGET_URL], true), + HttpHeader.HTTP11) + println("msg: $msg ${msg.requestHeader.headers.size}") + msg.requestHeader.headers.forEach { println(it) } + helper.sendAndReceive(msg) + return msg +} + +fun getRequiredParamsNames(): Array { + return arrayOf(PARAM_TARGET_URL) +} + +fun getOptionalParamsNames(): Array { + return arrayOf() +} + +fun getCredentialsParamsNames(): Array { + return arrayOf("username", "password") +} + +fun getLoggedInIndicator(): String { + return "Sign Out" +} + +fun getLoggedOutIndicator(): String { + return "Sign In" +} \ No newline at end of file diff --git a/addOns/kotlin/src/main/zapHomeFiles/scripts/templates/standalone/Standalone default template.kts b/addOns/kotlin/src/main/zapHomeFiles/scripts/templates/standalone/Standalone default template.kts new file mode 100644 index 00000000000..dc1f17b031b --- /dev/null +++ b/addOns/kotlin/src/main/zapHomeFiles/scripts/templates/standalone/Standalone default template.kts @@ -0,0 +1,2 @@ + +println("KaaKaawwtlin!!") diff --git a/addOns/kotlin/src/test/kotlin/org/zaproxy/zap/extension/kotlin/KotlinScriptTest.kt b/addOns/kotlin/src/test/kotlin/org/zaproxy/zap/extension/kotlin/KotlinScriptTest.kt new file mode 100644 index 00000000000..0530affd2d4 --- /dev/null +++ b/addOns/kotlin/src/test/kotlin/org/zaproxy/zap/extension/kotlin/KotlinScriptTest.kt @@ -0,0 +1,50 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2020 The ZAP Development Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.zaproxy.zap.extension.kotlin + +import org.junit.jupiter.api.BeforeAll +import org.zaproxy.zap.testutils.AbstractVerifyScriptTemplates +import java.nio.charset.StandardCharsets +import java.nio.file.Files +import java.nio.file.Path +import javax.script.Compilable + +class KotlinScriptTest : AbstractVerifyScriptTemplates() { + + companion object { + lateinit var se: Compilable + @BeforeAll + @JvmStatic + fun setUp() { + se = KotlinScriptEngineFactory(Thread.currentThread().contextClassLoader).scriptEngine as Compilable + } + } + + override fun getScriptExtension(): String? { + return ".kts" + } + + override fun parseTemplate(template: Path?) { + val reader = Files.newBufferedReader(template, StandardCharsets.UTF_8) + val s = se.compile(reader) + s.eval() + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 9879c2fe0e8..77bfd81d3b8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -51,6 +51,7 @@ var addOns = listOf( "jruby", "jsonview", "jython", + "kotlin", "onlineMenu", "openapi", "plugnhack",