diff --git a/CHANGELOG.md b/CHANGELOG.md index db5569cfa..38a24026e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1610,7 +1610,7 @@ * window memo object and markdown link render style ([70d0808](https://github.com/RSSNext/follow/commit/70d0808d75ad5ae754da3e84299566bbb55eec14)) * windows rounded left ([bf07c5e](https://github.com/RSSNext/follow/commit/bf07c5e2bfa740c02c6ca834e9935565098ca2a5)) * z-index ([d69df8b](https://github.com/RSSNext/follow/commit/d69df8bbacb159fb5bd5251a66c08fb58bec9d52)) - +* hotfix fix the bug of sanitizing that causes readability failed to fetch document content. ([db83710](https://github.com/RSSNext/follow/commit/db83710ee86eafa75052e80bc2c0e9927ea46560)) ### Features diff --git a/apps/main/src/lib/readability.ts b/apps/main/src/lib/readability.ts index e16a82b9d..3dfa9e177 100644 --- a/apps/main/src/lib/readability.ts +++ b/apps/main/src/lib/readability.ts @@ -8,6 +8,19 @@ import { isDev } from "~/env" const userAgents = `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 ${name}/${version}` +// For avoiding xss attack from readability, the raw document string should be sanitized. +// The xss attack in electron may lead to more serious outcomes than browser environment. +// It may allows remotely execute malicious scripts in main process. +// Before the sanitizing, the DOMPurify requires a `window` environment provided by linkedom. +function sanitizeHTMLString(dirtyDocumentString: string) { + const parser = parseHTML(dirtyDocumentString) + const purify = DOMPurify(parser.window) + // How do DOMPurify changes the origin html structure, + // You can refer its document https://github.com/cure53/DOMPurify?tab=readme-ov-file#can-i-configure-dompurify + const sanitizedDocumentString = purify.sanitize(dirtyDocumentString) + return sanitizedDocumentString +} + export async function readability(url: string) { const dirtyDocumentString = await fetch(url, { headers: { @@ -27,15 +40,13 @@ export async function readability(url: string) { return res.text() }) - // For avoid xss attack from readability, the raw document string should be purified. - const cleanedDocumentString = DOMPurify.sanitize(dirtyDocumentString) + const sanitizedDocumentString = sanitizeHTMLString(dirtyDocumentString) + const baseUrl = new URL(url).origin // FIXME: linkedom does not handle relative addresses in strings. Refer to // @see https://github.com/WebReflection/linkedom/issues/153 // JSDOM handles it correctly, but JSDOM introduces canvas binding. - - const { document } = parseHTML(cleanedDocumentString) - const baseUrl = new URL(url).origin + const { document } = parseHTML(sanitizedDocumentString) document.querySelectorAll("a").forEach((a) => { a.href = replaceRelativeAddress(baseUrl, a.href)