allow setting a web instance in the url from a whitelist
as web clients can be hosted on multiple domains, allow specifying which hosted instance we want to use. as this could be phishing vector, we work with a host whitelist for now until a better solution comes to mind.
This commit is contained in:
parent
0aa9c2e766
commit
47d0db89c1
2 changed files with 39 additions and 7 deletions
33
src/Link.js
33
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}`;
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue