All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zaproxy.zap.extension.script.ScriptsCache Maven / Gradle / Ivy

Go to download

The Zed Attack Proxy (ZAP) is an easy to use integrated penetration testing tool for finding vulnerabilities in web applications. It is designed to be used by people with a wide range of security experience and as such is ideal for developers and functional testers who are new to penetration testing. ZAP provides automated scanners as well as a set of tools that allow you to find security vulnerabilities manually.

The newest version!
/*
 * 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.script;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * A collection of cached scripts.
 *
 * @since 2.10.0
 * @see ExtensionScript#createScriptsCache(Configuration)
 */
public class ScriptsCache {

    private final ExtensionScript extensionScript;
    private final Configuration config;
    private final InterfaceProvider interfaceProvider;
    private final Map> cache;

    private List> cachedScripts;

    ScriptsCache(ExtensionScript extensionScript, Configuration config) {
        this.extensionScript = extensionScript;
        this.config = config;
        this.interfaceProvider =
                config.getInterfaceProvider() == null
                        ? createDefaultInterfaceProvider()
                        : config.getInterfaceProvider();
        this.cache = Collections.synchronizedMap(new HashMap<>());
        this.cachedScripts = Collections.emptyList();
    }

    private InterfaceProvider createDefaultInterfaceProvider() {
        return (scriptWrapper, targetInterface) -> {
            T script = extensionScript.getInterface(scriptWrapper, targetInterface);
            if (script == null) {
                extensionScript.handleFailedScriptInterface(
                        scriptWrapper,
                        config.getInterfaceErrorMessageProvider().getErrorMessage(scriptWrapper));
            }
            return script;
        };
    }

    /**
     * Refreshes the cache.
     *
     * 

Any scripts that are now disabled are removed, scripts that were changed are recreated. * *

Should be called when the scripts can be safely refreshed, for example, if a script needs * to be initialised before usage the cache should not be refreshed while it's being used. */ public void refresh() { synchronized (cache) { List latestScripts = extensionScript.getScripts(config.getScriptType()); cache.keySet().retainAll(latestScripts); List> latestCachedScripts = new ArrayList<>(); latestScripts.forEach( scriptWrapper -> refreshScriptImpl(scriptWrapper, latestCachedScripts)); cachedScripts = Collections.unmodifiableList(latestCachedScripts); } } private void refreshScriptImpl( ScriptWrapper scriptWrapper, List> latestCachedScripts) { CachedScript cachedScript = cache.computeIfAbsent(scriptWrapper, CachedScript::new); if (!cachedScript.isEnabled()) { cachedScript.setScript(null); return; } if (!cachedScript.hasChanged()) { latestCachedScripts.add(cachedScript); return; } cachedScript.setScript(null); try { T script = interfaceProvider.getInterface(scriptWrapper, config.getTargetInterface()); if (script != null) { cachedScript.setScript(script); latestCachedScripts.add(cachedScript); } } catch (Exception e) { extensionScript.handleScriptException(scriptWrapper, e); } } /** * Executes the given action on all cached scripts. * *

Exceptions thrown during the execution of the action are handled by the {@code * ExtensionScript}. * * @param action the action to be executed on each cached script. * @see ExtensionScript#handleScriptException(ScriptWrapper, Exception) */ public void execute(ScriptAction action) { cachedScripts.forEach( e -> { try { e.execute( () -> { action.apply(e.getScript()); return null; }); } catch (Exception ex) { extensionScript.handleScriptException(e.getScriptWrapper(), ex); } }); } /** * Convenience method that refreshes the cached scripts and executes the given action. * * @param action the action applied to each cached script. * @see #refresh() * @see #execute(ScriptAction) */ public void refreshAndExecute(ScriptAction action) { refresh(); execute(action); } /** * Executes the given action on all cached scripts. * *

Includes the corresponding script wrapper of each script. * *

Exceptions thrown during the execution of the action are handled by the {@code * ExtensionScript}. * * @param action the action to be executed on each cached script. * @see ExtensionScript#handleScriptException(ScriptWrapper, Exception) */ public void execute(ScriptWrapperAction action) { cachedScripts.forEach( e -> { ScriptWrapper sw = e.getScriptWrapper(); try { ExtensionScript.recordScriptCalledStats(sw); e.execute( () -> { action.apply(sw, e.getScript()); return null; }); } catch (Exception ex) { extensionScript.handleScriptException(sw, ex); } }); } /** * Convenience method that refreshes the cached scripts and executes the given action. * * @param action the action applied to each cached script. * @see #refresh() * @see #execute(ScriptWrapperAction) */ public void refreshAndExecute(ScriptWrapperAction action) { refresh(); execute(action); } /** * Gets the cached scripts. * * @return an unmodifiable list containing the cached scripts. */ public List> getCachedScripts() { return cachedScripts; } /** * A cached script, the interface and the corresponding script wrapper. * * @param the type of the interface. */ public static class CachedScript { private final ScriptWrapper scriptWrapper; private int currentModCount; private T script; CachedScript(ScriptWrapper scriptWrapper) { this.scriptWrapper = scriptWrapper; this.currentModCount = scriptWrapper.getModCount(); } /** * Gets the script wrapper. * * @return the script wrapper, never {@code null}. */ public ScriptWrapper getScriptWrapper() { return scriptWrapper; } /** * The script, through the interface. * * @return the script, never {@code null} for users of the collection. */ public T getScript() { return script; } void setScript(T script) { this.script = script; } R execute(Callable action) throws Exception { if (isSyncAccess()) { synchronized (this) { return action.call(); } } return action.call(); } private boolean isSyncAccess() { ScriptEngineWrapper engine = scriptWrapper.getEngine(); return engine != null && engine.isSingleThreaded(); } boolean hasChanged() { if (script == null) { return true; } int previousModCount = currentModCount; currentModCount = scriptWrapper.getModCount(); return previousModCount != currentModCount; } boolean isEnabled() { return scriptWrapper.isEnabled(); } } /** * The configuration of the {@link ScriptsCache}. * * @param the target type of the scripts. */ public static class Configuration { private final String scriptType; private final Class targetInterface; private final InterfaceProvider interfaceProvider; private final InterfaceErrorMessageProvider interfaceErrorMessageProvider; private Configuration( String scriptType, Class targetInterface, InterfaceProvider interfaceProvider, InterfaceErrorMessageProvider interfaceErrorMessageProvider) { this.scriptType = scriptType; this.targetInterface = targetInterface; this.interfaceProvider = interfaceProvider; this.interfaceErrorMessageProvider = interfaceErrorMessageProvider; } public String getScriptType() { return scriptType; } public Class getTargetInterface() { return targetInterface; } public InterfaceProvider getInterfaceProvider() { return interfaceProvider; } public InterfaceErrorMessageProvider getInterfaceErrorMessageProvider() { return interfaceErrorMessageProvider; } /** * Returns a new configuration builder. * * @param the target type of the scripts. * @return the configuration builder. */ public static Builder builder() { return new Builder<>(); } /** * A builder of configurations. * * @see #build() */ public static class Builder { private String scriptType; private Class targetInterface; private InterfaceProvider interfaceProvider; private InterfaceErrorMessageProvider interfaceErrorMessageProvider; private Builder() {} /** * Sets the script type. * * @param scriptType the script type. * @return this, for chaining. */ public Builder setScriptType(String scriptType) { this.scriptType = scriptType; return this; } /** * Sets the target interface. * * @param targetInterface the target interface. * @return this, for chaining. */ public Builder setTargetInterface(Class targetInterface) { this.targetInterface = targetInterface; return this; } /** * Sets the provider of interfaces. * * @param interfaceProvider the provider of interfaces. * @return this, for chaining. */ public Builder setInterfaceProvider(InterfaceProvider interfaceProvider) { this.interfaceProvider = interfaceProvider; return this; } /** * Sets the provider of error messages. * * @param interfaceErrorMessageProvider the provider of error messages. * @return this, for chaining. */ public Builder setInterfaceErrorMessageProvider( InterfaceErrorMessageProvider interfaceErrorMessageProvider) { this.interfaceErrorMessageProvider = interfaceErrorMessageProvider; return this; } /** * Builds the configuration from the specified data. * * @return the build configuration. * @throws IllegalStateException if the script type or the target interface is not set. * Or, the interface error message provider is set at the same time as the interface * provider. The error message provider is not used when using an interface * provider. */ public final Configuration build() { if (scriptType == null || scriptType.isEmpty()) { throw new IllegalStateException("The script type must be set."); } if (targetInterface == null) { throw new IllegalStateException("The target interface must be set."); } if (interfaceProvider != null && interfaceErrorMessageProvider != null) { throw new IllegalStateException( "The interface error message provider must not be set if using an interface provider."); } return new Configuration<>( scriptType, targetInterface, interfaceProvider, interfaceErrorMessageProvider); } } } /** * An action applied on a script, through the interface. * * @param the type of the interface. */ public interface ScriptAction { /** * Applies the action on the given script. * * @param script the script. * @throws Exception if an error occurred while applying the action to the script. */ void apply(T script) throws Exception; } /** * An action applied on a script, through the interface. * *

For convenience the corresponding wrapper is also provided. * * @param the type of the interface. */ public interface ScriptWrapperAction { /** * Applies the action on the given script. * * @param wrapper the corresponding script wrapper. * @param script the script. * @throws Exception if an error occurred while applying the action to the script. */ void apply(ScriptWrapper wrapper, T script) throws Exception; } /** * A provider of interfaces from scripts. * * @param the type of the interface. */ public interface InterfaceProvider { /** * Gets the given interface from the given script wrapper. * * @param scriptWrapper the script wrapper. * @param targetInterface the target interface. * @return the interface or {@code null} if the script does not implement it. * @throws Exception if an error occurred while creating the interface. */ T getInterface(ScriptWrapper scriptWrapper, Class targetInterface) throws Exception; } /** * A provider of error messages, that indicates that a script wrapper does not implement the * target interface. */ public interface InterfaceErrorMessageProvider { /** * Gets the error message that indicates that the script wrapper does not implement the * interface. * * @param scriptWrapper the script wrapper that does not implement the interface. * @return the error message. */ String getErrorMessage(ScriptWrapper scriptWrapper); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy