Skip to content

Commit

Permalink
Merge pull request #1 from cnsgithub/kml-encoding-20
Browse files Browse the repository at this point in the history
resolves OWASP#20 - HTML encoding for KML
  • Loading branch information
cnsgithub authored Jun 21, 2018
2 parents 81b9fdc + d1c1bed commit 291c94d
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 5 deletions.
24 changes: 24 additions & 0 deletions core/src/main/java/org/owasp/encoder/Encode.java
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,30 @@ public static void forXmlComment(Writer out, String input)
encode(Encoders.XML_COMMENT_ENCODER, out, input);
}

/**
* Encoder for KML.
*
* @param input the input to encode
* @return the encoded result
*/
public static String forKml(String input) {
return encode(Encoders.KML_ENCODER, input);
}

/**
* See {@link #forKml(String)} for description of encoding. This
* version writes directly to a Writer without an intervening string.
*
* @param out where to write encoded output
* @param input the input string to encode
* @throws IOException if thrown by writer
*/
public static void forKml(Writer out, String input)
throws IOException
{
encode(Encoders.KML_ENCODER, out, input);
}

/**
* Encodes data for an XML CDATA section. On the chance that the input
* contains a terminating {@code "]]>"}, it will be replaced by
Expand Down
9 changes: 9 additions & 0 deletions core/src/main/java/org/owasp/encoder/Encoders.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ public final class Encoders {
* Name of {@linkplain Encode#forXmlComment(String) XML comment} context.
*/
public static final String XML_COMMENT = "xml-comment";
/**
* Name of {@linkplain Encode#forKml(String) KML} context.
*/
public static final String KML = "kml";
/**
* Name of {@linkplain Encode#forCDATA(String) CDATA} context.
*/
Expand Down Expand Up @@ -160,6 +164,11 @@ public final class Encoders {
*/
static final XMLCommentEncoder XML_COMMENT_ENCODER
= map(XML_COMMENT, new XMLCommentEncoder());
/**
* Encoder for KML contexts.
*/
static final KMLEncoder KML_ENCODER
= map(KML, new KMLEncoder());
/**
* Encoder for CDATA contexts.
*/
Expand Down
55 changes: 55 additions & 0 deletions core/src/main/java/org/owasp/encoder/KMLEncoder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) 2012 Jeff Ichnowski
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above
// copyright notice, this list of conditions and the following
// disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// * Neither the name of the OWASP nor the names of its
// contributors may be used to endorse or promote products
// derived from this software without specific prior written
// permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
package org.owasp.encoder;

import java.nio.CharBuffer;
import java.nio.charset.CoderResult;

/**
* KMLEncoder -- Special case of XML encoding using numeric character entities (e.g. < instead of entity references (e.g. <).
* This encoder should be used instead of {@link XMLEncoder} to address some shortcomings in the KML specification and the way Google Earth (at least the desktop version) interprets HTML.
*
* @see <a href="http://kml4earth.appspot.com/kmlErrata.html?#encoding">KML Reference Errata</a>
* @see <a href="https://github.com/OWASP/owasp-java-encoder/issues/20">OWASP Issue</a>
*
* @author cnsgithub
*/
class KMLEncoder extends XMLEncoder {

@Override
protected CoderResult encodeArrays(CharBuffer input, CharBuffer output, boolean endOfInput) {
return super.encodeArrays(input, output, endOfInput, true);
}

}
44 changes: 41 additions & 3 deletions core/src/main/java/org/owasp/encoder/XMLEncoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,15 @@ class XMLEncoder extends Encoder {
/**
* The encoded length of an ampersand.
*/
static final int AMP_LENGTH = 5;
static final int AMP_LENGTH = 5, AMP_NUMERIC_LENGTH = 5;
/**
* The encoded length of a less-than sign.
*/
static final int LT_LENGTH = 4;
static final int LT_LENGTH = 4, LT_NUMERIC_LENGTH = 5;
/**
* The encoded length of a greater-than sign.
*/
static final int GT_LENGTH = 4;
static final int GT_LENGTH = 4, GT_NUMERIC_LENGTH = 5;
/**
* The encoded length of an apostrophe.
*/
Expand Down Expand Up @@ -245,6 +245,10 @@ public int firstEncodedOffset(String input, int off, int len) {
* {@inheritDoc}
*/
protected CoderResult encodeArrays(CharBuffer input, CharBuffer output, boolean endOfInput) {
return encodeArrays(input, output, endOfInput, false);
}

protected CoderResult encodeArrays(CharBuffer input, CharBuffer output, boolean endOfInput, boolean avoidEntityReferences) {
final char[] in = input.array();
final char[] out = output.array();
int i = input.arrayOffset() + input.position();
Expand All @@ -264,6 +268,17 @@ protected CoderResult encodeArrays(CharBuffer input, CharBuffer output, boolean
} else {
switch (ch) {
case '&':
if (avoidEntityReferences) {
if (j + AMP_NUMERIC_LENGTH > m) {
return overflow(input, i, output, j);
}
out[j++] = '&';
out[j++] = '#';
out[j++] = '3';
out[j++] = '8';
out[j++] = ';';
break;
}
if (j + AMP_LENGTH > m) {
return overflow(input, i, output, j);
}
Expand All @@ -274,6 +289,17 @@ protected CoderResult encodeArrays(CharBuffer input, CharBuffer output, boolean
out[j++] = ';';
break;
case '<':
if (avoidEntityReferences) {
if (j + LT_NUMERIC_LENGTH > m) {
return overflow(input, i, output, j);
}
out[j++] = '&';
out[j++] = '#';
out[j++] = '6';
out[j++] = '0';
out[j++] = ';';
break;
}
if (j + LT_LENGTH > m) {
return overflow(input, i, output, j);
}
Expand All @@ -283,6 +309,18 @@ protected CoderResult encodeArrays(CharBuffer input, CharBuffer output, boolean
out[j++] = ';';
break;
case '>':
if (avoidEntityReferences) {
if (j + GT_NUMERIC_LENGTH > m) {
return overflow(input, i, output, j);
}
out[j++] = '&';
out[j++] = '#';
out[j++] = '6';
out[j++] = '2';
out[j++] = ';';
break;

}
if (j + GT_LENGTH > m) {
return overflow(input, i, output, j);
}
Expand Down
93 changes: 93 additions & 0 deletions core/src/test/java/org/owasp/encoder/KMLEncoderTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright (c) 2012 Jeff Ichnowski
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above
// copyright notice, this list of conditions and the following
// disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// * Neither the name of the OWASP nor the names of its
// contributors may be used to endorse or promote products
// derived from this software without specific prior written
// permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

package org.owasp.encoder;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

/**
* KMLEncoderTest -- test suite for the KMLEncoder.
*
* @author cnsgithub
*/
public class KMLEncoderTest extends TestCase {

public static Test suite() {
TestSuite suite = new TestSuite();
EncoderTestSuiteBuilder builder = new EncoderTestSuiteBuilder(new KMLEncoder(), "-safe-", "-&-")
.encode("&#60;strike&#62;foo &#38; bar&#60;/strike&#62;", "<strike>foo & bar</strike>")
.encode("invalid-control-characters", " b ", "\0b\26")
.encode("valid-surrogate-pair", "\ud800\udc00", "\ud800\udc00")
.encode("missing-low-surrogate", " ", "\ud800")
.encode("missing-high-surrogate", " ", "\udc00")
.encode("valid-upper-char", "\ufffd", "\ufffd")
.encode("invalid-upper-char", " ", "\uffff")
.invalid(0, 0x1f)
.valid("\t\r\n")
.valid(' ', Character.MAX_CODE_POINT)
.invalid(0x7f, 0x9f)
.valid("\u0085")
.invalid(Character.MIN_SURROGATE, Character.MAX_SURROGATE)
.invalid(0xfdd0, 0xfdef)
.invalid(0xfffe, 0xffff)
.invalid(0x1fffe, 0x1ffff)
.invalid(0x2fffe, 0x2ffff)
.invalid(0x3fffe, 0x3ffff)
.invalid(0x4fffe, 0x4ffff)
.invalid(0x5fffe, 0x5ffff)
.invalid(0x6fffe, 0x6ffff)
.invalid(0x7fffe, 0x7ffff)
.invalid(0x8fffe, 0x8ffff)
.invalid(0x9fffe, 0x9ffff)
.invalid(0xafffe, 0xaffff)
.invalid(0xbfffe, 0xbffff)
.invalid(0xcfffe, 0xcffff)
.invalid(0xdfffe, 0xdffff)
.invalid(0xefffe, 0xeffff)
.invalid(0xffffe, 0xfffff)
.invalid(0x10fffe, 0x10ffff);

builder.encoded("&><\'\"")
.encode("&#39;", "\'")
.encode("&#34;", "\"")
.encode("safe", "safe");

suite.addTest(builder.validSuite().invalidSuite(XMLEncoder.INVALID_CHARACTER_REPLACEMENT).encodedSuite().build());
return suite;
}

}

4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,8 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
<source>1.6</source>

This comment has been minimized.

Copy link
@privettoli

privettoli Jun 24, 2018

But aren't there projects that compile using 1.5?

This comment has been minimized.

Copy link
@cnsgithub

cnsgithub Jun 26, 2018

Author Owner

Thanks for counterchecking this commit. The change was unintentional. I changed the compiler levels back to normal.

<target>1.6</target>
</configuration>
</plugin>
<plugin>
Expand Down

0 comments on commit 291c94d

Please sign in to comment.