rombert commented on code in PR #28: URL: https://github.com/apache/sling-org-apache-sling-xss/pull/28#discussion_r943373565
########## src/main/java/org/apache/sling/xss/impl/AntiSamyConstants.java: ########## @@ -0,0 +1,27 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl; + +public class AntiSamyConstants { Review Comment: Nit: remove class to `AntiSamyActions` and remove the '_ACTION_' suffix from constant names. I think `AntiySamyActions.REMOVE` reads better than `AntiSamyConstants.REMOVE_ACTION`. ########## src/main/java/org/apache/sling/xss/impl/xml/MapBuilder.java: ########## @@ -0,0 +1,247 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl.xml; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +import org.apache.sling.xss.impl.PolicyException; + +class MapBuilder { + + PolicyProvider policy; + // Antisamy hardcodes the allowed-empty-tags default: + // https://github.com/nahsra/antisamy/blob/main/src/main/java/org/owasp/validator/html/scan/Constants.java#L37 + public static final List<String> ALLOWED_EMPTY_TAGS = Arrays.asList( + "br", + "hr", + "a", + "img", + "link", + "iframe", + "script", + "object", + "applet", + "frame", + "base", + "param", + "meta", + "input", + "textarea", + "embed", + "basefont", + "col"); + + public void createRulesMap(PolicyProvider policy, AntiSamyRules topLevelElement) throws PolicyException { + this.policy = policy; + + parseCommonRegExps(topLevelElement.getRegexpList()); + parseDirectives(topLevelElement.getDirectiveList()); + parseAllowedEmptyTags(topLevelElement.getAllowedEmptyTags()); + parseCommonAttributes(topLevelElement.getCommonAttributeList()); + parseGlobalAttributes(topLevelElement.getGlobalTagAttributes().getGlobalTagAttributeList()); + parseDynamicAttributes(topLevelElement.getDynamicTagAttribute().getDynamicTagAttributeList()); + parseTagRules(topLevelElement.getTagRulesList()); + + parseCSSRules(topLevelElement.getPropertyList()); + } + + /** + * Go through the <common-regexps> section of the policy file. + * + * @param root Top level of <common-regexps> + */ + private void parseCommonRegExps(List<Regexp> root) { + for (Regexp regex : root) { + String name = regex.getName(); + Pattern regexp = Pattern.compile(regex.getValue(), + Pattern.DOTALL); + policy.commonRegularExpressions.put(name, regexp); + } + } + + /** + * Go through <directives> section of the policy file. + * + * @param root Top level of <directives> + */ + private void parseDirectives(List<Directive> root) { + for (Directive directive : root) { + String name = directive.getName(); + String value = directive.getValue(); + policy.directives.put(name, value); + } + } + + private void parseCommonAttributes(List<Attribute> root) { + for (Attribute attribute : root) { + List<Regexp> allowedRegexps = getAllowedRegexps(attribute.getRegexpList()); + Attribute newAttribute = new Attribute(attribute.getName(), allowedRegexps, attribute.getLiteralList(), + attribute.getOnInvalid(), attribute.getDescription()); + policy.commonAttributes.put(attribute.getName().toLowerCase(), newAttribute); + } + } + + // /** Review Comment: Remove the leading '//' so this can be recognised as a javadoc block. ########## src/main/java/org/apache/sling/xss/impl/xml/PolicyProvider.java: ########## @@ -0,0 +1,142 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl.xml; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.xml.stream.XMLStreamException; + +import org.apache.sling.xss.impl.PolicyException; + +public class PolicyProvider { + + protected final Map<String, Pattern> commonRegularExpressions = new HashMap<>(); + protected final Map<String, Attribute> commonAttributes = new HashMap<>(); + protected final Map<String, Tag> tagRules = new HashMap<>(); + protected final Map<String, Property> cssRules = new HashMap<>(); + protected final Map<String, String> directives = new HashMap<>(); + protected final Map<String, Attribute> globalAttributes = new HashMap<>(); + protected final Map<String, Attribute> dynamicAttributes = new HashMap<>(); + protected List<String> allowedEmptyTags = new ArrayList<>(); + protected final List<String> requireClosingTags = new ArrayList<>(); + + public static class CssPolicy { + + private final Map<String, Property> cssRules; + private final IncludeExcludeMatcher elementMatcher; + private final IncludeExcludeMatcher classMatcher; + private final IncludeExcludeMatcher idMatcher; + private final IncludeExcludeMatcher pseudoElementMatcher; + private final IncludeExcludeMatcher attributeMatcher; + + public CssPolicy(Map<String, Property> cssrules, Map<String, Pattern> commonRegExps, Map<String, String> directives) { + this.cssRules = Collections.unmodifiableMap(cssrules); + this.elementMatcher = new IncludeExcludeMatcher(commonRegExps.get("cssElementSelector"), + commonRegExps.get("cssElementExclusion")); + this.classMatcher = new IncludeExcludeMatcher(commonRegExps.get("cssClassSelector"), + commonRegExps.get("cssClassExclusion")); + this.idMatcher = new IncludeExcludeMatcher(commonRegExps.get("cssIDSelector"), + commonRegExps.get("cssIDExclusion")); + this.pseudoElementMatcher = new IncludeExcludeMatcher(commonRegExps.get("cssPseudoElementSelector"), + commonRegExps.get("cssPseudoElementExclusion")); + this.attributeMatcher = new IncludeExcludeMatcher(commonRegExps.get("cssAttributeSelector"), + commonRegExps.get("cssAttributeExclusion")); + } + + public Map<String, Property> getCssRules() { + return cssRules; + } + + public boolean isValidElementName(String name) { + return elementMatcher.matches(name); + } + + public boolean isValidClassName(String name) { + return classMatcher.matches(name); + } + + public boolean isValidId(String name) { + return idMatcher.matches(name); + } + + public boolean isValidPseudoElementName(String name) { + return pseudoElementMatcher.matches(name); + } + + public boolean isValidAttributeSelector(String name) { + return attributeMatcher.matches(name); + } + } + + public Map<String, String> getDirectives() { + return directives; + } + + public List<String> getRequireClosingTags() { + return requireClosingTags; + } + + public Map<String, Pattern> getCommonRegularExpressions() { + return commonRegularExpressions; + } + + public Map<String, Attribute> getGlobalAttributes() { + return globalAttributes; + } + + public Map<String, Attribute> getCommonAttributes() { + return commonAttributes; + } + + public Map<String, Property> getCssRules() { + return cssRules; + } + + public List<String> getAllowedEmptyTags() { + return allowedEmptyTags; + } + + public Map<String, Tag> getTagRules() { + return tagRules; + } + + public Map<String, Attribute> getDynamicAttributes() { + return dynamicAttributes; + } + + public CssPolicy getCssPolicy() { + return new CssPolicy(cssRules, + commonRegularExpressions, directives); + } + + public PolicyProvider(InputStream input) throws PolicyException, XMLStreamException, IOException { + AntiSamyXmlParser xmlParser = new AntiSamyXmlParser(); + MapBuilder mapBuilder = new MapBuilder(); + AntiSamyRules root = null; Review Comment: Nit: collapse this line and the next one into a single one: ```java AntiSamyRules root = xmlParser.createRules(input); ``` ########## src/main/java/org/apache/sling/xss/impl/HtmlToHtmlContentContext.java: ########## @@ -90,15 +81,15 @@ public boolean supportsPolicy() { return true; } - private CleanResults getCleanResults(PolicyHandler handler, String input) throws ScanException, PolicyException { - CleanResults results; + private String getCleanResults(PolicyHandler handler, String input) { + String results; ClassLoader tccl = Thread.currentThread().getContextClassLoader(); Review Comment: We should no longer need fiddling with the classloader. ########## src/main/java/org/apache/sling/xss/impl/xml/MapBuilder.java: ########## @@ -0,0 +1,247 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl.xml; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +import org.apache.sling.xss.impl.PolicyException; + +class MapBuilder { + + PolicyProvider policy; + // Antisamy hardcodes the allowed-empty-tags default: + // https://github.com/nahsra/antisamy/blob/main/src/main/java/org/owasp/validator/html/scan/Constants.java#L37 + public static final List<String> ALLOWED_EMPTY_TAGS = Arrays.asList( Review Comment: Nit: can this be private? ########## src/main/java/org/apache/sling/xss/impl/HtmlToHtmlContentContext.java: ########## @@ -48,7 +44,7 @@ public boolean check(final PolicyHandler policyHandler, final String str) { ClassLoader tccl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); - return policyHandler.getAntiSamy().scan(str).getNumberOfErrors() == 0; + return true; Review Comment: This doesn't look right, we are not returning true instead of scanning for errors. ########## src/main/java/org/apache/sling/xss/impl/HtmlSanitizer.java: ########## @@ -0,0 +1,88 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl; + +import java.lang.reflect.Field; + +import org.apache.sling.xss.impl.xml.PolicyProvider; +import org.owasp.html.DynamicAttributesSanitizerPolicy; +import org.owasp.html.Handler; +import org.owasp.html.HtmlStreamEventReceiver; +import org.owasp.html.HtmlStreamRenderer; +import org.owasp.html.PolicyFactory; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +public class HtmlSanitizer { + + private CustomPolicy custumPolicy; Review Comment: Typo: customPolicy ########## src/main/java/org/apache/sling/xss/impl/HtmlToHtmlContentContext.java: ########## @@ -48,7 +44,7 @@ public boolean check(final PolicyHandler policyHandler, final String str) { ClassLoader tccl = Thread.currentThread().getContextClassLoader(); Review Comment: We should no longer need fiddling with the classloader. ########## src/main/java/org/apache/sling/xss/impl/xml/PolicyProvider.java: ########## @@ -0,0 +1,142 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl.xml; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.xml.stream.XMLStreamException; + +import org.apache.sling.xss.impl.PolicyException; + +public class PolicyProvider { + + protected final Map<String, Pattern> commonRegularExpressions = new HashMap<>(); + protected final Map<String, Attribute> commonAttributes = new HashMap<>(); + protected final Map<String, Tag> tagRules = new HashMap<>(); + protected final Map<String, Property> cssRules = new HashMap<>(); + protected final Map<String, String> directives = new HashMap<>(); + protected final Map<String, Attribute> globalAttributes = new HashMap<>(); + protected final Map<String, Attribute> dynamicAttributes = new HashMap<>(); + protected List<String> allowedEmptyTags = new ArrayList<>(); + protected final List<String> requireClosingTags = new ArrayList<>(); + + public static class CssPolicy { + + private final Map<String, Property> cssRules; + private final IncludeExcludeMatcher elementMatcher; + private final IncludeExcludeMatcher classMatcher; + private final IncludeExcludeMatcher idMatcher; + private final IncludeExcludeMatcher pseudoElementMatcher; + private final IncludeExcludeMatcher attributeMatcher; + + public CssPolicy(Map<String, Property> cssrules, Map<String, Pattern> commonRegExps, Map<String, String> directives) { + this.cssRules = Collections.unmodifiableMap(cssrules); + this.elementMatcher = new IncludeExcludeMatcher(commonRegExps.get("cssElementSelector"), + commonRegExps.get("cssElementExclusion")); + this.classMatcher = new IncludeExcludeMatcher(commonRegExps.get("cssClassSelector"), + commonRegExps.get("cssClassExclusion")); + this.idMatcher = new IncludeExcludeMatcher(commonRegExps.get("cssIDSelector"), + commonRegExps.get("cssIDExclusion")); + this.pseudoElementMatcher = new IncludeExcludeMatcher(commonRegExps.get("cssPseudoElementSelector"), + commonRegExps.get("cssPseudoElementExclusion")); + this.attributeMatcher = new IncludeExcludeMatcher(commonRegExps.get("cssAttributeSelector"), + commonRegExps.get("cssAttributeExclusion")); + } + + public Map<String, Property> getCssRules() { + return cssRules; + } + + public boolean isValidElementName(String name) { + return elementMatcher.matches(name); + } + + public boolean isValidClassName(String name) { + return classMatcher.matches(name); + } + + public boolean isValidId(String name) { + return idMatcher.matches(name); + } + + public boolean isValidPseudoElementName(String name) { + return pseudoElementMatcher.matches(name); + } + + public boolean isValidAttributeSelector(String name) { + return attributeMatcher.matches(name); + } + } + + public Map<String, String> getDirectives() { + return directives; + } + + public List<String> getRequireClosingTags() { + return requireClosingTags; + } + + public Map<String, Pattern> getCommonRegularExpressions() { + return commonRegularExpressions; + } + + public Map<String, Attribute> getGlobalAttributes() { + return globalAttributes; + } + + public Map<String, Attribute> getCommonAttributes() { + return commonAttributes; + } + + public Map<String, Property> getCssRules() { + return cssRules; + } + + public List<String> getAllowedEmptyTags() { + return allowedEmptyTags; + } + + public Map<String, Tag> getTagRules() { + return tagRules; + } + + public Map<String, Attribute> getDynamicAttributes() { + return dynamicAttributes; + } + + public CssPolicy getCssPolicy() { + return new CssPolicy(cssRules, + commonRegularExpressions, directives); + } + + public PolicyProvider(InputStream input) throws PolicyException, XMLStreamException, IOException { Review Comment: Please move the constructor above the methods ########## src/main/java/org/apache/sling/xss/impl/xml/MapBuilder.java: ########## @@ -0,0 +1,247 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl.xml; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +import org.apache.sling.xss.impl.PolicyException; + +class MapBuilder { + + PolicyProvider policy; + // Antisamy hardcodes the allowed-empty-tags default: + // https://github.com/nahsra/antisamy/blob/main/src/main/java/org/owasp/validator/html/scan/Constants.java#L37 + public static final List<String> ALLOWED_EMPTY_TAGS = Arrays.asList( + "br", + "hr", + "a", + "img", + "link", + "iframe", + "script", + "object", + "applet", + "frame", + "base", + "param", + "meta", + "input", + "textarea", + "embed", + "basefont", + "col"); + + public void createRulesMap(PolicyProvider policy, AntiSamyRules topLevelElement) throws PolicyException { + this.policy = policy; + + parseCommonRegExps(topLevelElement.getRegexpList()); + parseDirectives(topLevelElement.getDirectiveList()); + parseAllowedEmptyTags(topLevelElement.getAllowedEmptyTags()); + parseCommonAttributes(topLevelElement.getCommonAttributeList()); + parseGlobalAttributes(topLevelElement.getGlobalTagAttributes().getGlobalTagAttributeList()); + parseDynamicAttributes(topLevelElement.getDynamicTagAttribute().getDynamicTagAttributeList()); + parseTagRules(topLevelElement.getTagRulesList()); + + parseCSSRules(topLevelElement.getPropertyList()); + } + + /** + * Go through the <common-regexps> section of the policy file. + * + * @param root Top level of <common-regexps> + */ + private void parseCommonRegExps(List<Regexp> root) { + for (Regexp regex : root) { + String name = regex.getName(); + Pattern regexp = Pattern.compile(regex.getValue(), + Pattern.DOTALL); + policy.commonRegularExpressions.put(name, regexp); + } + } + + /** + * Go through <directives> section of the policy file. + * + * @param root Top level of <directives> + */ + private void parseDirectives(List<Directive> root) { + for (Directive directive : root) { + String name = directive.getName(); + String value = directive.getValue(); + policy.directives.put(name, value); + } + } + + private void parseCommonAttributes(List<Attribute> root) { + for (Attribute attribute : root) { + List<Regexp> allowedRegexps = getAllowedRegexps(attribute.getRegexpList()); + Attribute newAttribute = new Attribute(attribute.getName(), allowedRegexps, attribute.getLiteralList(), + attribute.getOnInvalid(), attribute.getDescription()); + policy.commonAttributes.put(attribute.getName().toLowerCase(), newAttribute); + } + } + + // /** + // * Go through <allowed-empty-tags> section of the policy file. + // * + // * @param allowedEmptyTagsListNode Top level of <allowed-empty-tags> + // * @param allowedEmptyTags The tags that can be empty + // */ + private void parseAllowedEmptyTags(AllowedEmptyTags allowedEmptyTagsList) throws PolicyException { + if (allowedEmptyTagsList != null) { + policy.allowedEmptyTags = allowedEmptyTagsList.getLiterals(); + } else + policy.allowedEmptyTags.addAll(ALLOWED_EMPTY_TAGS); + } + + // /** + // * Go through <global-tag-attributes> section of the policy file. + // * + // * @param root Top level of <global-tag-attributes> + // * @param globalAttributes1 A HashMap of global Attributes that need + // validation + // * for every tag. + // * @param commonAttributes The common attributes + // * @throws PolicyException + // */ + private void parseGlobalAttributes(List<Attribute> root) throws PolicyException { + for (Attribute ele : root) { + String name = ele.getName(); + Attribute toAdd = policy.commonAttributes.get(name.toLowerCase()); + + if (toAdd != null) + policy.globalAttributes.put(name.toLowerCase(), toAdd); + else + throw new PolicyException("Global attribute '" + name + + "' was not defined in <common-attributes>"); + } + } + + // /** Review Comment: Remove the leading '//' so this can be recognised as a javadoc block. ########## src/main/java/org/apache/sling/xss/impl/xml/PolicyProvider.java: ########## @@ -0,0 +1,142 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl.xml; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.xml.stream.XMLStreamException; + +import org.apache.sling.xss.impl.PolicyException; + +public class PolicyProvider { + + protected final Map<String, Pattern> commonRegularExpressions = new HashMap<>(); + protected final Map<String, Attribute> commonAttributes = new HashMap<>(); + protected final Map<String, Tag> tagRules = new HashMap<>(); + protected final Map<String, Property> cssRules = new HashMap<>(); + protected final Map<String, String> directives = new HashMap<>(); + protected final Map<String, Attribute> globalAttributes = new HashMap<>(); + protected final Map<String, Attribute> dynamicAttributes = new HashMap<>(); + protected List<String> allowedEmptyTags = new ArrayList<>(); + protected final List<String> requireClosingTags = new ArrayList<>(); + + public static class CssPolicy { Review Comment: Please move this class after the last method ########## src/main/java/org/apache/sling/xss/impl/xml/MapBuilder.java: ########## @@ -0,0 +1,247 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl.xml; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +import org.apache.sling.xss.impl.PolicyException; + +class MapBuilder { + + PolicyProvider policy; + // Antisamy hardcodes the allowed-empty-tags default: + // https://github.com/nahsra/antisamy/blob/main/src/main/java/org/owasp/validator/html/scan/Constants.java#L37 + public static final List<String> ALLOWED_EMPTY_TAGS = Arrays.asList( + "br", + "hr", + "a", + "img", + "link", + "iframe", + "script", + "object", + "applet", + "frame", + "base", + "param", + "meta", + "input", + "textarea", + "embed", + "basefont", + "col"); + + public void createRulesMap(PolicyProvider policy, AntiSamyRules topLevelElement) throws PolicyException { + this.policy = policy; + + parseCommonRegExps(topLevelElement.getRegexpList()); + parseDirectives(topLevelElement.getDirectiveList()); + parseAllowedEmptyTags(topLevelElement.getAllowedEmptyTags()); + parseCommonAttributes(topLevelElement.getCommonAttributeList()); + parseGlobalAttributes(topLevelElement.getGlobalTagAttributes().getGlobalTagAttributeList()); + parseDynamicAttributes(topLevelElement.getDynamicTagAttribute().getDynamicTagAttributeList()); + parseTagRules(topLevelElement.getTagRulesList()); + + parseCSSRules(topLevelElement.getPropertyList()); + } + + /** + * Go through the <common-regexps> section of the policy file. + * + * @param root Top level of <common-regexps> + */ + private void parseCommonRegExps(List<Regexp> root) { + for (Regexp regex : root) { + String name = regex.getName(); + Pattern regexp = Pattern.compile(regex.getValue(), + Pattern.DOTALL); + policy.commonRegularExpressions.put(name, regexp); + } + } + + /** + * Go through <directives> section of the policy file. + * + * @param root Top level of <directives> + */ + private void parseDirectives(List<Directive> root) { + for (Directive directive : root) { + String name = directive.getName(); + String value = directive.getValue(); + policy.directives.put(name, value); + } + } + + private void parseCommonAttributes(List<Attribute> root) { + for (Attribute attribute : root) { + List<Regexp> allowedRegexps = getAllowedRegexps(attribute.getRegexpList()); + Attribute newAttribute = new Attribute(attribute.getName(), allowedRegexps, attribute.getLiteralList(), + attribute.getOnInvalid(), attribute.getDescription()); + policy.commonAttributes.put(attribute.getName().toLowerCase(), newAttribute); + } + } + + // /** + // * Go through <allowed-empty-tags> section of the policy file. + // * + // * @param allowedEmptyTagsListNode Top level of <allowed-empty-tags> + // * @param allowedEmptyTags The tags that can be empty + // */ + private void parseAllowedEmptyTags(AllowedEmptyTags allowedEmptyTagsList) throws PolicyException { + if (allowedEmptyTagsList != null) { + policy.allowedEmptyTags = allowedEmptyTagsList.getLiterals(); + } else + policy.allowedEmptyTags.addAll(ALLOWED_EMPTY_TAGS); + } + + // /** Review Comment: Remove the leading '//' so this can be recognised as a javadoc block. ########## src/test/java/org/apache/sling/xss/impl/XSSFilterImplTest.java: ########## @@ -122,4 +122,11 @@ public void testFallbackFiltering() { assertNotNull(xssFilter); assertEquals(longURLContext, xssFilter.filter(longURLContext)); } + + @Test + public void testUpdatePolicy() { + XSSFilterImpl xssFilter = new XSSFilterImpl(); + context.registerInjectActivateService(xssFilter); + // xssFilter.updatePolicy(); Review Comment: This test looks incomplete. Either add some more behaviour/checks or remove it. ########## src/main/java/org/apache/sling/xss/impl/CustomPolicy.java: ########## @@ -0,0 +1,261 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.annotation.Nullable; + +import org.apache.sling.xss.impl.style.CssValidator; +import org.apache.sling.xss.impl.xml.Attribute; +import org.apache.sling.xss.impl.xml.PolicyProvider; +import org.apache.sling.xss.impl.xml.Tag; + +import org.owasp.html.AttributePolicy; +import org.owasp.html.HtmlPolicyBuilder; +import org.owasp.html.PolicyFactory; + +import com.google.common.base.Predicate; + +public class CustomPolicy { + private PolicyFactory policyFactory; Review Comment: Can the instance fields be made final? ########## src/main/java/org/apache/sling/xss/impl/xml/PolicyProvider.java: ########## @@ -0,0 +1,142 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl.xml; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.xml.stream.XMLStreamException; + +import org.apache.sling.xss.impl.PolicyException; + +public class PolicyProvider { + + protected final Map<String, Pattern> commonRegularExpressions = new HashMap<>(); Review Comment: Do the fields need to be protected or can they be private? ########## src/main/java/org/apache/sling/xss/impl/CustomPolicy.java: ########## @@ -0,0 +1,261 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.annotation.Nullable; + +import org.apache.sling.xss.impl.style.CssValidator; +import org.apache.sling.xss.impl.xml.Attribute; +import org.apache.sling.xss.impl.xml.PolicyProvider; +import org.apache.sling.xss.impl.xml.Tag; + +import org.owasp.html.AttributePolicy; +import org.owasp.html.HtmlPolicyBuilder; +import org.owasp.html.PolicyFactory; + +import com.google.common.base.Predicate; + +public class CustomPolicy { + private PolicyFactory policyFactory; + private List<String> onInvalidRemoveTagList = new ArrayList<>(); + private Map<String, AttributePolicy> dynamicAttributesPolicyMap = new HashMap<>(); + private CssValidator cssValidator; + static final String ALLOW_DYNAMIC_ATTRIBUTES = "allowDynamicAttributes"; Review Comment: Please move the static fields above the instance fields. ########## src/main/java/org/apache/sling/xss/impl/xml/PolicyProvider.java: ########## @@ -0,0 +1,142 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl.xml; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.xml.stream.XMLStreamException; + +import org.apache.sling.xss.impl.PolicyException; + +public class PolicyProvider { Review Comment: I would call this an "AntisamyPolicy", because it expresses a policy ( what to do with HTML and CSS input ) in terms of an AntiSamy config file. ########## src/main/java/org/apache/sling/xss/impl/CustomPolicy.java: ########## @@ -0,0 +1,265 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.annotation.Nullable; + +import org.apache.sling.xss.impl.style.CssValidator; +import org.apache.sling.xss.impl.xml.Attribute; +import org.apache.sling.xss.impl.xml.Policy; +import org.apache.sling.xss.impl.xml.Tag; +import org.owasp.html.AttributePolicy; +import org.owasp.html.HtmlPolicyBuilder; +import org.owasp.html.PolicyFactory; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableSet; + +public class CustomPolicy { Review Comment: I thought about this some more and I think I prefer a name like `AntiSamyPolicyAdapter`, as it adapts a "policy" - rules to apply to HTML and CSS based - from the AntiSamy world to the Java HTML Sanitiser world. ########## src/main/java/org/apache/sling/xss/impl/CustomPolicy.java: ########## @@ -0,0 +1,261 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you 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.apache.sling.xss.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.annotation.Nullable; + +import org.apache.sling.xss.impl.style.CssValidator; +import org.apache.sling.xss.impl.xml.Attribute; +import org.apache.sling.xss.impl.xml.PolicyProvider; +import org.apache.sling.xss.impl.xml.Tag; + +import org.owasp.html.AttributePolicy; +import org.owasp.html.HtmlPolicyBuilder; +import org.owasp.html.PolicyFactory; + +import com.google.common.base.Predicate; + +public class CustomPolicy { + private PolicyFactory policyFactory; + private List<String> onInvalidRemoveTagList = new ArrayList<>(); + private Map<String, AttributePolicy> dynamicAttributesPolicyMap = new HashMap<>(); + private CssValidator cssValidator; + static final String ALLOW_DYNAMIC_ATTRIBUTES = "allowDynamicAttributes"; + static final String REMOVE_TAG_ONINVALID_ACTION = "removeTag"; + + public CustomPolicy(PolicyProvider policy) { + removeAttributeGuards(); + HtmlPolicyBuilder policyBuilder = new HtmlPolicyBuilder(); + + cssValidator = new CssValidator(policy.getCssPolicy()); + + // ------------ this is for the global attributes ------------- + Map<String, Attribute> globalAttributes = policy.getGlobalAttributes(); + + for (Attribute attribute : globalAttributes.values()) { + if (attribute.getOnInvalid().equals(REMOVE_TAG_ONINVALID_ACTION)) { + onInvalidRemoveTagList.add(attribute.getName()); + } + + if (CssValidator.STYLE_ATTRIBUTE_NAME.equals(attribute.getName())) { + // we match style tags separately + policyBuilder.allowAttributes(attribute.getName()).matching(cssValidator.newCssAttributePolicy()) + .globally(); + } else { + List<String> allowedValuesFromAttribute = attribute.getLiterals(); + for (String allowedValue : allowedValuesFromAttribute) { + policyBuilder.allowAttributes(attribute.getName()).matching(true, allowedValue).globally(); + } + + List<Pattern> regexsFromAttribute = attribute.getPatternList(); + if (!regexsFromAttribute.isEmpty()) { + policyBuilder.allowAttributes(attribute.getName()).matching(matchesToPatterns(regexsFromAttribute)) + .globally(); + } else { + policyBuilder.allowAttributes(attribute.getName()).globally(); + } + } + } + + // ------------ this is for the allowed emty tags ------------- + List<String> allowedEmptyTags = policy.getAllowedEmptyTags(); + for (String allowedEmptyTag : allowedEmptyTags) { + policyBuilder.allowWithoutAttributes(allowedEmptyTag); + } + + // ------------ this is for the tag rules ------------- + Map<String, Tag> tagMap = policy.getTagRules(); + for (Map.Entry<String, Tag> tag : tagMap.entrySet()) { + + String tagAction = tag.getValue().getAction(); + switch (tagAction) { + // Tag.action + case AntiSamyConstants.TRUNCATE_ACTION: + policyBuilder.allowElements(tag.getValue().getName()); + break; + + // filter: remove tags, but keep content, + case AntiSamyConstants.FILTER_ACTION: + break; + + // remove: remove tag and contents + case AntiSamyConstants.REMOVE_ACTION: + policyBuilder.disallowElements(tag.getValue().getName()); + break; + + case AntiSamyConstants.VALIDATE_ACTION: + case "": + policyBuilder.allowElements(tag.getValue().getName()); + boolean styleSeen = false; + // get the allowed Attributes for the tag + Map<String, Attribute> allowedAttributes = tag.getValue().getAttributeMap(); + // if there are allowed Attributes, map over them + for (Attribute attribute : allowedAttributes.values()) { + + if (attribute.getOnInvalid().equals(REMOVE_TAG_ONINVALID_ACTION)) { + onInvalidRemoveTagList.add(attribute.getName()); + } + + if (CssValidator.STYLE_ATTRIBUTE_NAME.equals(attribute.getName())) { + styleSeen = true; + } + + List<String> allowedValuesFromAttribute = attribute.getLiterals(); + for (String allowedValue : allowedValuesFromAttribute) { + policyBuilder.allowAttributes(attribute.getName()).matching(true, allowedValue) + .onElements(tag.getValue().getName()); + } + + List<Pattern> regexsFromAttribute = attribute.getPatternList(); + if (!regexsFromAttribute.isEmpty()) { + policyBuilder.allowAttributes(attribute.getName()) + .matching(matchesToPatterns(regexsFromAttribute)) + .onElements(tag.getValue().getName()); + } else { + policyBuilder.allowAttributes(attribute.getName()).onElements(tag.getValue().getName()); + } + } + + if (!styleSeen) { + policyBuilder.allowAttributes(CssValidator.STYLE_ATTRIBUTE_NAME) + .matching(cssValidator.newCssAttributePolicy()).onElements(tag.getValue().getName()); + } + break; + + default: + throw new RuntimeException("No tag action found."); + } + } + + // disallow style tag on specific elements + policyBuilder.disallowAttributes(CssValidator.STYLE_ATTRIBUTE_NAME) + .onElements(cssValidator.getDisallowedTagNames().toArray(new String[0])); + + // ---------- dynamic attributes ------------ + Map<String, Attribute> dynamicAttributes = new HashMap<>(); + + // checks if the dynamic attributes are allowed + if (policy.getDirectives().get(ALLOW_DYNAMIC_ATTRIBUTES).equals("true")) { + dynamicAttributes.putAll(policy.getDynamicAttributes()); + for (Attribute attribute : dynamicAttributes.values()) { + if (attribute.getOnInvalid().equals(REMOVE_TAG_ONINVALID_ACTION)) { + onInvalidRemoveTagList.add(attribute.getName()); + } + + List<Pattern> regexsFromAttribute = attribute.getPatternList(); + for (Pattern regex : regexsFromAttribute) { + dynamicAttributesPolicyMap.put(attribute.getName(), newDynamicAttributePolicy(regex)); + } + + List<String> allowedValuesFromAttribute = attribute.getLiterals(); + if (!allowedValuesFromAttribute.isEmpty()) { + dynamicAttributesPolicyMap.put(attribute.getName(), + newDynamicAttributePolicy(true, allowedValuesFromAttribute.toArray(new String[0]))); + } + + } + } + + policyFactory = policyBuilder.allowTextIn(CssValidator.STYLE_TAG_NAME).toFactory(); + + } + + public PolicyFactory getCustomPolicyFactory() { Review Comment: I would rename this to 'getHtmlCleanerPolicyFactory', because we use the word "policy" a lot, and this clarifies why a "Policy" class has a "getPolicyFactory" method. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
