Repository: apostrophecms/sanitize-html (js)

Issue:
Setting allwedClasses for "*" tag allows all classes, regardless of the filter
```js
sanitize('<span class="not-allowed">Text</span>', {
        allowedTags: [...sanitize.defaults.allowedTags, 'span'],
        allowedClasses: {
            '*': ['allowed'],
        },
    })
```
#### Expected:
```html
<span>Text</span>
```
#### Actual:
```html
<span class="not-allowed"></span>
```
This does not happen when `span` instead of `'*'` is used as the tag name for `allowedClasses`.

Pull request description:
Wildcard support for allowedClasses
This should fix #253.

Patch:
diff --git a/README.md b/README.md
index 063773c..eb9735d 100644
--- a/README.md
+++ b/README.md
@@ -218,6 +218,13 @@ const clean = sanitizeHtml(dirty, {
 });
 ```
 
+Similar to `allowedAttributes`, you can use `*` as a tag name, to allow listed classes to be valid for any tag:
+```js
+allowedClasses: {
+  '*': [ 'fancy', 'simple' ]
+}
+```
+
 ### Allowed CSS Styles
 
 If you wish to allow specific CSS _styles_ on a particular element, you can do that with the `allowedStyles` option. Simply declare your desired attributes as regular expression options within an array for the given attribute. Specific elements will inherit whitelisted attributes from the global (\*) attribute. Any other CSS classes are discarded.
diff --git a/index.js b/index.js
index 5bb16bc..6b7b6cc 100644
--- a/index.js
+++ b/index.js
@@ -370,7 +370,13 @@ function sanitizeHtml(html, options, _recursing) {
               }
             }
             if (a === 'class') {
-              value = filterClasses(value, allowedClassesMap[name]);
+              const allowedSpecificClasses = allowedClassesMap[name];
+              const allowedWildcardClasses = allowedClassesMap['*'];
+              if (allowedSpecificClasses && allowedWildcardClasses) {
+                value = filterClasses(value, deepmerge(allowedSpecificClasses, allowedWildcardClasses));
+              } else {
+                value = filterClasses(value, allowedSpecificClasses || allowedWildcardClasses);
+              }
               if (!value.length) {
                 delete frame.attribs[a];
                 return;


Test patch:
diff --git a/test/test.js b/test/test.js
index 2732f02..1ab818c 100644
--- a/test/test.js
+++ b/test/test.js
@@ -340,7 +340,7 @@ describe('sanitizeHtml', function() {
       '<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />'
     );
   });
-  it('should allow specific classes when whitelisted with allowedClasses', function() {
+  it('should allow specific classes when whitelisted with allowedClasses for a single tag', function() {
     assert.equal(
       sanitizeHtml(
         '<p class="nifty simple dippy">whee</p>',
@@ -354,6 +354,36 @@ describe('sanitizeHtml', function() {
       '<p class="nifty">whee</p>'
     );
   });
+  it('should allow specific classes when whitelisted with allowedClasses for all tags', function() {
+    assert.equal(
+      sanitizeHtml(
+        '<p class="nifty simple dippy">whee</p><div class="dippy nifty simple"></div>',
+        {
+          allowedTags: [ 'p', 'div' ],
+          allowedClasses: {
+            '*': [ 'nifty' ]
+          }
+        }
+      ),
+      '<p class="nifty">whee</p><div class="nifty"></div>'
+    );
+  });
+  it('should allow all classes that are whitelisted for a single tag or all tags', function() {
+    assert.equal(
+      sanitizeHtml(
+        '<p class="nifty simple dippy">whee</p><div class="simple dippy nifty"></div>',
+        {
+          allowedTags: [ 'p', 'div' ],
+          allowedClasses: {
+            '*': [ 'simple' ],
+            p: [ 'nifty' ],
+            div: [ 'dippy' ]
+          }
+        }
+      ),
+      '<p class="nifty simple">whee</p><div class="simple dippy"></div>'
+    );
+  });
   it('should allow defining schemes on a per-tag basis', function() {
     assert.equal(
       sanitizeHtml(