diff --git a/src/utils/permalinks/PermalinkConstructor.js b/src/utils/permalinks/PermalinkConstructor.js index 47d813390f..507f16f795 100644 --- a/src/utils/permalinks/PermalinkConstructor.js +++ b/src/utils/permalinks/PermalinkConstructor.js @@ -38,4 +38,42 @@ export default class PermalinkConstructor { isPermalinkHost(host: string): boolean { throw new Error("Not implemented"); } + + parsePermalink(fullUrl: string): PermalinkParts { + throw new Error("Not implemented"); + } +} + +// Inspired by/Borrowed with permission from the matrix-bot-sdk: +// https://github.com/turt2live/matrix-js-bot-sdk/blob/7c4665c9a25c2c8e0fe4e509f2616505b5b66a1c/src/Permalinks.ts#L1-L6 +export class PermalinkParts { + roomIdOrAlias: string; + eventId: string; + userId: string; + groupId: string; + viaServers: string[]; + + constructor(roomIdOrAlias: string, eventId: string, userId: string, groupId: string, viaServers: string[]) { + this.roomIdOrAlias = roomIdOrAlias; + this.eventId = eventId; + this.groupId = groupId; + this.userId = userId; + this.viaServers = viaServers; + } + + static forUser(userId: string): PermalinkParts { + return new PermalinkParts(null, null, userId, null, null); + } + + static forGroup(groupId: string): PermalinkParts { + return new PermalinkParts(null, null, null, groupId, null); + } + + static forRoom(roomIdOrAlias: string, viaServers: string[]): PermalinkParts { + return new PermalinkParts(roomIdOrAlias, null, null, null, viaServers || []); + } + + static forEvent(roomId: string, eventId: string, viaServers: string[]): PermalinkParts { + return new PermalinkParts(roomId, eventId, null, null, viaServers || []); + } } diff --git a/src/utils/permalinks/SpecPermalinkConstructor.js b/src/utils/permalinks/SpecPermalinkConstructor.js index 5dd4a5a24e..e4cff798a7 100644 --- a/src/utils/permalinks/SpecPermalinkConstructor.js +++ b/src/utils/permalinks/SpecPermalinkConstructor.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import PermalinkConstructor from "./PermalinkConstructor"; +import PermalinkConstructor, {PermalinkParts} from "./PermalinkConstructor"; export const host = "matrix.to"; export const baseUrl = `https://${host}`; @@ -51,4 +51,40 @@ export default class SpecPermalinkConstructor extends PermalinkConstructor { if (!candidates || candidates.length === 0) return ''; return `?via=${candidates.map(c => encodeURIComponent(c)).join("&via=")}`; } + + // Heavily inspired by/borrowed from the matrix-bot-sdk (with permission): + // https://github.com/turt2live/matrix-js-bot-sdk/blob/7c4665c9a25c2c8e0fe4e509f2616505b5b66a1c/src/Permalinks.ts#L33-L61 + parsePermalink(fullUrl: string): PermalinkParts { + if (!fullUrl || !fullUrl.startsWith(baseUrl)) { + throw new Error("Does not appear to be a permalink"); + } + + const parts = fullUrl.substring(`${baseUrl}/#/`.length).split("/"); + + const entity = parts[0]; + if (entity[0] === '@') { + // Probably a user, no further parsing needed. + return PermalinkParts.forUser(entity); + } else if (entity[0] === '+') { + // Probably a group, no further parsing needed. + return PermalinkParts.forGroup(entity); + } else if (entity[0] === '#' || entity[0] === '!') { + if (parts.length === 1) { + return PermalinkParts.forRoom(entity, []); + } + + // rejoin the rest because v3 events can have slashes (annoyingly) + const eventIdAndQuery = parts.length > 1 ? parts.slice(1).join('/') : ""; + const secondaryParts = eventIdAndQuery.split("?"); + + const eventId = secondaryParts[0]; + const query = secondaryParts.length > 1 ? secondaryParts[1] : ""; + + const via = query.split("via=").filter(p => !!p); + + return PermalinkParts.forEvent(entity, eventId, via); + } else { + throw new Error("Unknown entity type in permalink"); + } + } }