Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions src/app/components/editor/output.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,52 @@ describe('toMatrixCustomHTML emoticons', () => {
expect(html).toContain('height="32"');
});
});

describe('toMatrixCustomHTML matrix.to', () => {
it('serializes room mentions as raw matrix.to URL text, not an anchor', () => {
const html = trimCustomHtml(
toMatrixCustomHTML(
[
{
type: BlockType.Paragraph,
children: [
{
type: BlockType.Mention,
id: '!room:example.org',
name: 'My room',
children: [{ text: '' }],
} as never,
],
} as never,
],
{}
)
);

expect(html).toContain('https://matrix.to/#/!room:example.org');
expect(html).not.toMatch(/<a\b[^>]*matrix\.to/i);
});

it('serializes matrix.to links as raw URL text, not an anchor', () => {
const html = trimCustomHtml(
toMatrixCustomHTML(
[
{
type: BlockType.Paragraph,
children: [
{
type: BlockType.Link,
href: 'https://matrix.to/#/@alice:example.org',
children: [{ text: 'Alice' }],
} as never,
],
} as never,
],
{}
)
);

expect(html).toContain('https://matrix.to/#/@alice:example.org');
expect(html).not.toMatch(/<a\b[^>]*matrix\.to/i);
});
});
10 changes: 6 additions & 4 deletions src/app/components/editor/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { isUserId } from '$utils/matrix';
import type { CustomElement } from './slate';
import { BlockType } from './types';
import { getMarkdownCodeSpanRanges, isInsideMarkdownCodeSpan } from './utils';
import { MATRIX_TO_BASE } from '$plugins/matrix-to';
import { MATRIX_TO_BASE, testMatrixTo } from '$plugins/matrix-to';

export type OutputOptions = {
/**
Expand Down Expand Up @@ -38,8 +38,8 @@ const elementToCustomHtml = (node: CustomElement, children: string): string => {
fragment += `?${node.viaServers.map((server) => `via=${server}`).join('&')}`;
}

const matrixTo = `https://matrix.to/#/${fragment}`;
return `<a href="${encodeURI(matrixTo)}" target="_blank" rel="noreferrer noopener">${sanitizeText(node.name)}</a>`;
const matrixTo = `${MATRIX_TO_BASE}#/${fragment}`;
return sanitizeText(matrixTo);
}
case BlockType.Emoticon:
return node.key.startsWith('mxc://')
Expand All @@ -48,7 +48,9 @@ const elementToCustomHtml = (node: CustomElement, children: string): string => {
)}" title="${sanitizeText(node.shortcode)}" height="32" />`
: sanitizeText(node.key);
case BlockType.Link:
return `<a href="${encodeURI(node.href)}" target="_blank" rel="noreferrer noopener">${children}</a>`;
return testMatrixTo(node.href)
? sanitizeText(node.href)
: `<a href="${encodeURI(node.href)}" target="_blank" rel="noreferrer noopener">${children}</a>`;
case BlockType.Command:
return `/${sanitizeText(node.command)}`;
default:
Expand Down
17 changes: 17 additions & 0 deletions src/app/plugins/markdown/markdownToHtml.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,4 +223,21 @@ describe('markdownToHtml', () => {
const result = markdownToHtml(html);
expect(result).not.toContain('?');
});

it('keeps normal markdown links valid when many bare matrix.to URLs are shielded', () => {
const matrixLines = Array.from(
{ length: 12 },
(_, i) => `https://matrix.to/#/@u${i}:example.org`
).join('\n');
const md = `${matrixLines}\n[docs](https://example.com/doc)`;
const result = markdownToHtml(md);
expect(result).toContain('<a href="https://example.com/doc"');
expect(result).not.toContain('&lt;a href=');
});

it('emits bare matrix.to text for unformatted URLs, not anchor tags', () => {
const result = markdownToHtml('join https://matrix.to/#/#room:example.org please');
expect(result).toContain('https://matrix.to/#/#room:example.org');
expect(result).not.toMatch(/<a[^>]*matrix\.to/);
});
});
6 changes: 4 additions & 2 deletions src/app/plugins/markdown/markdownToHtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@

const unshieldBareMatrixToLinks = (html: string, placeholders: Map<string, string>): string => {
let result = html;
for (const [key, url] of placeholders.entries()) {
result = result.split(key).join(escapeHtml(url));
const keys = [...placeholders.keys()].sort((a, b) => b.length - a.length);

Check warning on line 80 in src/app/plugins/markdown/markdownToHtml.ts

View workflow job for this annotation

GitHub Actions / Lint

eslint-plugin-unicorn(no-array-sort)

Use `Array#toSorted()` instead of `Array#sort()`.
for (const key of keys) {
const url = placeholders.get(key);
if (url) result = result.split(key).join(escapeHtml(url));
}
return result;
};
Expand Down
Loading