I am making an email client for blind people (well, legally blind anyways), and I am trying to render the HTML body for the emails, in a safe way, but without losing the style of the original content. I also want all the content to have increased the size of everything, especially the text.
I would recommend using an iframe
which can prevent script execution via the sandbox
attribute. You can add additional styling to set a specific root font size, though this may not work as expected depending on the mail's own styling.
<script>
let mail = `
<h1>Title</h1>
Lorem ipsum dolor sit
<!-- Svelte parser does not like additional script tags. -->
<${''}script>alert('!')</${''}script>
`;
$: document = mail + `
<style>
html, body { font-size: 32px; }
</style>
`
</script>
<iframe srcdoc={document} title="Mail message" sandbox />
<style>
iframe {
border: none;
width: 100%;
height: 100%;
}
</style>
As an alternative to the font size, the whole frame can be scaled up using a transform, its size has to be reduced proportionally:
iframe {
border: none;
width: calc(100% / 2);
height: calc(100% / 2);
transform-origin: 0 0;
transform: scale(2);
}
If you need more direct access to the the generated content, e.g. via events, you can instead sanitize the HTML using one of the various libraries out there (e.g. xss
or sanitize-html
). The HTML can then be inserted using {@html ...}
.
To handle a click on a link, you can wrap the content in an element and handle the click there, checking whether the target
was a link element.
<script>
let mail = `
<h1>Title</h1>
<a href="http://stackoverflow.com">Stack Overflow</a>
`;
function sanitize(html) {
// Use some sanitizer package here
return html;
}
function onClick(e) {
if (e.target.tagName == 'A') {
e.preventDefault();
alert('Links to: ' + e.target.href);
}
}
</script>
<div class="container" on:click={onClick}>
{@html sanitize(mail)}
</div>
<style>
.container {
border: none;
width: calc(100% / 2);
height: calc(100% / 2);
transform-origin: 0 0;
transform: scale(2);
}
</style>
(Sanitization omitted, because the mentioned packages are not compatible with the REPL.)