diff --git a/packages/ui-services/src/Import/EvernoteConverter/EvernoteConverter.ts b/packages/ui-services/src/Import/EvernoteConverter/EvernoteConverter.ts index f19fc7b143e..e377e4a1c6b 100644 --- a/packages/ui-services/src/Import/EvernoteConverter/EvernoteConverter.ts +++ b/packages/ui-services/src/Import/EvernoteConverter/EvernoteConverter.ts @@ -388,15 +388,23 @@ export class EvernoteConverter implements Converter { } stripHTML(html: string) { - const tmp = document.createElement('html') - tmp.innerHTML = html - return tmp.textContent || tmp.innerText || '' + const doc = new DOMParser().parseFromString(html, 'text/html') + return doc.body.textContent || '' } } function changeElementTag(element: HTMLElement, newTag: string) { - const attributes = Array.prototype.slice.call(element.attributes) - element.outerHTML = `<${newTag} ${attributes.map((attr) => attr.name + '="' + attr.value + '"').join(' ')}>${ - element.innerHTML - }` + const doc = element.ownerDocument + const parent = element.parentElement + if (!parent) { + return + } + const replacement = doc.createElement(newTag) + for (const attr of Array.from(element.attributes)) { + replacement.setAttribute(attr.name, attr.value) + } + while (element.firstChild) { + replacement.appendChild(element.firstChild) + } + parent.replaceChild(replacement, element) } diff --git a/packages/ui-services/src/Import/GoogleKeepConverter/GoogleKeepConverter.ts b/packages/ui-services/src/Import/GoogleKeepConverter/GoogleKeepConverter.ts index 5f11f5da516..00acfa51088 100644 --- a/packages/ui-services/src/Import/GoogleKeepConverter/GoogleKeepConverter.ts +++ b/packages/ui-services/src/Import/GoogleKeepConverter/GoogleKeepConverter.ts @@ -74,8 +74,8 @@ export class GoogleKeepConverter implements Converter { convertHTMLToSuper: HTMLToSuperConverterFunction, canUseSuper: boolean, ): Promise { - const rootElement = document.createElement('html') - rootElement.innerHTML = data + const doc = new DOMParser().parseFromString(data, 'text/html') + const rootElement = doc.documentElement const headingElement = rootElement.getElementsByClassName('heading')[0] const parsedDate = new Date(headingElement?.textContent || '') @@ -110,8 +110,9 @@ export class GoogleKeepConverter implements Converter { }) if (!canUseSuper) { - // Replace
with \n so line breaks get recognised - contentElement.innerHTML = contentElement.innerHTML.replace(/
/g, '\n') + Array.from(contentElement.querySelectorAll('br')).forEach((br) => { + br.replaceWith(doc.createTextNode('\n')) + }) content = contentElement.textContent } else { content = convertHTMLToSuper(rootElement.innerHTML, { diff --git a/packages/ui-services/src/Import/ImportLimits.spec.ts b/packages/ui-services/src/Import/ImportLimits.spec.ts new file mode 100644 index 00000000000..b25b4b0a862 --- /dev/null +++ b/packages/ui-services/src/Import/ImportLimits.spec.ts @@ -0,0 +1,15 @@ +import { assertImportFileWithinSizeLimit, MaxImportFileSizeBytes } from './ImportLimits' + +describe('ImportLimits', () => { + it('rejects files over the configured limit', () => { + const file = new File(['x'], 'note.html', { type: 'text/html' }) + Object.defineProperty(file, 'size', { value: MaxImportFileSizeBytes + 1 }) + expect(() => assertImportFileWithinSizeLimit(file)).toThrow('Import file is too large') + }) + + it('allows files at or below max import size', () => { + const file = new File(['x'], 'note.html', { type: 'text/html' }) + Object.defineProperty(file, 'size', { value: MaxImportFileSizeBytes }) + expect(() => assertImportFileWithinSizeLimit(file)).not.toThrow() + }) +}) diff --git a/packages/ui-services/src/Import/ImportLimits.ts b/packages/ui-services/src/Import/ImportLimits.ts new file mode 100644 index 00000000000..bd8d04a3094 --- /dev/null +++ b/packages/ui-services/src/Import/ImportLimits.ts @@ -0,0 +1,7 @@ +export const MaxImportFileSizeBytes = 50 * 1_000_000 + +export function assertImportFileWithinSizeLimit(file: File): void { + if (file.size > MaxImportFileSizeBytes) { + throw new Error('Import file is too large') + } +} diff --git a/packages/ui-services/src/Import/Importer.ts b/packages/ui-services/src/Import/Importer.ts index a8af94e8da0..9a5c0485706 100644 --- a/packages/ui-services/src/Import/Importer.ts +++ b/packages/ui-services/src/Import/Importer.ts @@ -12,6 +12,7 @@ import { EvernoteConverter } from './EvernoteConverter/EvernoteConverter' import { GoogleKeepConverter } from './GoogleKeepConverter/GoogleKeepConverter' import { PlaintextConverter } from './PlaintextConverter/PlaintextConverter' import { SimplenoteConverter } from './SimplenoteConverter/SimplenoteConverter' +import { assertImportFileWithinSizeLimit, MaxImportFileSizeBytes } from './ImportLimits' import { readFileAsText } from './Utils' import { DecryptedItemInterface, @@ -74,6 +75,9 @@ export class Importer { } detectService = async (file: File): Promise => { + if (file.size > MaxImportFileSizeBytes) { + return null + } const content = await readFileAsText(file) const { ext } = parseFileName(file.name) @@ -232,6 +236,8 @@ export class Importer { throw new Error('Importing Super notes requires a subscription') } + assertImportFileWithinSizeLimit(file) + const successful: ConversionResult['successful'] = [] const errored: ConversionResult['errored'] = []