diff --git a/src/main/java/org/olat/core/util/filter/impl/OpenOLATPolicy.java b/src/main/java/org/olat/core/util/filter/impl/OpenOLATPolicy.java index 4586307ab7a3f05c99f62f2b9ef4c449a9d8c060..ab8cb3d454a8479e72bb1f6d6fa80732c24aa77d 100644 --- a/src/main/java/org/olat/core/util/filter/impl/OpenOLATPolicy.java +++ b/src/main/java/org/olat/core/util/filter/impl/OpenOLATPolicy.java @@ -19,14 +19,21 @@ */ package org.olat.core.util.filter.impl; +import java.util.List; import java.util.regex.Pattern; import org.owasp.html.HtmlPolicyBuilder; +import org.owasp.html.HtmlStreamEventProcessor; +import org.owasp.html.HtmlStreamEventReceiver; +import org.owasp.html.HtmlStreamEventReceiverWrapper; import org.owasp.html.PolicyFactory; import com.google.common.base.Predicate; /** + * The policy allow very specific onclicks values. It has a pre and + * post processor to handle the javascript:parent.goto(273846) + * * * Initial date: 22 mai 2019<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com @@ -160,7 +167,7 @@ public class OpenOLATPolicy { .matching(new Patterns(ONSITEURL, OFFSITEURL, OLATINTERNALURL)) .onElements("a") .allowAttributes("onclick") - .matching(false, "o_XHRWikiEvent(this);", "o_XHRWikiEvent(this);return(false);") + .matching(new OnClickValues()) .onElements("a") // link edu-sharing .allowAttributes("data-es_show_infos") @@ -267,8 +274,91 @@ public class OpenOLATPolicy { .allowWithoutAttributes("span") .allowElements("center") .allowWithoutAttributes("center") + .withPreprocessor(new OpenOLATPreprocessor()) + .withPostprocessor(new OpenOLATPostprocessor()) .toFactory(); + private static class OpenOLATPreprocessor implements HtmlStreamEventProcessor { + + @Override + public HtmlStreamEventReceiver wrap(HtmlStreamEventReceiver sink) { + return new OpenOLATPreReceiver(sink); + } + } + + private static class OpenOLATPreReceiver extends HtmlStreamEventReceiverWrapper { + + public OpenOLATPreReceiver(HtmlStreamEventReceiver sink) { + super(sink); + } + + @Override + public void openTag(String elementName, List<String> attrs) { + if("a".equals(elementName) && attrs != null) { + int numOfAttrs = attrs.size(); + for(int i=0; i<numOfAttrs; i++) { + String attr = attrs.get(i); + if("href".equals(attr) && i+1 < numOfAttrs + && attrs.get(i+1).startsWith("javascript:parent.goto") + && OLATINTERNALURL.matcher(attrs.get(i + 1)).matches()) { + attrs.set(i, "onclick"); + } + } + } + super.openTag(elementName, attrs); + } + } + + private static class OpenOLATPostprocessor implements HtmlStreamEventProcessor { + + @Override + public HtmlStreamEventReceiver wrap(HtmlStreamEventReceiver sink) { + return new OpenOLATostReceiver(sink); + } + } + + private static class OpenOLATostReceiver extends HtmlStreamEventReceiverWrapper { + + public OpenOLATostReceiver(HtmlStreamEventReceiver sink) { + super(sink); + } + + @Override + public void openTag(String elementName, List<String> attrs) { + if("a".equals(elementName) && attrs != null) { + int numOfAttrs = attrs.size(); + for(int i=0; i<numOfAttrs; i++) { + String attr = attrs.get(i); + if("onclick".equals(attr) && i+1 < numOfAttrs + && attrs.get(i+1).startsWith("javascript:parent.goto") + && OLATINTERNALURL.matcher(attrs.get(i + 1)).matches()) { + attrs.set(i, "href"); + } + } + } + super.openTag(elementName, attrs); + } + } + + private static class OnClickValues implements Predicate<String> { + + @Override + public boolean apply(String s) { + if("o_XHRWikiEvent(this);".equals(s) || "o_XHRWikiEvent(this);return(false);".equals(s)) { + return true; + } + return OLATINTERNALURL.matcher(s).matches(); + } + + // Needed for Java8 compat with later Guava that extends + // java.util.function.Predicate. + // For some reason the default test method implementation that calls + // through to apply is not assumed here. + @SuppressWarnings("unused") + public boolean test(String s) { + return apply(s); + } + } private static class Patterns implements Predicate<String> { diff --git a/src/test/java/org/olat/core/util/filter/impl/XSSFilterParamTest.java b/src/test/java/org/olat/core/util/filter/impl/XSSFilterParamTest.java index 258691f98a062b6194c2e6c3939910ecaefe8a7d..6bbd766efaf19dc5e6ed00b736899e9106ba4e81 100644 --- a/src/test/java/org/olat/core/util/filter/impl/XSSFilterParamTest.java +++ b/src/test/java/org/olat/core/util/filter/impl/XSSFilterParamTest.java @@ -184,7 +184,7 @@ public class XSSFilterParamTest { /* 100 */ { "<img src=\"/olat/edusharing/preview?objectUrl=ccrep://OpenOLAT/d5130470-14b4-4ad4-88b7-dfb3ebe943da&version=1.0\" data-es_identifier=\"2083dbe64f00b07232b11608ec0842fc\" data-es_objecturl=\"ccrep://OpenOLAT/d5130470-14b4-4ad4-88b7-dfb3ebe943da\" data-es_version=\"1.0\" data-es_version_current=\"1.0\" data-es_mediatype='i23' data-es_mimetype=\"image/png\" data-es_width=\"1000\" data-es_height=\"446\" data-es_first_edit=\"false\" class=\"edusharing\" alt=\"Bildschirmfoto 2018-11-07 um 16.09.49.png\" title=\"Bildschirmfoto 2018-11-07 um 16.09.49.png\" width=\"1000\" height=\"446\">", "<img src=\"/olat/edusharing/preview?objectUrl=ccrep://OpenOLAT/d5130470-14b4-4ad4-88b7-dfb3ebe943da&version=1.0\" data-es_identifier=\"2083dbe64f00b07232b11608ec0842fc\" data-es_objecturl=\"ccrep://OpenOLAT/d5130470-14b4-4ad4-88b7-dfb3ebe943da\" data-es_version=\"1.0\" data-es_version_current=\"1.0\" data-es_mediatype=\"i23\" data-es_mimetype=\"image/png\" data-es_width=\"1000\" data-es_height=\"446\" data-es_first_edit=\"false\" class=\"edusharing\" alt=\"Bildschirmfoto 2018-11-07 um 16.09.49.png\" title=\"Bildschirmfoto 2018-11-07 um 16.09.49.png\" width=\"1000\" height=\"446\" />" }, - { "Before<br>After<br>More", "Before<br />After<br />More" }, + { "<a href=\"javascript:parent.gotonode(100055283652712)\">Test</a>", "<a href=\"javascript:parent.gotonode(100055283652712)\">Test</a>" }, { null, "" } // be tolerant }); }