/*
Copyright 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import "./index.css";
import "@fontsource/inter/400.css";
import "@fontsource/inter/600.css";
import { logger } from "matrix-js-sdk/src/logger";
import { getVectorConfig } from "../getconfig";
import { type MobileAppVariant, mobileApps, updateMobilePage } from "./mobile-apps.ts";
function onBackToElementClick(): void {
// Cookie should expire in 4 hours
document.cookie = "element_mobile_redirect_to_guide=false;path=/;max-age=14400";
window.location.href = "../";
}
// NEVER pass user-controlled content to this function! Hardcoded strings only please.
function renderConfigError(message: string): void {
const contactMsg =
"If this is unexpected, please contact your system administrator " + "or technical support representative.";
message = `
Error loading Element
${message}
${contactMsg}
`;
const toHide = document.getElementsByClassName("mx_HomePage_container");
const errorContainers = document.getElementsByClassName(
"mx_HomePage_errorContainer",
) as HTMLCollectionOf;
for (const e of toHide) {
// We have to clear the content because .style.display='none'; doesn't work
// due to an !important in the CSS.
e.innerHTML = "";
}
for (const e of errorContainers) {
e.style.display = "block";
e.innerHTML = message;
}
}
async function initPage(): Promise {
const config = await getVectorConfig("..");
// We manually parse the config similar to how validateServerConfig works because
// calling that function pulls in roughly 4mb of JS we don't use.
const wkConfig = config?.["default_server_config"]; // overwritten later under some conditions
let serverName = config?.["default_server_name"];
const defaultHsUrl = config?.["default_hs_url"];
const defaultIsUrl = config?.["default_is_url"];
const appVariant = (config?.["mobile_guide_app_variant"] ?? "x") as MobileAppVariant;
const metadata = mobileApps[appVariant];
const incompatibleOptions = [wkConfig, serverName, defaultHsUrl].filter((i) => !!i);
if (defaultHsUrl && (wkConfig || serverName)) {
return renderConfigError(
"Invalid configuration: a default_hs_url can't be specified along with default_server_name " +
"or default_server_config",
);
}
if (incompatibleOptions.length < 1) {
return renderConfigError("Invalid configuration: no default server specified.");
}
let hsUrl: string | undefined;
let isUrl: string | undefined;
if (!serverName && typeof wkConfig?.["m.homeserver"]?.["base_url"] === "string") {
hsUrl = wkConfig["m.homeserver"]["base_url"];
serverName = wkConfig["m.homeserver"]["server_name"];
if (typeof wkConfig["m.identity_server"]?.["base_url"] === "string") {
isUrl = wkConfig["m.identity_server"]["base_url"];
}
}
if (serverName) {
// We also do our own minimal .well-known validation to avoid pulling in the js-sdk
try {
const result = await fetch(`https://${serverName}/.well-known/matrix/client`);
const wkConfig = await result.json();
if (wkConfig?.["m.homeserver"]) {
hsUrl = wkConfig["m.homeserver"]["base_url"];
if (wkConfig["m.identity_server"]) {
isUrl = wkConfig["m.identity_server"]["base_url"];
}
}
} catch (e) {
if (wkConfig?.["m.homeserver"]) {
hsUrl = wkConfig["m.homeserver"]["base_url"] || undefined;
if (wkConfig["m.identity_server"]) {
isUrl = wkConfig["m.identity_server"]["base_url"] || undefined;
}
} else {
logger.error(e);
return renderConfigError("Unable to fetch homeserver configuration");
}
}
}
if (defaultHsUrl) {
hsUrl = defaultHsUrl;
isUrl = defaultIsUrl;
}
if (!hsUrl) {
return renderConfigError("Unable to locate homeserver");
}
if (hsUrl && !hsUrl.endsWith("/")) hsUrl += "/";
if (isUrl && !isUrl.endsWith("/")) isUrl += "/";
let deepLinkUrl = `https://mobile.element.io${metadata.deepLinkPath}`;
if (metadata.usesLegacyDeepLink) {
deepLinkUrl += `?hs_url=${encodeURIComponent(hsUrl)}`;
if (isUrl) {
deepLinkUrl += `&is_url=${encodeURIComponent(isUrl)}`;
}
} else if (serverName) {
deepLinkUrl += `?account_provider=${serverName}`;
}
// Not part of updateMobilePage as the link is only shown on mobile_guide and not on mobile.element.io
document.getElementById("back_to_element_button")!.onclick = onBackToElementClick;
updateMobilePage(metadata, deepLinkUrl, serverName ?? hsUrl);
}
void initPage();