Skip to content

Commit aa45aa2

Browse files
authored
Disallow links without protocol (e.g. starting with http(s)://) in LinkedText. (#32972)
* Disallow links without protocols in LinkedText. * Update tests
1 parent 1974b50 commit aa45aa2

4 files changed

Lines changed: 21 additions & 11 deletions

File tree

apps/web/playwright/e2e/links/messages.spec.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ test.describe("Message links", () => {
1414
await use({ roomId });
1515
},
1616
});
17-
for (const link of ["https://example.org", "example.org", "ftp://example.org"]) {
17+
for (const link of ["https://example.org", "ftp://example.org"]) {
1818
test(`should linkify a regular link '${link}'`, async ({ page, user, app, room }) => {
1919
await page.goto(`#/room/${room.roomId}`);
2020
// Needs to be unformatted so we test linkifing
@@ -24,6 +24,13 @@ test.describe("Message links", () => {
2424
await expect(linkElement).toBeVisible();
2525
});
2626
}
27+
test("should NOT linkify a bare domain", async ({ page, user, app, room }) => {
28+
await page.goto(`#/room/${room.roomId}`);
29+
// Needs to be unformatted so we test linkifing
30+
await app.client.sendMessage(room.roomId, `Check out example.org`);
31+
const linkElement = page.locator(".mx_EventTile_last").getByRole("link", { name: "example.org" });
32+
await expect(linkElement).not.toBeVisible();
33+
});
2734
test("should linkify a User ID", async ({ page, user, app, room }) => {
2835
await page.goto(`#/room/${room.roomId}`);
2936
// Needs to be unformatted so we test linkifing

apps/web/playwright/e2e/links/topic.spec.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,7 @@ test.describe("Topic links", () => {
1414
await use({ roomId });
1515
},
1616
});
17-
for (const link of [
18-
"https://example.org",
19-
"example.org",
20-
"ftp://example.org",
21-
"#aroom:example.org",
22-
"@alice:example.org",
23-
]) {
17+
for (const link of ["https://example.org", "ftp://example.org", "#aroom:example.org", "@alice:example.org"]) {
2418
// Playwright treats '@' as a tag, so replace it to be safe
2519
test(`should linkify plaintext '${link.replace("@", "_@")}'`, async ({ page, user, app, room }) => {
2620
await app.client.sendStateEvent(

packages/shared-components/src/core/utils/LinkedText/LinkedText.test.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ describe("LinkedText", () => {
4949
expect(container).toMatchSnapshot();
5050
});
5151

52+
it("does not linkify domains without a protocol.", () => {
53+
const { queryAllByRole } = render(
54+
<LinkedTextContext value={{}}>
55+
<LinkedText>Check out this link github.com</LinkedText>
56+
</LinkedTextContext>,
57+
);
58+
expect(queryAllByRole("link")).toHaveLength(0);
59+
});
60+
5261
it("renders a user ID", () => {
5362
const { container } = render(<WithUserId />);
5463
expect(container).toMatchSnapshot();
@@ -73,7 +82,7 @@ describe("LinkedText", () => {
7382
const fn = vitest.fn();
7483
const { getAllByRole } = render(
7584
<LinkedTextContext value={{}}>
76-
<LinkedText onLinkClick={fn}>Check out this link https://google.com and example.org</LinkedText>
85+
<LinkedText onLinkClick={fn}>Check out this link https://google.com and https://example.org</LinkedText>
7786
</LinkedTextContext>,
7887
);
7988
const links = getAllByRole("link");

packages/shared-components/src/core/utils/linkify.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,10 @@ export function generateLinkedTextOptions({
228228
: undefined),
229229
// By default, ignore Matrix ID types.
230230
// Other applications may implement their own version of LinkifyComponent.
231-
validate: (_value, type: string) =>
231+
validate: (value, type: string) =>
232232
!!(type === LinkifyMatrixOpaqueIdType.UserId && userIdListener) ||
233233
!!(type === LinkifyMatrixOpaqueIdType.RoomAlias && roomAliasListener) ||
234-
type === LinkifyMatrixOpaqueIdType.URL,
234+
!!(type === LinkifyMatrixOpaqueIdType.URL && URL.canParse(value)),
235235
} satisfies linkifyjs.Opts;
236236
}
237237

0 commit comments

Comments
 (0)