/** * Add allowed URL protocols for an element's URL attribute. This restricts the possible values of * the attribute to URLs with the defined protocol. * * <p>E.g.: <code>addProtocols("a", "href", "ftp", "http", "https")</code> * * @param tag Tag the URL protocol is for * @param key Attribute key * @param protocols List of valid protocols * @return this, for chaining */ public Whitelist addProtocols(String tag, String key, String... protocols) { Validate.notEmpty(tag); Validate.notEmpty(key); Validate.notNull(protocols); TagName tagName = TagName.valueOf(tag); AttributeKey attrKey = AttributeKey.valueOf(key); Map<AttributeKey, Set<Protocol>> attrMap; Set<Protocol> protSet; if (this.protocols.containsKey(tagName)) { attrMap = this.protocols.get(tagName); } else { attrMap = new HashMap<AttributeKey, Set<Protocol>>(); this.protocols.put(tagName, attrMap); } if (attrMap.containsKey(attrKey)) { protSet = attrMap.get(attrKey); } else { protSet = new HashSet<Protocol>(); attrMap.put(attrKey, protSet); } for (String protocol : protocols) { Validate.notEmpty(protocol); Protocol prot = Protocol.valueOf(protocol); protSet.add(prot); } return this; }
/** * Add a list of allowed elements to a whitelist. (If a tag is not allowed, it will be removed * from the HTML.) * * @param tags tag names to allow * @return this (for chaining) */ public Whitelist addTags(String... tags) { Validate.notNull(tags); for (String tagName : tags) { Validate.notEmpty(tagName); tagNames.add(TagName.valueOf(tagName)); } return this; }
Attributes getEnforcedAttributes(String tagName) { Attributes attrs = new Attributes(); TagName tag = TagName.valueOf(tagName); if (enforcedAttributes.containsKey(tag)) { Map<AttributeKey, AttributeValue> keyVals = enforcedAttributes.get(tag); for (Map.Entry<AttributeKey, AttributeValue> entry : keyVals.entrySet()) { attrs.put(entry.getKey().toString(), entry.getValue().toString()); } } return attrs; }
/** * Test if the supplied attribute is allowed by this whitelist for this tag * * @param tagName tag to consider allowing the attribute in * @param el element under test, to confirm protocol * @param attr attribute under test * @return true if allowed */ protected boolean isSafeAttribute(String tagName, Element el, Attribute attr) { TagName tag = TagName.valueOf(tagName); AttributeKey key = AttributeKey.valueOf(attr.getKey()); if (attributes.containsKey(tag)) { if (attributes.get(tag).contains(key)) { if (protocols.containsKey(tag)) { Map<AttributeKey, Set<Protocol>> attrProts = protocols.get(tag); // ok if not defined protocol; otherwise test return !attrProts.containsKey(key) || testValidProtocol(el, attr, attrProts.get(key)); } else { // attribute found, no protocols defined, so OK return true; } } } // no attributes defined for tag, try :all tag return !tagName.equals(":all") && isSafeAttribute(":all", el, attr); }
/** * Add an enforced attribute to a tag. An enforced attribute will always be added to the element. * If the element already has the attribute set, it will be overridden. * * <p>E.g.: <code>addEnforcedAttribute("a", "rel", "nofollow")</code> will make all <code>a</code> * tags output as <code><a href="..." rel="nofollow"></code> * * @param tag The tag the enforced attribute is for. The tag will be added to the allowed tag list * if necessary. * @param key The attribute key * @param value The enforced attribute value * @return this (for chaining) */ public Whitelist addEnforcedAttribute(String tag, String key, String value) { Validate.notEmpty(tag); Validate.notEmpty(key); Validate.notEmpty(value); TagName tagName = TagName.valueOf(tag); if (!tagNames.contains(tagName)) tagNames.add(tagName); AttributeKey attrKey = AttributeKey.valueOf(key); AttributeValue attrVal = AttributeValue.valueOf(value); if (enforcedAttributes.containsKey(tagName)) { enforcedAttributes.get(tagName).put(attrKey, attrVal); } else { Map<AttributeKey, AttributeValue> attrMap = new HashMap<AttributeKey, AttributeValue>(); attrMap.put(attrKey, attrVal); enforcedAttributes.put(tagName, attrMap); } return this; }
/** * Add a list of allowed attributes to a tag. (If an attribute is not allowed on an element, it * will be removed.) * * <p>E.g.: <code>addAttributes("a", "href", "class")</code> allows <code>href</code> and <code> * class</code> attributes on <code>a</code> tags. * * <p>To make an attribute valid for <b>all tags</b>, use the pseudo tag <code>:all</code>, e.g. * <code>addAttributes(":all", "class")</code>. * * @param tag The tag the attributes are for. The tag will be added to the allowed tag list if * necessary. * @param keys List of valid attributes for the tag * @return this (for chaining) */ public Whitelist addAttributes(String tag, String... keys) { Validate.notEmpty(tag); Validate.notNull(keys); Validate.isTrue(keys.length > 0, "No attributes supplied."); TagName tagName = TagName.valueOf(tag); if (!tagNames.contains(tagName)) tagNames.add(tagName); Set<AttributeKey> attributeSet = new HashSet<AttributeKey>(); for (String key : keys) { Validate.notEmpty(key); attributeSet.add(AttributeKey.valueOf(key)); } if (attributes.containsKey(tagName)) { Set<AttributeKey> currentSet = attributes.get(tagName); currentSet.addAll(attributeSet); } else { attributes.put(tagName, attributeSet); } return this; }
/** * Test if the supplied tag is allowed by this whitelist * * @param tag test tag * @return true if allowed */ protected boolean isSafeTag(String tag) { return tagNames.contains(TagName.valueOf(tag)); }