001: package org.tigris.scarab.util;
002:
003: /* ================================================================
004: * Copyright (c) 2000-2002 CollabNet. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are
008: * met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowlegement: "This product includes
019: * software developed by Collab.Net <http://www.Collab.Net/>."
020: * Alternately, this acknowlegement may appear in the software itself, if
021: * and wherever such third-party acknowlegements normally appear.
022: *
023: * 4. The hosted project names must not be used to endorse or promote
024: * products derived from this software without prior written
025: * permission. For written permission, please contact info@collab.net.
026: *
027: * 5. Products derived from this software may not use the "Tigris" or
028: * "Scarab" names nor may "Tigris" or "Scarab" appear in their names without
029: * prior written permission of Collab.Net.
030: *
031: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
032: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
033: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
034: * IN NO EVENT SHALL COLLAB.NET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
035: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
036: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
037: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
038: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
039: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
040: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
041: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
042: *
043: * ====================================================================
044: *
045: * This software consists of voluntary contributions made by many
046: * individuals on behalf of Collab.Net.
047: */
048:
049: import org.apache.velocity.app.event.ReferenceInsertionEventHandler;
050: import org.apache.velocity.app.event.NullSetEventHandler;
051:
052: /**
053: * This is a Velocity EventCartridge Filter which is responsible
054: * for processing $ variables when they are rendered in a template.
055: * The current purpose of this filter is to process out CSS
056: * (cross site scripting) vulnerabilities. There is some commented
057: * out code that adds a bit of timing information to make sure that
058: * the processing doesn't add to much overhead. In limited testing,
059: * it looks like this class only adds about 0-2ms of processing time to
060: * each request.
061: *
062: * <p>
063: * This class also implements the NullSetEventHandler and returns
064: * false from the shouldLogOnNullSet because we don't need that stuff
065: * showing up in the log files.
066: *
067: * @author <a href="mailto:jon@collab.net">Jon S. Stevens</a>
068: * @version $Id: ReferenceInsertionFilter.java 7365 2003-03-15 21:56:59Z jon $
069: */
070: public class ReferenceInsertionFilter implements
071: ReferenceInsertionEventHandler, NullSetEventHandler {
072: public boolean shouldLogOnNullSet(String lhs, String rhs) {
073: return false;
074: }
075:
076: public Object referenceInsert(String reference, Object value) {
077: // if value is null, we don't want to filter it of course!
078: if (value == null) {
079: return null;
080: }
081:
082: // System.out.println ("reference: '" + reference +
083: // "' type: '" + value.getClass().getName() + "'");
084:
085: // long start = System.currentTimeMillis();
086: Object result = value;
087: if (value instanceof String) {
088: if (
089: // don't filter renderer because it will get filtered
090: // when the actual rendering is done.
091: !reference.startsWith("$renderer") &&
092: // don't want to filter this because it outputs HTML
093: !reference.startsWith("$intake.declare") &&
094: // localization tool pre-filters data
095: !reference.startsWith("$l10n")) {
096: // we are already a String
097: result = filter((String) value);
098: }
099: }
100: // don't filter links and some other known to be safe elements
101: else if (!(value instanceof SkipFiltering)) {
102: // We convert the object to a string and output the result
103: result = filter(value.toString());
104: }
105: /*
106: long stop = System.currentTimeMillis();
107: System.out.println ("start: " + start);
108: System.out.println ("stop: " + stop);
109: long time = stop - start;
110: System.out.println ("reference: '" + reference +
111: "': " + time);
112: */
113: return result;
114: }
115:
116: /**
117: * This method is borrowed from Struts. It converts
118: * < > & " into the appropriate entities.
119: */
120: public static String filter(String value) {
121: if (value == null) {
122: return (null);
123: }
124: char content[] = new char[value.length()];
125: value.getChars(0, value.length(), content, 0);
126: StringBuffer result = new StringBuffer(content.length + 50);
127: for (int i = 0; i < content.length; i++) {
128: switch (content[i]) {
129: case '<':
130: result.append("<");
131: break;
132: case '>':
133: result.append(">");
134: break;
135: case '&':
136: if (i + 1 < content.length && content[i + 1] == '#') {
137: result.append('&');
138: } else {
139: result.append("&");
140: }
141: break;
142: case '"':
143: result.append(""");
144: break;
145: default:
146: result.append(content[i]);
147: }
148: }
149: return (result.toString());
150: }
151: }
|