Skip to content

Commit

Permalink
Ignore permalink_prefix when serializing Markdown
Browse files Browse the repository at this point in the history
fixes element-hq/element-web/issues/26002

During serialization of messages, pills were wrongfully serialized to a URL
starting with `permalink_prefix`. This is against the Spec (which mandates
https://matrix.to/#/ links) and the resulting pills were not recognized as
pills in other clients.

Spec-Appendix concerning matrix.to links: https://spec.matrix.org/v1.8/appendices/#matrixto-navigation
  • Loading branch information
herkulessi committed Oct 3, 2023
1 parent e1cfde0 commit c1bd2e1
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 18 deletions.
4 changes: 2 additions & 2 deletions src/editor/serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ export function mdSerialize(model: EditorModel): string {
case Type.AtRoomPill:
return html + part.text;
case Type.RoomPill: {
const url = makeGenericPermalink(part.resourceId);
const url = makeGenericPermalink(part.resourceId, true);
// Escape square brackets and backslashes
// Here we use the resourceId for compatibility with non-rich text clients
// See https://github.com/vector-im/element-web/issues/16660
const title = part.resourceId.replace(/[[\\\]]/g, (c) => "\\" + c);
return html + `[${title}](${url})`;
}
case Type.UserPill: {
const url = makeGenericPermalink(part.resourceId);
const url = makeGenericPermalink(part.resourceId, true);
// Escape square brackets and backslashes; convert newlines to HTML
const title = part.text.replace(/[[\\\]]/g, (c) => "\\" + c).replace(/\n/g, "<br>");
return html + `[${title}](${url})`;
Expand Down
21 changes: 15 additions & 6 deletions src/utils/permalinks/ElementPermalinkConstructor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,32 @@ export default class ElementPermalinkConstructor extends PermalinkConstructor {
}
}

public forEvent(roomId: string, eventId: string, serverCandidates: string[]): string {
public forEvent(roomId: string, eventId: string, serverCandidates: string[], ispill = false): string {
if(ispill) {
return `https://matrix.to/#/${roomId}/${eventId}${this.encodeServerCandidates(serverCandidates)}`;
}
return `${this.elementUrl}/#/room/${roomId}/${eventId}${this.encodeServerCandidates(serverCandidates)}`;
}

public forRoom(roomIdOrAlias: string, serverCandidates?: string[]): string {
public forRoom(roomIdOrAlias: string, serverCandidates?: string[], ispill = false): string {
if(ispill) {
return `https://matrix.to/#/${roomIdOrAlias}${this.encodeServerCandidates(serverCandidates)}`;
}
return `${this.elementUrl}/#/room/${roomIdOrAlias}${this.encodeServerCandidates(serverCandidates)}`;
}

public forUser(userId: string): string {
public forUser(userId: string, ispill = false): string {
if(ispill) {
return `https://matrix.to/#/${userId}`;
}
return `${this.elementUrl}/#/user/${userId}`;
}

public forEntity(entityId: string): string {
public forEntity(entityId: string, ispill = false): string {
if (entityId[0] === "!" || entityId[0] === "#") {
return this.forRoom(entityId);
return this.forRoom(entityId, [], ispill);
} else if (entityId[0] === "@") {
return this.forUser(entityId);
return this.forUser(entityId, ispill);
} else throw new Error("Unrecognized entity");
}

Expand Down
8 changes: 4 additions & 4 deletions src/utils/permalinks/PermalinkConstructor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ limitations under the License.
* TODO: Convert this to a real TypeScript interface
*/
export default class PermalinkConstructor {
public forEvent(roomId: string, eventId: string, serverCandidates: string[] = []): string {
public forEvent(roomId: string, eventId: string, serverCandidates: string[] = [], ispill = false): string {
throw new Error("Not implemented");
}

public forRoom(roomIdOrAlias: string, serverCandidates: string[] = []): string {
public forRoom(roomIdOrAlias: string, serverCandidates: string[] = [], ispill = false): string {
throw new Error("Not implemented");
}

public forUser(userId: string): string {
public forUser(userId: string, ispill = false): string {
throw new Error("Not implemented");
}

public forEntity(entityId: string): string {
public forEntity(entityId: string, ispill = false): string {
throw new Error("Not implemented");
}

Expand Down
12 changes: 6 additions & 6 deletions src/utils/permalinks/Permalinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,26 +269,26 @@ export class RoomPermalinkCreator {
};
}

export function makeGenericPermalink(entityId: string): string {
return getPermalinkConstructor().forEntity(entityId);
export function makeGenericPermalink(entityId: string, ispill = false): string {
return getPermalinkConstructor().forEntity(entityId, ispill);
}

export function makeUserPermalink(userId: string): string {
export function makeUserPermalink(userId: string, ispill = false): string {
return getPermalinkConstructor().forUser(userId);
}

export function makeRoomPermalink(matrixClient: MatrixClient, roomId: string): string {
export function makeRoomPermalink(matrixClient: MatrixClient, roomId: string, ispill = false): string {
if (!roomId) {
throw new Error("can't permalink a falsy roomId");
}

// If the roomId isn't actually a room ID, don't try to list the servers.
// Aliases are already routable, and don't need extra information.
if (roomId[0] !== "!") return getPermalinkConstructor().forRoom(roomId, []);
if (roomId[0] !== "!") return getPermalinkConstructor().forRoom(roomId, [], ispill);

const room = matrixClient.getRoom(roomId);
if (!room) {
return getPermalinkConstructor().forRoom(roomId, []);
return getPermalinkConstructor().forRoom(roomId, [], ispill);
}
const permalinkCreator = new RoomPermalinkCreator(room);
permalinkCreator.load();
Expand Down

0 comments on commit c1bd2e1

Please sign in to comment.