Markdown component improvement

Hello,

Well, I am trying to create help dialog using markdown and to include download link to some template. However then I press on link vaadin acts as if this link was not created. In general it would be even better to use target=“_blank” on the link, but I was not able to do that. For below example to work - please put any test.xlsx file in your src\main\resources\META-INF\resources\assets. Are were any workarounds? Maybe some improvements on framework level?

@Component
@Scope("prototype")
@Route(value = "md_test")
@AnonymousAllowed
public class MarkdownTest extends VerticalLayout {
    public MarkdownTest() {
        add(new Button("Test", e -> {
            new TestDialog(mdText).open();
        }));
    }

    class TestDialog extends Dialog {
        public TestDialog(String markdownText) {
            this.add(new Markdown(markdownText));

            this.setCloseOnEsc(true);
            this.setCloseOnOutsideClick(true);
            this.setWidth("700px");
            this.setHeight("500px");
        }
    }

    private static final String mdText = """
            ## Test 
            - <a href="http://localhost:8080/assets/test.xlsx" target="_blank">test1</a> 
            - [test2](http://localhost:8080/assets/test.xlsx) 
            - [test3 Kmarkdown](http://localhost:8080/assets/test.xlsx){:target="_blank"} 
            """;
}

You mean… it’s navigating within your application? If yes: you need to add “router-ignore” as attribute to the anchor… target=“_blank” should work

Yes, it is within application. I added router-ignore however behaviour didnt changed. Also target=“_blank” is not working, because it was ignored by framework. Please check screen shot.

public class MarkdownTest extends VerticalLayout {
    public MarkdownTest() {
        add(new Button("Test", e -> {
            new TestDialog(mdText).open();
        }));
    }

    class TestDialog extends Dialog {
        public TestDialog(String markdownText) {
            this.add(new Markdown(markdownText));

            this.setCloseOnEsc(true);
            this.setCloseOnOutsideClick(true);
            this.setWidth("700px");
            this.setHeight("500px");
        }
    }

    private static final String mdText = """
            ## Test 
            - <a href="http://localhost:8080/assets/test.xlsx" target="_blank">test1</a> 
            - <a router-ignore href="http://localhost:8080/assets/test.xlsx" target="_blank">test2</a> 
            - [test3](http://localhost:8080/assets/test.xlsx) 
            - [test4 Kmarkdown](http://localhost:8080/assets/test.xlsx){:target="_blank"} 
            """;
}

Now it looks like a bug that could be opened at the web-components repository on GitHub :grinning:

The Markdown component itself doesn’t do anything with links (or any other HTML for that matter), but it uses DOMPurify (GitHub - cure53/DOMPurify: DOMPurify - a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. DOMPurify works with a secure default, but offers a lot of configurability and hooks. Demo:) to sanitize the HTML. Perhaps there is something in the sanitization that, for whatever reason, strips target attributes. If so, there’s probably some way to configure it to not do that.

Ah, welp, apparently that was it: allow target="_blank"? · Issue #317 · cure53/DOMPurify · GitHub

So the Markdown component presumably then needs an API for configuring the sanitization.

@tomazzaz, before I create a ticket about this, could you try adding rel="noopener" to the link and see if that helps?

I added rel=“noopener” it passed to generated HTML <a rel="noopener" href="http://localhost:8080/assets/test.xlsx">test2</a> however the behaviour still the same. It is not working as expected

Welp, then it’s definitely being stripped by the XSS sanitizer.

Created an issue for either adding an API for configuring the sanitizer, or just applying that flag hardcoded by default: Markdown: API for configuring HTML sanitization · Issue #9799 · vaadin/web-components · GitHub

In other words, not a bug per se, but the XSS sanitizer being overly cautious about it for this reason: الروابط إلى وجهات مشتركة المصدر غير آمنة  |  Lighthouse  |  Chrome for Developers