• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011, Mike Samuel
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 //
8 // Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // Neither the name of the OWASP nor the names of its contributors may
14 // be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 // COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
28 
29 package org.owasp.html;
30 
31 import java.util.List;
32 
33 import javax.annotation.Nullable;
34 import javax.annotation.concurrent.Immutable;
35 
36 /**
37  * A policy that can be applied to an element to decide whether or not to
38  * allow it in the output, possibly after transforming attributes.
39  * <p>
40  * Element policies are applied <strong>after</strong>
41  * {@link AttributePolicy attribute policies} so
42  * they can be used to add extra attributes.
43  *
44  * @author Mike Samuel <mikesamuel@gmail.com>
45  * @see HtmlPolicyBuilder#allowElements(ElementPolicy, String...)
46  */
47 @TCB public interface ElementPolicy {
48   /**
49    * @param elementName the lower-case element name.
50    * @param attrs a list of alternating attribute names and values.
51    *    The list may be added to or removed from.  When removing, be
52    *    careful to remove both the name and its associated value.
53    *
54    * @return {@code null} to disallow the element, or the adjusted element name.
55    */
apply(String elementName, List<String> attrs)56   public @Nullable String apply(String elementName, List<String> attrs);
57 
58 
59   /** Utilities for working with element policies. */
60   public static final class Util {
Util()61     private Util() { /* uninstantiable */ }
62 
63     /**
64      * Given zero or more element policies, returns an element policy equivalent
65      * to applying them in order failing early if any of them fails.
66      */
join(ElementPolicy... policies)67     public static final ElementPolicy join(ElementPolicy... policies) {
68 
69       class PolicyJoiner {
70         ElementPolicy last = null;
71         ElementPolicy out = null;
72 
73         void join(ElementPolicy p) {
74           if (p == REJECT_ALL_ELEMENT_POLICY) {
75             out = p;
76           } else if (out != REJECT_ALL_ELEMENT_POLICY) {
77             if (p instanceof JoinedElementPolicy) {
78               JoinedElementPolicy jep = (JoinedElementPolicy) p;
79               join(jep.first);
80               join(jep.second);
81             } else if (p != last) {
82               last = p;
83               if (out == null || out == IDENTITY_ELEMENT_POLICY) {
84                 out = p;
85               } else if (p != IDENTITY_ELEMENT_POLICY) {
86                 out = new JoinedElementPolicy(out, p);
87               }
88             }
89           }
90         }
91       }
92 
93       PolicyJoiner pu = new PolicyJoiner();
94       for (ElementPolicy policy : policies) {
95         if (policy == null) { continue; }
96         pu.join(policy);
97       }
98       return pu.out != null ? pu.out : IDENTITY_ELEMENT_POLICY;
99     }
100 
101   }
102 
103   public static final ElementPolicy IDENTITY_ELEMENT_POLICY
104       = new ElementPolicy() {
105     public String apply(String elementName, List<String> attrs) {
106       return elementName;
107     }
108   };
109 
110   public static final ElementPolicy REJECT_ALL_ELEMENT_POLICY
111       = new ElementPolicy() {
112     public @Nullable String apply(String elementName, List<String> attrs) {
113       return null;
114     }
115   };
116 
117 }
118 
119 @Immutable
120 final class JoinedElementPolicy implements ElementPolicy {
121   final ElementPolicy first, second;
122 
JoinedElementPolicy(ElementPolicy first, ElementPolicy second)123   JoinedElementPolicy(ElementPolicy first, ElementPolicy second) {
124     this.first = first;
125     this.second = second;
126   }
127 
apply(String elementName, List<String> attrs)128   public @Nullable String apply(String elementName, List<String> attrs) {
129     elementName = first.apply(elementName, attrs);
130     return elementName != null ? second.apply(elementName, attrs) : null;
131   }
132 }
133