/*
 * Zed Attack Proxy (ZAP) and its related class files.
 *
 * ZAP is an HTTP/HTTPS proxy for assessing web application security.
 *
 * 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.pscanrules;

import java.util.List;
import net.htmlparser.jericho.Element;
import net.htmlparser.jericho.HTMLElementName;
import net.htmlparser.jericho.Source;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;
import org.apache.log4j.Logger;
import org.parosproxy.paros.core.scanner.Alert;
import org.parosproxy.paros.network.HttpMessage;
import org.zaproxy.zap.extension.pscan.PassiveScanThread;
import org.zaproxy.zap.extension.pscan.PluginPassiveScanner;


public class CrossDomainScriptInclusionScanner extends PluginPassiveScanner {

	private PassiveScanThread parent = null;
	private static final Logger logger = Logger.getLogger(CrossDomainScriptInclusionScanner.class);
	
	@Override
	public void scanHttpRequestSend(HttpMessage msg, int id) {
		
	}

	@Override
	public void scanHttpResponseReceive(HttpMessage msg, int id, Source source) {
		if (msg.getResponseBody().length() > 0 && msg.getResponseHeader().isText()){
			List<Element> sourceElements = source.getAllElements(HTMLElementName.SCRIPT);
			if (sourceElements != null) {
				for (Element sourceElement : sourceElements) {
					String src = sourceElement.getAttributeValue("src");
						if (src != null && isScriptFromOtherDomain(msg.getRequestHeader().getHostName(), src)) {
							this.raiseAlert(msg, id, src);
						}	
				}	
			}
		}
	}

	private void raiseAlert(HttpMessage msg, int id, String crossDomainScript) {
		Alert alert = new Alert(getPluginId(), Alert.RISK_LOW, Alert.WARNING, 
		    	getName());
		    	alert.setDetail(
		    			"The page at the following URL includes one or more script files from a third-party domain", 
		    	    msg.getRequestHeader().getURI().toString(),
		    	    crossDomainScript,
		    	    "", 
		    	    "",
		    	    "Ensure JavaScript source files are loaded from only trusted sources, and the sources can't be controlled by end users of the application", 
		            "", 
		            crossDomainScript, // evidence
		            0,	// TODO CWE Id
		            0,	// TODO WASC Id
		            msg);
	
    	parent.raiseAlert(id, alert);
	}
	
	@Override
	public void setParent(PassiveScanThread parent) {
		this.parent = parent;		
	}
	
	@Override
	public int getPluginId() {
		return 10017;
	}

	@Override
	public String getName() {
		return "Cross-Domain JavaScript Source File Inclusion";
	}

	private boolean isScriptFromOtherDomain (String host, String scriptURL){
		if (!scriptURL.startsWith("//") && (scriptURL.startsWith("/") || scriptURL.startsWith("./") || scriptURL.startsWith("../"))) {
			return false;
		}
		boolean result = false;
		try {
			URI scriptURI = new URI(scriptURL, true);
			String scriptHost = scriptURI.getHost();
			if(scriptHost != null && !scriptHost.toLowerCase().equals(host.toLowerCase())){
				result = true;
			} 
		}catch (URIException e) {
			logger.debug("Error: " + e.getMessage());
		}
		return result;
	}
}

@@ -2276,15 +2276,17 @@
 ert.
-WARNING
+CONFIRMED
 , %0D%0A

Update from deprecated Alert.WARNING