/* * 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.api; import java.io.StringWriter; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import net.sf.json.JSONObject; import org.apache.commons.lang.StringEscapeUtils; import org.apache.log4j.Logger; import org.parosproxy.paros.Constant; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.zaproxy.zap.utils.XMLStringUtil; public class ApiException extends Exception { private static final long serialVersionUID = 1L; public enum Type { /** * Indicates that the response's format requested is not valid. * * @see API.Format */ BAD_FORMAT, /** * Indicates that the requested type is not valid. * * @see API.RequestType */ BAD_TYPE, NO_IMPLEMENTOR, BAD_ACTION, BAD_VIEW, BAD_OTHER, INTERNAL_ERROR, MISSING_PARAMETER, URL_NOT_FOUND, HREF_NOT_FOUND, SCAN_IN_PROGRESS, DISABLED, ALREADY_EXISTS, DOES_NOT_EXIST, /** * Indicates that the value of a parameter is illegal/invalid (for example, it's not of expected type (boolean, * integer)). * <p> * The name of the parameter should be in the {@code detail} of the exception. * * @see ApiException#ApiException(Type, String) * @see ApiException#ApiException(Type, String, Throwable) */ ILLEGAL_PARAMETER, CONTEXT_NOT_FOUND, CONTENT_TYPE_NOT_SUPPORTED, USER_NOT_FOUND, URL_NOT_IN_CONTEXT, BAD_API_KEY, SCRIPT_NOT_FOUND, BAD_SCRIPT_FORMAT, NO_ACCESS, /* * Indicates that the requested operation is not allowed in the current mode */ MODE_VIOLATION, /** * Indicates that the external data (provided by other means other than the API parameters, for example, obtained from * the file system) is not correct. * * @since 2.6.0 */ BAD_EXTERNAL_DATA } private final Type type; private final String detail; private final Logger logger = Logger.getLogger(this.getClass()); public ApiException(Type type) { this(type, null, null); } public ApiException(Type type, Throwable cause) { this(type, null, cause); } public ApiException(Type type, String detail) { this(type, detail, null); } public ApiException(Type type, String detail, Throwable cause) { super(type.name().toLowerCase(), cause); this.type = type; this.detail = detail; } public Type getType() { return type; } @Override public String toString () { return this.toString(true); } public String toString (boolean incDetails) { if (! incDetails) { return Constant.messages.getString("api.error." + super.getMessage()); } else if (detail != null) { return Constant.messages.getString("api.error." + super.getMessage()) + " (" + super.getMessage() + ") : " + detail; } else { return Constant.messages.getString("api.error." + super.getMessage()) + " (" + super.getMessage() + ")"; } } public String toString(API.Format format, boolean incDetails) { switch(format) { case HTML: case UI: return StringEscapeUtils.escapeHtml(this.toString(incDetails)); case XML: try { DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); Document doc = docBuilder.newDocument(); Element rootElement = doc.createElement("Exception"); doc.appendChild(rootElement); rootElement.setAttribute("type", "exception"); rootElement.setAttribute("code", this.getMessage()); if (incDetails && detail != null) { rootElement.setAttribute("detail", XMLStringUtil.escapeControlChrs(this.detail)); } rootElement.appendChild(doc.createTextNode(XMLStringUtil.escapeControlChrs(this.toString(incDetails)))); TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); DOMSource source = new DOMSource(doc); StringWriter sw = new StringWriter(); StreamResult result = new StreamResult(sw); transformer.transform(source, result); return sw.toString(); } catch (Exception e) { logger.error(e.getMessage(), e); } break; case JSON: return this.toJSON(incDetails).toString(); default: break; } return null; } private JSONObject toJSON (boolean incDetails) { JSONObject ja = new JSONObject(); ja.put("code", super.getMessage()); ja.put("message", Constant.messages.getString("api.error." + super.getMessage())); if (incDetails && detail != null) { ja.put("detail", detail); } return ja; } }