From e389bed0cc56a58c75bc25e2f8e63104ab19611d Mon Sep 17 00:00:00 2001 From: HarHarLinks <2803622+HarHarLinks@users.noreply.github.com> Date: Sat, 23 May 2026 00:27:12 +0200 Subject: [PATCH 1/2] implement msc4481 Signed-off-by: HarHarLinks <2803622+HarHarLinks@users.noreply.github.com> --- README.md | 17 +++++++++++++---- src/Link.js | 25 ++++++++++++++++++++----- src/create/CreateLinkView.js | 4 ++-- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1aac1b5c..04ec6a7c 100644 --- a/README.md +++ b/README.md @@ -46,12 +46,21 @@ increase its availability and avoid tampering. The matrix.to URL scheme is +| Entity type: | Example URL | +|--------------|---------------------------------------------------------------------| +| Rooms: | | +| Rooms by ID: | | +| Users: | | +| Messages: | | + +The legacy scheme is deprecated, but as follows + | Entity type: | Example URL | |--------------|-------------------------------------------------------------------| -| Rooms: | https://matrix.to/#/#matrix:matrix.org | -| Rooms by ID: | https://matrix.to/#/!cURbafjkfsMDVwdRDQ:matrix.org | -| Users: | https://matrix.to/#/@matthew:matrix.org | -| Messages: | https://matrix.to/#/#matrix:matrix.org/$1448831580433WbpiJ:jki.re | +| Rooms: | | +| Rooms by ID: | | +| Users: | | +| Messages: | | The #/ component is mandatory and exists to avoid leaking the target URL to the server hosting matrix.to. diff --git a/src/Link.js b/src/Link.js index 9eb96cea..ee09f001 100644 --- a/src/Link.js +++ b/src/Link.js @@ -17,10 +17,10 @@ limitations under the License. import {createEnum} from "./utils/enum.js"; import {orderedUnique} from "./utils/unique.js"; -const ROOMALIAS_PATTERN = /^#([^:]*):(.+)$/; -const ROOMID_PATTERN = /^!([^:]*)(:(.+))?$/; // As of room version 12, room IDs don't have domains -const USERID_PATTERN = /^@([^:]+):(.+)$/; -const EVENTID_PATTERN = /^$([^:]+):(.+)$/; +const ROOMALIAS_PATTERN = /^(?:#|r\/)([^:]*):(.+)$/; +const ROOMID_PATTERN = /^(?:!|roomid\/)([^:]*)(:(.+))?$/; // As of room version 12, room IDs don't have domains +const USERID_PATTERN = /^(?:@|u\/)([^:]+):(.+)$/; +const EVENTID_PATTERN = /^(?:$|e\/)([^:]+):(.+)$/; const GROUPID_PATTERN = /^\+([^:]+):(.+)$/; export const IdentifierKind = createEnum( @@ -111,7 +111,22 @@ export class Link { return null; } linkStr = linkStr.slice(2); - const [identifier, eventId] = linkStr.split("/"); + const segments = linkStr.split("/"); + let _1, identifier, _2, eventId; + if (/^(roomid|r|u)/.test(linkStr)) { + [_1, identifier, _2, eventId] = segments; + if (_1 === "roomid") + identifier = "!" + identifier; + else if (_1 === "r") + identifier = "#" + identifier; + else + identifier = "@" + identifier; + + if (_2 === "e") + eventId = "$" + eventId; + } else { + [identifier, eventId] = segments; + } let viaServers = []; let clientId = null; diff --git a/src/create/CreateLinkView.js b/src/create/CreateLinkView.js index cd013222..e6c73fea 100644 --- a/src/create/CreateLinkView.js +++ b/src/create/CreateLinkView.js @@ -29,7 +29,7 @@ export class CreateLinkView extends TemplateView { type: "text", name: "identifier", required: true, - placeholder: "#room:example.com, @user:example.com", + placeholder: "r/room:example.com, u/user:example.com", onChange: evt => this._onIdentifierChange(evt) })), t.div(t.input({className: "primary fullwidth icon link", type: "submit", value: "Create link"})) @@ -48,7 +48,7 @@ export class CreateLinkView extends TemplateView { _onIdentifierChange(evt) { const inputField = evt.target; if (!this.value.validateIdentifier(inputField.value)) { - inputField.setCustomValidity("That doesn't seem valid. Try #room:example.com, @user:example.com or +group:example.com."); + inputField.setCustomValidity("That doesn't seem valid. Try r/room:example.com, u/user:example.com or +group:example.com."); } else { inputField.setCustomValidity(""); } From 3ebc22fbacab731034ac8bc66e9a943f62311d75 Mon Sep 17 00:00:00 2001 From: HarHarLinks <2803622+HarHarLinks@users.noreply.github.com> Date: Sat, 23 May 2026 01:18:14 +0200 Subject: [PATCH 2/2] fix converting old sigils Signed-off-by: HarHarLinks <2803622+HarHarLinks@users.noreply.github.com> --- src/Link.js | 15 +++++++++++++-- src/create/CreateLinkViewModel.js | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Link.js b/src/Link.js index ee09f001..3db8027b 100644 --- a/src/Link.js +++ b/src/Link.js @@ -40,6 +40,16 @@ function asPrefix(identifierKind) { } } +function asMSC4481Prefix(identifierKind) { + switch (identifierKind) { + case IdentifierKind.RoomId: return "roomid/"; + case IdentifierKind.RoomAlias: return "r/"; + case IdentifierKind.GroupId: return asPrefix(identifierKind); + case IdentifierKind.UserId: return "u/"; + default: throw new Error("invalid id kind " + identifierKind); + } +} + function getWebInstanceMap(queryParams) { const prefix = "web-instance["; const postfix = "]"; @@ -225,10 +235,11 @@ export class Link { } toFragment() { + const id = `/${asMSC4481Prefix(this.identifierKind)}${this.identifier.substring(1)}`; if (this.eventId) { - return `/${this.identifier}/${this.eventId}`; + return `${id}/e/${this.eventId.substring(1)}`; } else { - return `/${this.identifier}`; + return id; } } } diff --git a/src/create/CreateLinkViewModel.js b/src/create/CreateLinkViewModel.js index 80b5d0c6..856f14cd 100644 --- a/src/create/CreateLinkViewModel.js +++ b/src/create/CreateLinkViewModel.js @@ -30,7 +30,7 @@ export class CreateLinkViewModel extends ViewModel { } async createLink(identifier) { - this._link = Link.parseIdentifier(identifier); + this._link = Link.parseFragment(`#/${identifier}`); if (this._link) { this.openLink("#" + this._link.toFragment()); }