Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HtmlSanitizerOptions #359

Merged
merged 14 commits into from
Jul 12, 2022
15 changes: 15 additions & 0 deletions src/HtmlSanitizer/HtmlSanitizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ public class HtmlSanitizer : IHtmlSanitizer

private static readonly HtmlParser defaultHtmlParser = new(new HtmlParserOptions(), BrowsingContext.New(defaultConfiguration));

/// <summary>
/// Initializes a new instance of the <see cref="HtmlSanitizer"/> class.
/// </summary>
/// <param name="options">Options to control the sanitizing.</param>
public HtmlSanitizer(HtmlSanitizerOptions options)
{
AllowedTags = options.AllowedTags;
AllowedSchemes = options.AllowedSchemes;
AllowedAttributes = options.AllowedAttributes;
UriAttributes = options.UriAttributes;
AllowedClasses = options.AllowedCssClasses;
AllowedCssProperties = options.AllowedCssProperties;
AllowedAtRules = options.AllowedAtRules;
}

/// <summary>
/// Initializes a new instance of the <see cref="HtmlSanitizer"/> class.
/// </summary>
Expand Down
47 changes: 47 additions & 0 deletions src/HtmlSanitizer/HtmlSanitizerOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using AngleSharp.Css.Dom;
using System;
using System.Collections.Generic;

namespace Ganss.XSS
{
/// <summary>
/// Provides options to be used with <see cref="HtmlSanitizer"/>.
/// </summary>
public class HtmlSanitizerOptions
{
/// <summary>
/// Gets or sets the allowed tag names such as "a" and "div".
/// </summary>
public ISet<string> AllowedTags { get; set; } = new HashSet<string>();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't these have private setters? Also, they should be initialized with StringComparer.OrdinalIgnoreCase.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I would want public setters because then I can easily assign a set to the properties using object initializer syntax. Without a setter, I would have to loop over a set and append each item in the set using the Add method.

Yes, it should probably be initialized with StringComparer.OrdinalIgnoreCase if we want it to be case-insensitive, which we probably do want.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use object and collection initializer syntax even if the setter is private. Collection initializer syntax works with the Add() method so you can do this:

public class SetTest
{
    public HashSet<string> Set { get; private set; } = new HashSet<string>();
}

var s = new SetTest()
{
    Set = { "a", "b" }
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. but you cannot assign from a predefined set like this:

public static class Presets
{
    public static HashSet<string> Default { get; } = new HashSet<string>();
}

var s = new SetTest()
{
    Set = Presets.Default
};

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, then how about making them init-only?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea! I like that!

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's this problem now. Not sure how to deal with it or if it's even worth it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems easier to just skip init and just have public setters instead.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah ok, I agree.


/// <summary>
/// Gets or sets the allowed HTML attributes such as "href" and "alt".
/// </summary>
public ISet<string> AllowedAttributes { get; set; } = new HashSet<string>();

/// <summary>
/// Gets or sets the allowed CSS classes.
/// </summary>
public ISet<string> AllowedCssClasses { get; set; } = new HashSet<string>();

/// <summary>
/// Gets or sets the allowed CSS properties such as "font" and "margin".
/// </summary>
public ISet<string> AllowedCssProperties { get; set; } = new HashSet<string>();

/// <summary>
/// Gets or sets the allowed CSS at-rules such as "@media" and "@font-face".
/// </summary>
public ISet<CssRuleType> AllowedAtRules { get; set; } = new HashSet<CssRuleType>();

/// <summary>
/// Gets or sets the allowed URI schemes such as "http" and "https".
/// </summary>
public ISet<string> AllowedSchemes { get; set; } = new HashSet<string>();

/// <summary>
/// Gets or sets the HTML attributes that can contain a URI such as "href".
/// </summary>
public ISet<string> UriAttributes { get; set; } = new HashSet<string>();
}
}