/*
* 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.brk.impl.http;
import java.util.regex.Pattern;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.log4j.Logger;
import org.parosproxy.paros.Constant;
import org.parosproxy.paros.model.Model;
import org.parosproxy.paros.network.HttpMessage;
import org.zaproxy.zap.extension.brk.AbstractBreakPointMessage;
import org.zaproxy.zap.extension.httppanel.Message;
public class HttpBreakpointMessage extends AbstractBreakPointMessage {
public enum Location {url, request_header, request_body, response_header, response_body};
public enum Match {contains, regex};
private static final Logger logger = Logger.getLogger(HttpBreakpointMessage.class);
private static final String TYPE = "HTTP";
private String string;
private Pattern pattern;
private Location location;
private Match match;
private boolean inverse;
private boolean ignoreCase;
public HttpBreakpointMessage(String string, Location location, Match match, boolean inverse, boolean ignoreCase) {
super();
this.string = string;
this.location = location;
this.match = match;
this.inverse = inverse;
this.ignoreCase = ignoreCase;
compilePattern();
}
@Override
public String getType() {
return TYPE;
}
public String getString() {
return string;
}
public void setString(String str) {
this.string = str;
compilePattern();
}
public Pattern getPattern() {
return pattern;
}
public void setPattern(Pattern pattern) {
this.pattern = pattern;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public Match getMatch() {
return match;
}
public void setMatch(Match match) {
this.match = match;
compilePattern();
}
public boolean isInverse() {
return inverse;
}
public void setInverse(boolean inverse) {
this.inverse = inverse;
}
public boolean isIgnoreCase() {
return ignoreCase;
}
public void setIgnoreCase(boolean ignoreCase) {
this.ignoreCase = ignoreCase;
compilePattern();
}
@Override
public boolean match(Message aMessage, boolean isRequest, boolean onlyIfInScope) {
if (aMessage instanceof HttpMessage) {
HttpMessage messge = (HttpMessage)aMessage;
try {
String uri = messge.getRequestHeader().getURI().toString();
if (onlyIfInScope) {
if (! Model.getSingleton().getSession().isInScope(uri)) {
return false;
}
}
String src = null;
switch (location) {
case url:
src = uri;
break;
case request_header:
if (! isRequest) {
return false;
}
src = messge.getRequestHeader().toString();
break;
case request_body:
if (! isRequest) {
return false;
}
src = messge.getRequestBody().toString();
break;
case response_header:
if (isRequest) {
return false;
}
src = messge.getResponseHeader().toString();
break;
case response_body:
if (isRequest) {
return false;
}
src = messge.getResponseBody().toString();
break;
}
boolean res;
if (Match.contains.equals(this.match)) {
if (ignoreCase) {
res = src.toLowerCase().contains(string.toLowerCase());
} else {
res = src.contains(string);
}
} else {
res = pattern.matcher(src).find();
}
if (inverse) {
return ! res;
} else {
return res;
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
return false;
}
private void compilePattern() {
try {
if (ignoreCase) {
pattern = Pattern.compile(string, Pattern.CASE_INSENSITIVE);
} else {
pattern = Pattern.compile(string);
}
} catch (Exception e) {
// This wont be a problem if its a 'contains' match
logger.debug("Potentially invalid regex", e);
}
}
@Override
public String getDisplayMessage() {
return Constant.messages.getString("brk.brkpoint.location." + location.name()) + ": " +
Constant.messages.getString("brk.brkpoint.match." + match.name()) + ": " +
(ignoreCase ? Constant.messages.getString("brk.brkpoint.ignorecase.label") : "") +
(inverse ? Constant.messages.getString("brk.brkpoint.inverse.label") : "") +
string;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (!(obj instanceof HttpBreakpointMessage)) {
return false;
}
HttpBreakpointMessage hbm = (HttpBreakpointMessage) obj;
return this.getString().equals(hbm.getString()) &&
this.getLocation().equals(hbm.getLocation()) &&
this.getMatch().equals(hbm.getMatch()) &&
this.isIgnoreCase() == hbm.isIgnoreCase() &&
this.isInverse() == hbm.isInverse();
}
@Override
public int hashCode() {
return new HashCodeBuilder(349, 631). // two 'randomly' chosen prime numbers
append(string).
append(location).
append(match).
append(ignoreCase).
append(inverse).
toHashCode();
}
}