diff --git a/addOns/kotlin/CHANGELOG.md b/addOns/kotlin/CHANGELOG.md new file mode 100644 index 00000000000..71106474244 --- /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/). + +## Unreleased + +- 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..7174dc4dd89 --- /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.0.0" +description = "Allows Kotlin to be used for ZAP scripting - (some) templates included" + +zapAddOn { + addOnName.set("Kotlin Support") + 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/java/org/zaproxy/zap/extension/kotlin/ExtensionKotlin.java b/addOns/kotlin/src/main/java/org/zaproxy/zap/extension/kotlin/ExtensionKotlin.java new file mode 100644 index 00000000000..e7167958511 --- /dev/null +++ b/addOns/kotlin/src/main/java/org/zaproxy/zap/extension/kotlin/ExtensionKotlin.java @@ -0,0 +1,86 @@ +/* + * 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 java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import javax.swing.*; +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.AddOnLoader; +import org.zaproxy.zap.control.ExtensionFactory; +import org.zaproxy.zap.extension.script.ExtensionScript; + +public class ExtensionKotlin extends ExtensionAdaptor { + + public static final String NAME = "ExtensionKotlin"; + public static final int EXTENSION_ORDER = 9999; + public static final ImageIcon KOTLIN_ICON; + private static final List> EXTENSION_DEPENDENCIES; + private static final Logger LOGGER = Logger.getLogger(ExtensionKotlin.class); + + static { + List> dependencies = new ArrayList<>(1); + dependencies.add(ExtensionScript.class); + EXTENSION_DEPENDENCIES = Collections.unmodifiableList(dependencies); + + KOTLIN_ICON = + View.isInitialised() + ? new ImageIcon( + ExtensionKotlin.class.getResource( + "/org/zaproxy/zap/extension/kotlin/resources/kotlin.png")) + : null; + } + + public ExtensionKotlin() { + super(NAME); + setOrder(EXTENSION_ORDER); + } + + @Override + public void hook(ExtensionHook extensionHook) { + super.hook(extensionHook); + + LOGGER.debug("Hooking Kotlin Scripting Extension"); + String zapJar = ZAP.class.getProtectionDomain().getCodeSource().getLocation().getFile(); + + LOGGER.debug("Loading Kotlin engine..."); + AddOnLoader addonLoader = ExtensionFactory.getAddOnLoader(); + Arrays.stream(addonLoader.getURLs()).forEach(LOGGER::debug); + KotlinScriptEngineFactory factory = new KotlinScriptEngineFactory(addonLoader, zapJar); + getExtScript().registerScriptEngineWrapper(new KotlinEngineWrapper(factory)); + LOGGER.debug("Kotlin engine loaded."); + } + + public List> getDependencies() { + return EXTENSION_DEPENDENCIES; + } + + private ExtensionScript getExtScript() { + return Control.getSingleton().getExtensionLoader().getExtension(ExtensionScript.class); + } +} diff --git a/addOns/kotlin/src/main/java/org/zaproxy/zap/extension/kotlin/KotlinEngineWrapper.java b/addOns/kotlin/src/main/java/org/zaproxy/zap/extension/kotlin/KotlinEngineWrapper.java new file mode 100644 index 00000000000..8df0201ff26 --- /dev/null +++ b/addOns/kotlin/src/main/java/org/zaproxy/zap/extension/kotlin/KotlinEngineWrapper.java @@ -0,0 +1,54 @@ +/* + * 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 java.util.Collections; +import java.util.List; +import javax.script.ScriptEngineFactory; +import javax.swing.*; +import org.fife.ui.rsyntaxtextarea.SyntaxConstants; +import org.zaproxy.zap.extension.script.DefaultEngineWrapper; + +public class KotlinEngineWrapper extends DefaultEngineWrapper { + + @Override + public ImageIcon getIcon() { + return ExtensionKotlin.KOTLIN_ICON; + } + + @Override + public String getSyntaxStyle() { + return SyntaxConstants.SYNTAX_STYLE_NONE; + } + + @Override + public boolean isRawEngine() { + return false; + } + + @Override + public List getExtensions() { + return Collections.singletonList("kts"); + } + + public KotlinEngineWrapper(ScriptEngineFactory factory) { + super(factory); + } +} diff --git a/addOns/kotlin/src/main/java/org/zaproxy/zap/extension/kotlin/KotlinScriptEngineFactory.java b/addOns/kotlin/src/main/java/org/zaproxy/zap/extension/kotlin/KotlinScriptEngineFactory.java new file mode 100644 index 00000000000..1bab7f3f01c --- /dev/null +++ b/addOns/kotlin/src/main/java/org/zaproxy/zap/extension/kotlin/KotlinScriptEngineFactory.java @@ -0,0 +1,61 @@ +/* + * 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 java.io.File; +import java.util.List; +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import kotlin.jvm.JvmClassMappingKt; +import kotlin.reflect.KClass; +import kotlin.script.experimental.jvm.util.JvmClasspathUtilKt; +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; + +public class KotlinScriptEngineFactory extends KotlinJsr223JvmScriptEngineFactoryBase { + + private final List jars; + + public KotlinScriptEngineFactory(ClassLoader classLoader, String zapJar) { + List clJars = + JvmClasspathUtilKt.scriptCompilationClasspathFromContextOrStdlib( + new String[] {"kotlin-stdlib"}, classLoader, true); + if (zapJar != null) { + clJars.add(new File(zapJar)); + } + jars = clJars; + } + + @Override + public ScriptEngine getScriptEngine() { + return new KotlinJsr223JvmLocalScriptEngine( + this, + jars, + KotlinStandardJsr223ScriptTemplate.class.getName(), + (ctx, types) -> + new ScriptArgsWithTypes( + new Bindings[] {ctx.getBindings(ScriptContext.ENGINE_SCOPE)}, + types), + new KClass[] {JvmClassMappingKt.getKotlinClass(Bindings.class)}); + } +} 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..a8e29939945 --- /dev/null +++ b/addOns/kotlin/src/main/resources/org/zaproxy/zap/extension/kotlin/resources/Messages.properties @@ -0,0 +1,2 @@ +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..c477d00d648 --- /dev/null +++ b/addOns/kotlin/src/main/zapHomeFiles/scripts/templates/authentication/Authentication default template.kts @@ -0,0 +1,45 @@ +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..2763b05d35b --- /dev/null +++ b/addOns/kotlin/src/main/zapHomeFiles/scripts/templates/standalone/Standalone default template.kts @@ -0,0 +1,3 @@ +println("KaaKaawwtlin!!") + + diff --git a/addOns/kotlin/src/test/java/org/zaproxy/zap/extension/kotlin/VerifyScriptTemplates.java b/addOns/kotlin/src/test/java/org/zaproxy/zap/extension/kotlin/VerifyScriptTemplates.java new file mode 100644 index 00000000000..6ac5a66abeb --- /dev/null +++ b/addOns/kotlin/src/test/java/org/zaproxy/zap/extension/kotlin/VerifyScriptTemplates.java @@ -0,0 +1,57 @@ +/* + * 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 java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import javax.script.Compilable; +import javax.script.CompiledScript; +import org.junit.jupiter.api.BeforeAll; +import org.zaproxy.zap.testutils.AbstractVerifyScriptTemplates; + +/** Verifies that the Kotlin script templates are parsed without errors. */ +public class VerifyScriptTemplates extends AbstractVerifyScriptTemplates { + + private static Compilable se; + + @BeforeAll + public static void setUp() { + se = + (Compilable) + new KotlinScriptEngineFactory( + Thread.currentThread().getContextClassLoader(), null) + .getScriptEngine(); + } + + @Override + protected String getScriptExtension() { + return ".kts"; + } + + @Override + protected void parseTemplate(Path template) throws Exception { + try (Reader reader = Files.newBufferedReader(template, StandardCharsets.UTF_8)) { + CompiledScript cs = se.compile(reader); + cs.eval(); + } + } +} 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",