Skip to content

Commit 47d3913

Browse files
authored
Merge branch 'main' into cssschema-withProperties
2 parents e44b673 + 73b86b5 commit 47d3913

File tree

11 files changed

+293
-14
lines changed

11 files changed

+293
-14
lines changed

.gitattributes

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/COPYING text
2+
/src/test/resources/org/owasp/html/* text eol=lf
3+
.gitattributes text
4+
.gitignore text
5+
*.html text
6+
*.java text
7+
*.js text
8+
*.json text
9+
*.md text
10+
*.sh text
11+
*.txt text
12+
*.xml text
13+
*.yml text

.github/workflows/maven.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven
3+
4+
name: Java CI with Maven
5+
6+
on:
7+
push:
8+
paths-ignore:
9+
- '.github/workflows/*.yml'
10+
- '!.github/workflows/maven.yml'
11+
pull_request:
12+
paths-ignore:
13+
- '.github/workflows/*.yml'
14+
- '!.github/workflows/maven.yml'
15+
16+
permissions:
17+
contents: read
18+
19+
jobs:
20+
build:
21+
runs-on: ubuntu-latest
22+
23+
strategy:
24+
matrix:
25+
java: [ '11', '17', '21' ]
26+
27+
steps:
28+
- uses: actions/checkout@v4
29+
- name: Set up JDK ${{ matrix.Java }}
30+
uses: actions/setup-java@v4
31+
with:
32+
java-version: ${{ matrix.Java }}
33+
distribution: 'temurin'
34+
cache: maven
35+
- name: Build with Maven
36+
run: mvn --batch-mode --errors --fail-at-end --show-version --update-snapshots verify
37+
- name: Store artifact
38+
if: ${{ matrix.Java == 11 }}
39+
uses: actions/upload-artifact@v4
40+
with:
41+
name: jar-jdk${{ matrix.Java }}
42+
path: target/*.jar
43+
retention-days: 7

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ A fast and easy to configure HTML Sanitizer written in Java which lets
77
you include HTML authored by third-parties in your web application while
88
protecting against XSS.
99

10-
The existing dependencies are on guava and JSR 305. The other jars
10+
The existing dependency is on JSR 305. The other jars
1111
are only needed by the test suite. The JSR 305 dependency is a
1212
compile-only dependency, only needed for annotations.
1313

RELEASE-checklist.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ set -e
88

99

1010
# Make sure the build is ok via
11-
mvn -Dguava.version=27.0-jre -f aggregate clean verify javadoc:jar source:jar
1211
mvn -f aggregate clean verify jacoco:report site javadoc:jar source:jar
1312
mvn install
1413
mvn org.sonatype.ossindex.maven:ossindex-maven-plugin:audit -f aggregate

docs/getting_started.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44

55
If you are using Maven then follow the [maven](maven.md) directions to
66
add a dependency. Otherwise,
7-
[download prebuilt jars](https://search.maven.org/#artifactdetails%7Ccom.googlecode.owasp-java-html-sanitizer%7Cowasp-java-html-sanitizer%7C20180219.1%7Cjar)
7+
[download prebuilt jars](https://search.maven.org/artifact/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/)
88
or `git clone git@github.com:OWASP/java-html-sanitizer.git` and build
99
the latest source.
1010

11-
Unless maven is managing your CLASSPATH for you, you need to add both `owasp-java-html-sanitizer.jar` and the
12-
Guava JAR.
11+
Unless maven is managing your CLASSPATH for you, you need to add `owasp-java-html-sanitizer.jar`.
1312

1413
Once you have your CLASSPATH set up correctly with the relevant JARs
1514
you should be able to add

parent/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ application while protecting against XSS.
257257
<dependency>
258258
<groupId>com.google.protobuf</groupId>
259259
<artifactId>protobuf-java</artifactId>
260-
<version>3.9.1</version>
260+
<version>3.16.3</version>
261261
<scope>provided</scope>
262262
</dependency>
263263
<dependency>

src/main/java/org/owasp/html/HtmlPolicyBuilder.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import java.util.HashMap;
3333
import java.util.HashSet;
3434
import java.util.LinkedHashMap;
35-
import java.util.LinkedHashSet;
3635
import java.util.List;
3736
import java.util.Map;
3837
import java.util.Set;
@@ -965,12 +964,11 @@ public AttributeBuilder matching(
965964
*/
966965
@SuppressWarnings("synthetic-access")
967966
public HtmlPolicyBuilder globally() {
968-
if(attributeNames.get(0).equals("style")) {
969-
return allowStyling();
970-
} else {
971-
return HtmlPolicyBuilder.this.allowAttributesGlobally(
972-
policy, attributeNames);
967+
if (attributeNames.contains("style")) {
968+
allowStyling();
973969
}
970+
return HtmlPolicyBuilder.this.allowAttributesGlobally(
971+
policy, attributeNames);
974972
}
975973

976974
/**

src/test/java/org/owasp/html/CssSchemaTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ public static final void testDangerousProperties() {
5555
// Prefix corner cases.
5656
"-",
5757
"-moz-",
58+
"-ms-",
59+
"-o-",
60+
"-webkit-",
5861
}) {
5962
assertSame(key, CssSchema.DISALLOWED, CssSchema.DEFAULT.forKey(key));
6063
}

src/test/java/org/owasp/html/HtmlPolicyBuilderTest.java

Lines changed: 174 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,28 @@ public static final void testStyleFiltering() {
232232
}
233233

234234
@Test
235-
public void testCustomPropertyStyleFilterung() {
235+
public void testSpecificStyleFilterung() {
236+
assertEquals(
237+
Arrays.stream(new String[] {
238+
"<h1>Header</h1>",
239+
"<p>Paragraph 1</p>",
240+
"<p>Click me out</p>",
241+
"<p></p>",
242+
"<p><b>Fancy</b> with <i><b>soupy</b></i><b> tags</b>.",
243+
"</p><p style=\"text-align:center\">Stylish Para 1</p>",
244+
"<p style=\"color:red\">Stylish Para 2</p>",
245+
""}).collect(Collectors.joining("\n")),
246+
apply(new HtmlPolicyBuilder()
247+
.allowCommonInlineFormattingElements()
248+
.allowCommonBlockElements()
249+
.allowStyling(CssSchema.withProperties(
250+
List.of("color", "text-align", "font-size")))
251+
.allowStandardUrlProtocols()));
252+
}
253+
254+
255+
@Test
256+
public void testCustomPropertyStyleFiltering() {
236257
assertEquals(
237258
Arrays.stream(new String[] {
238259
"<h1>Header</h1>",
@@ -256,7 +277,29 @@ public void testCustomPropertyStyleFilterung() {
256277
}
257278

258279
@Test
259-
public void testCustomPropertyStyleFilterungDisallowed() {
280+
public void testUnionStyleFiltering() {
281+
assertEquals(
282+
Arrays.stream(new String[] {
283+
"<h1>Header</h1>",
284+
"<p>Paragraph 1</p>",
285+
"<p>Click me out</p>",
286+
"<p></p>",
287+
"<p><b>Fancy</b> with <i><b>soupy</b></i><b> tags</b>.",
288+
"</p><p style=\"text-align:center\">Stylish Para 1</p>",
289+
"<p style=\"color:red\">Stylish Para 2</p>",
290+
""}).collect(Collectors.joining("\n")),
291+
apply(new HtmlPolicyBuilder()
292+
.allowCommonInlineFormattingElements()
293+
.allowCommonBlockElements()
294+
.allowStyling(CssSchema.withProperties(
295+
List.of("color", "text-align")))
296+
.allowStyling( // union allowed style properties
297+
CssSchema.withProperties(List.of("font-size")))
298+
.allowStandardUrlProtocols()));
299+
}
300+
301+
@Test
302+
public void testCustomPropertyStyleFilteringDisallowed() {
260303
assertEquals(
261304
Arrays.stream(new String[] {
262305
"<h1>Header</h1>",
@@ -339,6 +382,25 @@ public static final void testAllowUrlProtocols() {
339382
.allowUrlProtocols("http")));
340383
}
341384

385+
@Test
386+
public static final void testDisallowUrlProtocols() {
387+
assertEquals(
388+
Arrays.stream(new String[] {
389+
"Header",
390+
"Paragraph 1",
391+
"Click me out",
392+
"<img src=\"canary.png\" alt=\"local-canary\" />",
393+
"Fancy with soupy tags.",
394+
"Stylish Para 1",
395+
"Stylish Para 2",
396+
""}).collect(Collectors.joining("\n")),
397+
apply(new HtmlPolicyBuilder()
398+
.allowElements("img")
399+
.allowAttributes("src", "alt").onElements("img")
400+
.allowUrlProtocols("http", "https")
401+
.disallowUrlProtocols("http")));
402+
}
403+
342404
@Test
343405
public static final void testPossibleFalloutFromIssue5() {
344406
assertEquals(
@@ -897,6 +959,52 @@ public static final void testEmptyDefaultLinkRelsSet() {
897959
pf.sanitize("<a href=\"http://example.com\" target=\"_blank\">eg</a>"));
898960
}
899961

962+
@Test
963+
public static final void testRequireAndSkipRels() {
964+
PolicyFactory pf = new HtmlPolicyBuilder()
965+
.allowElements("a")
966+
.allowAttributes("href", "target").onElements("a")
967+
.allowStandardUrlProtocols()
968+
.requireRelsOnLinks("noreferrer")
969+
.skipRelsOnLinks("noopener", "noreferrer")
970+
.toFactory();
971+
972+
assertEquals(
973+
"<a href=\"http://example.com\" target=\"_blank\">eg</a>",
974+
pf.sanitize("<a href=\"http://example.com\" target=\"_blank\">eg</a>"));
975+
976+
assertEquals(
977+
"<a href=\"http://example.com\" target=\"_blank\">eg</a>",
978+
pf.sanitize("<a href=\"http://example.com\" rel=noreferrer target=\"_blank\">eg</a>"));
979+
980+
assertEquals(
981+
"<a href=\"http://example.com\" target=\"_blank\">eg</a>",
982+
pf.sanitize("<a href=\"http://example.com\" rel=noopener target=\"_blank\">eg</a>"));
983+
}
984+
985+
@Test
986+
public static final void testSkipAndRequireRels() {
987+
PolicyFactory pf = new HtmlPolicyBuilder()
988+
.allowElements("a")
989+
.allowAttributes("href", "target").onElements("a")
990+
.allowStandardUrlProtocols()
991+
.skipRelsOnLinks("noopener", "noreferrer")
992+
.requireRelsOnLinks("noreferrer")
993+
.toFactory();
994+
995+
assertEquals(
996+
"<a href=\"http://example.com\" target=\"_blank\" rel=\"noreferrer\">eg</a>",
997+
pf.sanitize("<a href=\"http://example.com\" target=\"_blank\">eg</a>"));
998+
999+
assertEquals(
1000+
"<a href=\"http://example.com\" target=\"_blank\" rel=\"noreferrer\">eg</a>",
1001+
pf.sanitize("<a href=\"http://example.com\" rel=noreferrer target=\"_blank\">eg</a>"));
1002+
1003+
assertEquals(
1004+
"<a href=\"http://example.com\" target=\"_blank\" rel=\"noreferrer\">eg</a>",
1005+
pf.sanitize("<a href=\"http://example.com\" rel=noopener target=\"_blank\">eg</a>"));
1006+
}
1007+
9001008
@Test
9011009
public static final void testExplicitRelsSkip() {
9021010
PolicyFactory pf = new HtmlPolicyBuilder()
@@ -963,6 +1071,64 @@ public static final void testDirLi() {
9631071
"<dir compact=\"compact\"><li>something</li></dir>"));
9641072
}
9651073

1074+
@Test
1075+
public void testDisallowTextIn() {
1076+
HtmlPolicyBuilder sharedPolicyBuilder = new HtmlPolicyBuilder()
1077+
.allowElements("div")
1078+
.allowAttributes("style").onElements("div");
1079+
1080+
PolicyFactory allowPolicy = sharedPolicyBuilder.toFactory();
1081+
assertEquals("<div style=\"display:node\">Some Text</div>",
1082+
allowPolicy.sanitize("<div style=\"display:node\">Some Text</div>"));
1083+
1084+
PolicyFactory disallowTextPolicy =
1085+
sharedPolicyBuilder.disallowTextIn("div").toFactory();
1086+
assertEquals("<div style=\"display:node\"></div>",
1087+
disallowTextPolicy.sanitize(
1088+
"<div style=\"display:node\">Some Text</div>"));
1089+
}
1090+
1091+
@Test
1092+
public void testDisallowAttribute() {
1093+
HtmlPolicyBuilder sharedPolicyBuilder = new HtmlPolicyBuilder()
1094+
.allowElements("div", "p")
1095+
.allowAttributes("style").onElements("div", "p");
1096+
1097+
PolicyFactory allowPolicy = sharedPolicyBuilder.toFactory();
1098+
assertEquals(
1099+
"<p style=\"display:node\">Some</p><div style=\"display:node\">Text</div>",
1100+
allowPolicy.sanitize(
1101+
"<p style=\"display:node\">Some</p><div style=\"display:node\">Text</div>"));
1102+
1103+
PolicyFactory disallowTextPolicy =
1104+
sharedPolicyBuilder.disallowAttributes("style").onElements("p").toFactory();
1105+
assertEquals("<p>Some</p><div style=\"display:node\">Text</div>",
1106+
disallowTextPolicy.sanitize(
1107+
"<p style=\"display:node\">Some</p><div style=\"display:node\">Text</div>"));
1108+
}
1109+
1110+
@Test
1111+
public void testCreativeCSSStyling() {
1112+
PolicyFactory policy = new HtmlPolicyBuilder()
1113+
.allowElements("p")
1114+
.allowAttributes("style").onElements("p").allowStyling().toFactory();
1115+
1116+
assertEquals("<p>Some</p>",
1117+
policy.sanitize("<p style=\"{display:none\">Some</p>"));
1118+
1119+
assertEquals("<p style=\"color:red\">Some</p>",
1120+
policy.sanitize("<p style=\"{display:none;};color:red\">Some</p>"));
1121+
1122+
assertEquals("<p style=\"color:red\">Some</p>",
1123+
policy.sanitize("<p style=\"{display:none;}color:red\">Some</p>"));
1124+
1125+
assertEquals("<p style=\"color:red\">Some</p>",
1126+
policy.sanitize("<p style=\"display:none }; color:red\">Some</p>"));
1127+
1128+
assertEquals("<p style=\"color:red\">Some</p>",
1129+
policy.sanitize("<p style=\"{display:none;}}color:red\">Some</p>"));
1130+
}
1131+
9661132
@Test
9671133
public static void testScriptTagWithCommentBlockContainingHtmlCommentEnd() {
9681134
PolicyFactory scriptSanitizer = new HtmlPolicyBuilder()
@@ -1057,6 +1223,12 @@ public static final void testTextareaIsNotTextArea() {
10571223
assertEquals("x<textArea>y</textArea>", textAreaPolicy.sanitize(input));
10581224
}
10591225

1226+
@Test
1227+
public static final void testHtmlPolicyBuilderDefinitionWithNoAttributesDefinedGlobally() {
1228+
// Does not crash with a runtime exception
1229+
new HtmlPolicyBuilder().allowElements().allowAttributes().globally().toFactory();
1230+
}
1231+
10601232
@Test
10611233
public static final void testCSSFontSize() {
10621234
HtmlPolicyBuilder builder = new HtmlPolicyBuilder();

0 commit comments

Comments
 (0)