diff --git a/src/Link.js b/src/Link.js index 44d769e..d3ff7f1 100644 --- a/src/Link.js +++ b/src/Link.js @@ -40,6 +40,21 @@ function asPrefix(identifierKind) { } } +function getWebInstanceMap(queryParams) { + const prefix = "web-instance["; + const postfix = "]"; + const webInstanceParams = queryParams.filter(([key]) => key.startsWith(prefix) && key.endsWith(postfix)); + const webInstances = webInstanceParams.map(([key, value]) => { + const noPrefix = key.substr(prefix.length); + const clientId = noPrefix.substr(0, noPrefix.length - postfix.length); + return [clientId, value]; + }); + return webInstances.reduce((map, [clientId, host]) => { + map[clientId] = host; + return map; + }, {}); +} + export function getLabelForLinkKind(kind) { switch (kind) { case LinkKind.User: return "Start chat"; @@ -74,8 +89,12 @@ export class Link { let viaServers = []; let clientId = null; + let webInstances = {}; if (queryParamsStr) { - const queryParams = queryParamsStr.split("&").map(pair => pair.split("=")); + const queryParams = queryParamsStr.split("&").map(pair => { + const [key, value] = pair.split("="); + return [decodeURIComponent(key), decodeURIComponent(value)]; + }); viaServers = queryParams .filter(([key, value]) => key === "via") .map(([,value]) => value); @@ -83,6 +102,7 @@ export class Link { if (clientParam) { clientId = clientParam[1]; } + webInstances = getWebInstanceMap(queryParams); } if (linkStr.startsWith("#/")) { @@ -96,32 +116,33 @@ export class Link { if (matches) { const server = matches[2]; const localPart = matches[1]; - return new Link(clientId, viaServers, IdentifierKind.UserId, localPart, server); + return new Link(clientId, viaServers, IdentifierKind.UserId, localPart, server, webInstances); } matches = ROOMALIAS_PATTERN.exec(identifier); if (matches) { const server = matches[2]; const localPart = matches[1]; - return new Link(clientId, viaServers, IdentifierKind.RoomAlias, localPart, server, eventId); + return new Link(clientId, viaServers, IdentifierKind.RoomAlias, localPart, server, webInstances, eventId); } matches = ROOMID_PATTERN.exec(identifier); if (matches) { const server = matches[2]; const localPart = matches[1]; - return new Link(clientId, viaServers, IdentifierKind.RoomId, localPart, server, eventId); + return new Link(clientId, viaServers, IdentifierKind.RoomId, localPart, server, webInstances, eventId); } matches = GROUPID_PATTERN.exec(identifier); if (matches) { const server = matches[2]; const localPart = matches[1]; - return new Link(clientId, viaServers, IdentifierKind.GroupId, localPart, server); + return new Link(clientId, viaServers, IdentifierKind.GroupId, localPart, server, webInstances); } return null; } - constructor(clientId, viaServers, identifierKind, localPart, server, eventId) { + constructor(clientId, viaServers, identifierKind, localPart, server, webInstances, eventId) { const servers = [server]; servers.push(...viaServers); + this.webInstances = webInstances; this.servers = orderedUnique(servers); this.identifierKind = identifierKind; this.identifier = `${asPrefix(identifierKind)}${localPart}:${server}`; diff --git a/src/open/clients/Element.js b/src/open/clients/Element.js index 8e605fc..b9a4b1d 100644 --- a/src/open/clients/Element.js +++ b/src/open/clients/Element.js @@ -17,6 +17,13 @@ limitations under the License. import {Maturity, Platform, LinkKind, FDroidLink, AppleStoreLink, PlayStoreLink, WebsiteLink} from "../types.js"; +const trustedWebInstances = [ + "app.element.io", // first one is the default one + "develop.element.io", + "chat.fosdem.org", + "chat.mozilla.org", +]; + /** * Information on how to deep link to a given matrix client. */ @@ -56,7 +63,11 @@ export class Element { break; } if (platform === Platform.DesktopWeb || platform === Platform.MobileWeb || platform === Platform.iOS) { - return `https://app.element.io/#/${fragmentPath}`; + let instanceHost = trustedWebInstances[0]; + if (trustedWebInstances.includes(link.webInstances[this.id])) { + instanceHost = link.webInstances[this.id]; + } + return `https://${instanceHost}/#/${fragmentPath}`; } else if (platform === Platform.Linux || platform === Platform.Windows || platform === Platform.macOS) { return `element://vector/webapp/#/${fragmentPath}`; } else {