mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-30 16:16:19 +00:00
fix: keep an Outlook-style reply from loading the quoted message's remote images
This commit is contained in:
@@ -6,6 +6,30 @@ import { buildQuotedHtmlBlock, QuotedHtml, serializeEditorContent } from '../quo
|
||||
const createEditor = (content: string) => new Editor({ extensions: [StarterKit, QuotedHtml], content });
|
||||
|
||||
describe('HTML quote borders', () => {
|
||||
it('flattens quotes without parsing the original into the page, where its images would load', () => {
|
||||
// A browser fetches an <img> as soon as it is parsed into an element of
|
||||
// the live document, attached or not: that fires the tracker the remote
|
||||
// content setting holds back.
|
||||
const descriptor = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML')!;
|
||||
const liveParses: string[] = [];
|
||||
Object.defineProperty(Element.prototype, 'innerHTML', {
|
||||
...descriptor,
|
||||
set(this: Element, value: string) {
|
||||
if (this.ownerDocument === document && this.tagName !== 'TEMPLATE') liveParses.push(value);
|
||||
descriptor.set!.call(this, value);
|
||||
},
|
||||
});
|
||||
let html = '';
|
||||
try {
|
||||
html = buildQuotedHtmlBlock('<blockquote><img src="https://tracker.example/p.png">Hi</blockquote>', { showQuoteBorder: false });
|
||||
} finally {
|
||||
Object.defineProperty(Element.prototype, 'innerHTML', descriptor);
|
||||
}
|
||||
expect(liveParses.filter((value) => value.includes('tracker.example'))).toEqual([]);
|
||||
expect(html).toContain('<img src="https://tracker.example/p.png">');
|
||||
expect(html).not.toContain('blockquote');
|
||||
});
|
||||
|
||||
it('keeps normal quote styling by default', () => {
|
||||
const original = '<blockquote>Original reply</blockquote>';
|
||||
const editor = createEditor(buildQuotedHtmlBlock(original));
|
||||
|
||||
@@ -303,14 +303,17 @@ export function buildQuotedHtmlBlock(
|
||||
if (!showQuoteBorder) {
|
||||
// Outlook-style replies flatten quote levels, including earlier replies.
|
||||
// Work on sanitized DOM so tables, links and signatures remain intact.
|
||||
const container = document.createElement("div");
|
||||
// A template's content is inert: parsed into a plain div, the original's
|
||||
// remote images would load here, past the parking the island does.
|
||||
const container = document.createElement("template");
|
||||
container.innerHTML = html;
|
||||
container.querySelectorAll("blockquote").forEach((quote) => {
|
||||
const block = document.createElement("div");
|
||||
const content = container.content;
|
||||
content.querySelectorAll("blockquote").forEach((quote) => {
|
||||
const block = content.ownerDocument.createElement("div");
|
||||
block.append(...Array.from(quote.childNodes));
|
||||
quote.replaceWith(block);
|
||||
});
|
||||
container.querySelectorAll<HTMLElement>(`[${QUOTED_HTML_MARKER}]`).forEach((quote) => {
|
||||
content.querySelectorAll<HTMLElement>(`[${QUOTED_HTML_MARKER}]`).forEach((quote) => {
|
||||
quote.setAttribute("data-quote-border", "false");
|
||||
quote.style.borderLeft = "none";
|
||||
quote.style.paddingLeft = "0";
|
||||
|
||||
Reference in New Issue
Block a user