18403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// Copyright (c) 2011, Mike Samuel 28403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// All rights reserved. 38403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// 48403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// Redistribution and use in source and binary forms, with or without 58403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// modification, are permitted provided that the following conditions 68403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// are met: 78403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// 88403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// Redistributions of source code must retain the above copyright 98403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// notice, this list of conditions and the following disclaimer. 108403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// Redistributions in binary form must reproduce the above copyright 118403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// notice, this list of conditions and the following disclaimer in the 128403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// documentation and/or other materials provided with the distribution. 138403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// Neither the name of the OWASP nor the names of its contributors may 148403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// be used to endorse or promote products derived from this software 158403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// without specific prior written permission. 168403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 178403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 188403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 198403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 208403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 218403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 228403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 238403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 248403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 258403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 268403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 278403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel// POSSIBILITY OF SUCH DAMAGE. 288403881c365ab36b721ccc4500af1b3a5bd25870mikesamuel 294e867904c8295537803c1c8a076e130df5674b58mikesamuelpackage org.owasp.html; 304e867904c8295537803c1c8a076e130df5674b58mikesamuel 314e867904c8295537803c1c8a076e130df5674b58mikesamuelimport java.util.List; 324e867904c8295537803c1c8a076e130df5674b58mikesamuel 334e867904c8295537803c1c8a076e130df5674b58mikesamuelimport javax.annotation.Nullable; 344e867904c8295537803c1c8a076e130df5674b58mikesamuelimport javax.annotation.concurrent.Immutable; 354e867904c8295537803c1c8a076e130df5674b58mikesamuel 364e867904c8295537803c1c8a076e130df5674b58mikesamuel/** 374e867904c8295537803c1c8a076e130df5674b58mikesamuel * A policy that can be applied to an element to decide whether or not to 384e867904c8295537803c1c8a076e130df5674b58mikesamuel * allow it in the output, possibly after transforming attributes. 394e867904c8295537803c1c8a076e130df5674b58mikesamuel * <p> 404e867904c8295537803c1c8a076e130df5674b58mikesamuel * Element policies are applied <strong>after</strong> 414e867904c8295537803c1c8a076e130df5674b58mikesamuel * {@link AttributePolicy attribute policies} so 424e867904c8295537803c1c8a076e130df5674b58mikesamuel * they can be used to add extra attributes. 434e867904c8295537803c1c8a076e130df5674b58mikesamuel * 446d8c2e9241d042a3e0bff40dac4c388966ad060cmikesamuel * @author Mike Samuel <mikesamuel@gmail.com> 454e867904c8295537803c1c8a076e130df5674b58mikesamuel * @see HtmlPolicyBuilder#allowElements(ElementPolicy, String...) 464e867904c8295537803c1c8a076e130df5674b58mikesamuel */ 474e867904c8295537803c1c8a076e130df5674b58mikesamuel@TCB public interface ElementPolicy { 484e867904c8295537803c1c8a076e130df5674b58mikesamuel /** 494e867904c8295537803c1c8a076e130df5674b58mikesamuel * @param elementName the lower-case element name. 504e867904c8295537803c1c8a076e130df5674b58mikesamuel * @param attrs a list of alternating attribute names and values. 514e867904c8295537803c1c8a076e130df5674b58mikesamuel * The list may be added to or removed from. When removing, be 524e867904c8295537803c1c8a076e130df5674b58mikesamuel * careful to remove both the name and its associated value. 534e867904c8295537803c1c8a076e130df5674b58mikesamuel * 544e867904c8295537803c1c8a076e130df5674b58mikesamuel * @return {@code null} to disallow the element, or the adjusted element name. 554e867904c8295537803c1c8a076e130df5674b58mikesamuel */ 564e867904c8295537803c1c8a076e130df5674b58mikesamuel public @Nullable String apply(String elementName, List<String> attrs); 574e867904c8295537803c1c8a076e130df5674b58mikesamuel 584e867904c8295537803c1c8a076e130df5674b58mikesamuel 594e867904c8295537803c1c8a076e130df5674b58mikesamuel /** Utilities for working with element policies. */ 604e867904c8295537803c1c8a076e130df5674b58mikesamuel public static final class Util { 614e867904c8295537803c1c8a076e130df5674b58mikesamuel private Util() { /* uninstantiable */ } 624e867904c8295537803c1c8a076e130df5674b58mikesamuel 634e867904c8295537803c1c8a076e130df5674b58mikesamuel /** 644e867904c8295537803c1c8a076e130df5674b58mikesamuel * Given zero or more element policies, returns an element policy equivalent 654e867904c8295537803c1c8a076e130df5674b58mikesamuel * to applying them in order failing early if any of them fails. 664e867904c8295537803c1c8a076e130df5674b58mikesamuel */ 674e867904c8295537803c1c8a076e130df5674b58mikesamuel public static final ElementPolicy join(ElementPolicy... policies) { 684e867904c8295537803c1c8a076e130df5674b58mikesamuel 694e867904c8295537803c1c8a076e130df5674b58mikesamuel class PolicyJoiner { 704e867904c8295537803c1c8a076e130df5674b58mikesamuel ElementPolicy last = null; 714e867904c8295537803c1c8a076e130df5674b58mikesamuel ElementPolicy out = null; 724e867904c8295537803c1c8a076e130df5674b58mikesamuel 734e867904c8295537803c1c8a076e130df5674b58mikesamuel void join(ElementPolicy p) { 744e867904c8295537803c1c8a076e130df5674b58mikesamuel if (p == REJECT_ALL_ELEMENT_POLICY) { 754e867904c8295537803c1c8a076e130df5674b58mikesamuel out = p; 764e867904c8295537803c1c8a076e130df5674b58mikesamuel } else if (out != REJECT_ALL_ELEMENT_POLICY) { 774e867904c8295537803c1c8a076e130df5674b58mikesamuel if (p instanceof JoinedElementPolicy) { 784e867904c8295537803c1c8a076e130df5674b58mikesamuel JoinedElementPolicy jep = (JoinedElementPolicy) p; 794e867904c8295537803c1c8a076e130df5674b58mikesamuel join(jep.first); 804e867904c8295537803c1c8a076e130df5674b58mikesamuel join(jep.second); 814e867904c8295537803c1c8a076e130df5674b58mikesamuel } else if (p != last) { 824e867904c8295537803c1c8a076e130df5674b58mikesamuel last = p; 834e867904c8295537803c1c8a076e130df5674b58mikesamuel if (out == null || out == IDENTITY_ELEMENT_POLICY) { 844e867904c8295537803c1c8a076e130df5674b58mikesamuel out = p; 854e867904c8295537803c1c8a076e130df5674b58mikesamuel } else if (p != IDENTITY_ELEMENT_POLICY) { 864e867904c8295537803c1c8a076e130df5674b58mikesamuel out = new JoinedElementPolicy(out, p); 874e867904c8295537803c1c8a076e130df5674b58mikesamuel } 884e867904c8295537803c1c8a076e130df5674b58mikesamuel } 894e867904c8295537803c1c8a076e130df5674b58mikesamuel } 904e867904c8295537803c1c8a076e130df5674b58mikesamuel } 914e867904c8295537803c1c8a076e130df5674b58mikesamuel } 924e867904c8295537803c1c8a076e130df5674b58mikesamuel 934e867904c8295537803c1c8a076e130df5674b58mikesamuel PolicyJoiner pu = new PolicyJoiner(); 944e867904c8295537803c1c8a076e130df5674b58mikesamuel for (ElementPolicy policy : policies) { 954e867904c8295537803c1c8a076e130df5674b58mikesamuel if (policy == null) { continue; } 964e867904c8295537803c1c8a076e130df5674b58mikesamuel pu.join(policy); 974e867904c8295537803c1c8a076e130df5674b58mikesamuel } 984e867904c8295537803c1c8a076e130df5674b58mikesamuel return pu.out != null ? pu.out : IDENTITY_ELEMENT_POLICY; 994e867904c8295537803c1c8a076e130df5674b58mikesamuel } 1004e867904c8295537803c1c8a076e130df5674b58mikesamuel 1014e867904c8295537803c1c8a076e130df5674b58mikesamuel } 1024e867904c8295537803c1c8a076e130df5674b58mikesamuel 1034e867904c8295537803c1c8a076e130df5674b58mikesamuel public static final ElementPolicy IDENTITY_ELEMENT_POLICY 1044e867904c8295537803c1c8a076e130df5674b58mikesamuel = new ElementPolicy() { 1054e867904c8295537803c1c8a076e130df5674b58mikesamuel public String apply(String elementName, List<String> attrs) { 1064e867904c8295537803c1c8a076e130df5674b58mikesamuel return elementName; 1074e867904c8295537803c1c8a076e130df5674b58mikesamuel } 1084e867904c8295537803c1c8a076e130df5674b58mikesamuel }; 1094e867904c8295537803c1c8a076e130df5674b58mikesamuel 1104e867904c8295537803c1c8a076e130df5674b58mikesamuel public static final ElementPolicy REJECT_ALL_ELEMENT_POLICY 1114e867904c8295537803c1c8a076e130df5674b58mikesamuel = new ElementPolicy() { 1124e867904c8295537803c1c8a076e130df5674b58mikesamuel public @Nullable String apply(String elementName, List<String> attrs) { 1134e867904c8295537803c1c8a076e130df5674b58mikesamuel return null; 1144e867904c8295537803c1c8a076e130df5674b58mikesamuel } 1154e867904c8295537803c1c8a076e130df5674b58mikesamuel }; 1164e867904c8295537803c1c8a076e130df5674b58mikesamuel 1174e867904c8295537803c1c8a076e130df5674b58mikesamuel} 1184e867904c8295537803c1c8a076e130df5674b58mikesamuel 1194e867904c8295537803c1c8a076e130df5674b58mikesamuel@Immutable 1204e867904c8295537803c1c8a076e130df5674b58mikesamuelfinal class JoinedElementPolicy implements ElementPolicy { 1214e867904c8295537803c1c8a076e130df5674b58mikesamuel final ElementPolicy first, second; 1224e867904c8295537803c1c8a076e130df5674b58mikesamuel 1234e867904c8295537803c1c8a076e130df5674b58mikesamuel JoinedElementPolicy(ElementPolicy first, ElementPolicy second) { 1244e867904c8295537803c1c8a076e130df5674b58mikesamuel this.first = first; 1254e867904c8295537803c1c8a076e130df5674b58mikesamuel this.second = second; 1264e867904c8295537803c1c8a076e130df5674b58mikesamuel } 1274e867904c8295537803c1c8a076e130df5674b58mikesamuel 1284e867904c8295537803c1c8a076e130df5674b58mikesamuel public @Nullable String apply(String elementName, List<String> attrs) { 1294e867904c8295537803c1c8a076e130df5674b58mikesamuel elementName = first.apply(elementName, attrs); 1304e867904c8295537803c1c8a076e130df5674b58mikesamuel return elementName != null ? second.apply(elementName, attrs) : null; 1314e867904c8295537803c1c8a076e130df5674b58mikesamuel } 1324e867904c8295537803c1c8a076e130df5674b58mikesamuel} 133