The render-time guard of the link mark was the only thing between a file's javascript: href and the page; the importers now read such a link as text.
34 lines
1.6 KiB
TypeScript
34 lines
1.6 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { importDocx } from '../../src/lib/import/docx';
|
|
import { importOdt } from '../../src/lib/import/odt';
|
|
import { buildDocx } from '../../src/lib/export/docx';
|
|
import { buildOdt } from '../../src/lib/export/odt';
|
|
|
|
// A file can carry any href; one with a scheme the editor would never open is read as
|
|
// plain text, so the boundary is the import and not a render-time guard.
|
|
type N = { type: string; attrs?: any; content?: N[]; marks?: any[]; text?: string };
|
|
|
|
function links(node: N, out: string[] = []): string[] {
|
|
for (const m of node.marks ?? []) if (m.type === 'link') out.push(m.attrs.href);
|
|
for (const c of node.content ?? []) links(c, out);
|
|
return out;
|
|
}
|
|
|
|
const doc: N = { type: 'doc', content: [{ type: 'paragraph', content: [
|
|
{ type: 'text', text: 'run', marks: [{ type: 'link', attrs: { href: 'javascript:alert(1)' } }] },
|
|
{ type: 'text', text: ' site', marks: [{ type: 'link', attrs: { href: 'https://example.com' } }] },
|
|
{ type: 'text', text: ' here', marks: [{ type: 'link', attrs: { href: '#top' } }] },
|
|
] }] };
|
|
const margins = { top: 2, bottom: 2, left: 2, right: 2 };
|
|
|
|
describe('a link with a scheme the editor never opens is dropped on import', () => {
|
|
it('through ODT', async () => {
|
|
const back = importOdt(await buildOdt(doc as any, margins, 'portrait')).content as unknown as N;
|
|
expect(links(back)).toEqual(['https://example.com', '#top']);
|
|
});
|
|
it('through DOCX', async () => {
|
|
const back = importDocx(await buildDocx(doc as any, margins, 'portrait')).content as unknown as N;
|
|
expect(links(back)).toEqual(['https://example.com', '#top']);
|
|
});
|
|
});
|