LeSuisse/vue-dompurify-html

custom hook not preserving <use xlink:href="#sprite-...

Closed this issue · 5 comments

Hi,

I'm implementing vue-dompurify-html at version 2.5.0 and I've followed the Usage instructions and applied configurations from DomPurify in order to preserve the xlink attributes in the use tags of my svg's.

This is an example of my svg:

<svg aria-hidden="true" class="icon star"><use xlink:href="#sprite-star"/></svg>

These are my vue-dompurify-html configurations in my Vue component:

import Vue from 'vue';
import VueDOMPurifyHTML from 'vue-dompurify-html';

Vue.use(VueDOMPurifyHTML, {
    namedConfigurations: {
        svg: {
            ADD_TAGS: ['svg', 'use'],
            ADD_ATTR: ['xlink', 'xlink:href', 'href']
        }
    },
    hooks: {
        uponSanitizeElement: (node, data) => {
            if (data.tagName === 'use') {
                const link = node.getAttribute('xlink') || '';
                if (!link.startsWith('#sprite-')) {
                    return node.parentNode?.removeChild(node);
                }
            }
        }
    }
});

And this is how my html is purified:

<span v-dompurify-html:svg="productstar"/>

My configuration results in my svg being stripped from the use tag as follows:

<svg class="icon star" aria-hidden="true"></svg>

How can I preserve thie use with xlink attribute in my svg?

Hello,

I'm not sure this is an issue with vue-dompurify-html.

I did not test but according to cure53/DOMPurify#574 and cure53/DOMPurify#233 you might want to use the afterSanitizeAttributes hook.

Does not seem to do anything, it's like the added hook isn't being passed at all:

Vue.use(VueDOMPurifyHTML, {
    namedConfigurations: {
        svg: {
            ADD_TAGS: ['svg', 'use'],
            ADD_ATTR: ['xlink', 'xlink:href', 'href']
        }
    },
    hooks: {
        afterSanitizeAttributes: (node) => {
            if(!node.hasAttribute('xlink:href')){
                node.remove();
            }
        }
    }
});

Hi @LeSuisse many thanks for maintaining this plugin.
I tried debugging this more with @Tomjesch but the only thing that worked was by hooking directly into DOMPurify.

It doesn't work by adding the "afterSanitizeAttributes" to the VueDOMPurifyHTML hooks object.

Working solution:

import DOMPurify from 'dompurify';

DOMPurify.setConfig({
    ADD_TAGS: ['svg', 'use'],
    ADD_ATTRIBUTES: ['xlink', 'xlink:href', 'href']
});
DOMPurify.addHook('afterSanitizeAttributes', function (node) {
    if (node.hasAttribute('xlink:href') && !node.getAttribute('xlink:href').match(/^#/)) {
        node.remove();
    }
});
is2ei commented

@Tomjesch

You should get the attribute by xlink:href, not xlink.

Your code:

import Vue from 'vue';
import VueDOMPurifyHTML from 'vue-dompurify-html';

Vue.use(VueDOMPurifyHTML, {
    namedConfigurations: {
        svg: {
            ADD_TAGS: ['svg', 'use'],
            ADD_ATTR: ['xlink', 'xlink:href', 'href']
        }
    },
    hooks: {
        uponSanitizeElement: (node, data) => {
            if (data.tagName === 'use') {
                const link = node.getAttribute('xlink') || '';
                if (!link.startsWith('#sprite-')) {
                    return node.parentNode?.removeChild(node);
                }
            }
        }
    }
});

Correct code:

import Vue from 'vue';
import VueDOMPurifyHTML from 'vue-dompurify-html';

Vue.use(VueDOMPurifyHTML, {
    namedConfigurations: {
        svg: {
            ADD_TAGS: ['svg', 'use'],
            ADD_ATTR: ['xlink', 'xlink:href', 'href']
        }
    },
    hooks: {
        uponSanitizeElement: (node, data) => {
            if (data.tagName === 'use') {
                const link = node.getAttribute('xlink:href') || '';
                if (!link.startsWith('#sprite-')) {
                    return node.parentNode?.removeChild(node);
                }
            }
        }
    }
});

Thanks for the working snippet @is2ei.

I'm closing since this was not a a vue-dompurify-html issue but a DOMPurify config issue.

https://stackblitz.com/edit/vue-dompurify-html-issue-1721?file=main.ts