/// <summary>Invokes the CSS parser on the element.</summary> /// <param name="node">The <see cref="HtmlNode"/> to scan.</param> /// <param name="parentNode">The parent of the node.</param> /// <returns><see langword="true"/> if processing ended with no exceptions.</returns> private bool ProcessStyleTag(HtmlNode node, HtmlNode parentNode) { var styleScanner = new CssScanner(Policy); try { CleanResults cleanStyleSheet = styleScanner.ScanStyleSheet(node.FirstChild.InnerHtml); errorMessages.AddRange(cleanStyleSheet.GetErrorMessages()); /* * If IE gets an empty style tag, i.e. <style/> it will break all CSS on the page. I wish I * was kidding. So, if after validation no CSS properties are left, we would normally be left * with an empty style tag and break all CSS. To prevent that, we have this check. */ string cleanHtml = cleanStyleSheet.GetCleanHtml(); node.FirstChild.InnerHtml = string.IsNullOrEmpty(cleanHtml) ? EMPTY_CSS_COMMENT : cleanHtml; } catch (Exception exc) { if (exc is ScanException || exc is ParseException) { AddError(Constants.ERROR_CSS_TAG_MALFORMED, HtmlEntityEncoder.HtmlEntityEncode(node.FirstChild.InnerHtml)); parentNode.RemoveChild(node); return(false); } else { throw; } } return(true); }
public void TestMessageInSupportedCulture() { foreach (string cultureName in Constants.SUPPORTED_LANGUAGES.Union(new List <string> { "en-US", "es-UY" })) { string message = null; try { policy.Should().NotBeNull(); antisamy.SetCulture(cultureName); CleanResults results = antisamy.Scan("<unknowntag>", policy); results.GetNumberOfErrors().Should().Be(1); message = results.GetErrorMessages().First(); } catch { // To comply with try/catch } message.Should().NotBeNull(because: $"\"{cultureName}\" should be a valid culture and have an associated message."); } }
private bool ProcessAttributes(HtmlNode node, Tag tag) { string tagName = tag.Name; int currentAttributeIndex = 0; while (currentAttributeIndex < node.Attributes.Count) { HtmlAttribute htmlAttribute = node.Attributes[currentAttributeIndex]; string name = htmlAttribute.Name; string value = htmlAttribute.Value; Attribute attribute = tag.GetAttributeByName(name); if (attribute == null) { attribute = Policy.GetGlobalAttributeByName(name); // Not a global attribute, perhaps it is a dynamic attribute, if allowed. if (attribute == null && Policy.AllowsDynamicAttributes) { attribute = Policy.GetDynamicAttributeByName(name); } } if (name.ToLowerInvariant() == "style" && attribute != null) { var styleScanner = new CssScanner(Policy); try { CleanResults cleanInlineStyle = styleScanner.ScanInlineStyle(value, tagName); htmlAttribute.Value = cleanInlineStyle.GetCleanHtml(); errorMessages.AddRange(cleanInlineStyle.GetErrorMessages()); } catch (Exception exc) { if (exc is ScanException || exc is ParseException) { AddError(Constants.ERROR_CSS_ATTRIBUTE_MALFORMED, HtmlEntityEncoder.HtmlEntityEncode(value), HtmlEntityEncoder.HtmlEntityEncode(tagName)); node.Attributes.Remove(name); currentAttributeIndex--; } else { throw; } } } else { if (attribute != null) { value = HtmlEntity.DeEntitize(value); string lowerCaseValue = value.ToLowerInvariant(); bool isAttributeValid = attribute.AllowedValues.Any(v => v != null && v.ToLowerInvariant() == lowerCaseValue) || attribute.AllowedRegExp.Any(r => r != null && Regex.IsMatch(value, "^" + r + "$")); if (!isAttributeValid) { string onInvalidAction = attribute.OnInvalid; if (onInvalidAction == "removeTag") { RemoveNode(node); AddError(Constants.ERROR_ATTRIBUTE_INVALID_REMOVED, HtmlEntityEncoder.HtmlEntityEncode(tagName), HtmlEntityEncoder.HtmlEntityEncode(name), HtmlEntityEncoder.HtmlEntityEncode(value)); } else if (onInvalidAction == "filterTag") { // Remove the node and move up the rest that was inside the tag after processing ProcessChildren(node); PromoteChildren(node); AddError(Constants.ERROR_ATTRIBUTE_CAUSE_FILTER, HtmlEntityEncoder.HtmlEntityEncode(tagName), HtmlEntityEncoder.HtmlEntityEncode(name), HtmlEntityEncoder.HtmlEntityEncode(value)); } else if (onInvalidAction == "encodeTag") { // Encode the node and move up the rest that was inside the tag after processing ProcessChildren(node); EncodeAndPromoteChildren(node); AddError(Constants.ERROR_ATTRIBUTE_CAUSE_ENCODE, HtmlEntityEncoder.HtmlEntityEncode(tagName), HtmlEntityEncoder.HtmlEntityEncode(name), HtmlEntityEncoder.HtmlEntityEncode(value)); } else { // Just remove the attribute node.Attributes.Remove(attribute.Name); currentAttributeIndex--; AddError(Constants.ERROR_ATTRIBUTE_INVALID, HtmlEntityEncoder.HtmlEntityEncode(tagName), HtmlEntityEncoder.HtmlEntityEncode(name), HtmlEntityEncoder.HtmlEntityEncode(value)); } if (new string[] { "removeTag", "filterTag", "encodeTag" }.Contains(onInvalidAction)) { return(false); // Can't process any more if we remove/filter/encode the tag } } } else { AddError(Constants.ERROR_ATTRIBUTE_NOT_IN_POLICY, HtmlEntityEncoder.HtmlEntityEncode(tagName), HtmlEntityEncoder.HtmlEntityEncode(name), HtmlEntityEncoder.HtmlEntityEncode(value)); node.Attributes.Remove(name); currentAttributeIndex--; } } currentAttributeIndex++; } return(true); }