Move default homeserver to config file

This commit is contained in:
David Baker 2022-12-20 17:26:45 +00:00
parent 282a4853cf
commit 96de515e56
13 changed files with 69 additions and 54 deletions

View file

@ -32,7 +32,6 @@ import { useTranslation } from "react-i18next";
import { ErrorView } from "./FullScreenView";
import {
initClient,
defaultHomeserver,
CryptoStoreIntegrityError,
fallbackICEServerAllowed,
} from "./matrix-utils";
@ -40,6 +39,7 @@ import { widget } from "./widget";
import { PosthogAnalytics, RegistrationType } from "./PosthogAnalytics";
import { translatedError } from "./TranslatedError";
import { useEventTarget } from "./useEvents";
import { Config } from "./config/Config";
declare global {
interface Window {
@ -139,7 +139,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
return {
client: await initClient(
{
baseUrl: defaultHomeserver,
baseUrl: Config.defaultHomeserverUrl(),
accessToken: access_token,
userId: user_id,
deviceId: device_id,
@ -155,7 +155,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
try {
const client = await initClient(
{
baseUrl: defaultHomeserver,
baseUrl: Config.defaultHomeserverUrl(),
accessToken: access_token,
userId: user_id,
deviceId: device_id,

View file

@ -29,11 +29,11 @@ import { ReactComponent as Logo } from "../icons/LogoLarge.svg";
import { useClient } from "../ClientContext";
import { FieldRow, InputField, ErrorMessage } from "../input/Input";
import { Button } from "../button";
import { defaultHomeserver, defaultHomeserverHost } from "../matrix-utils";
import styles from "./LoginPage.module.css";
import { useInteractiveLogin } from "./useInteractiveLogin";
import { usePageTitle } from "../usePageTitle";
import { PosthogAnalytics } from "../PosthogAnalytics";
import { Config } from "../config/Config";
export const LoginPage: FC = () => {
const { t } = useTranslation();
@ -41,7 +41,7 @@ export const LoginPage: FC = () => {
const { setClient } = useClient();
const login = useInteractiveLogin();
const homeserver = defaultHomeserver; // TODO: Make this configurable
const homeserver = Config.defaultHomeserverUrl(); // TODO: Make this configurable
const usernameRef = useRef<HTMLInputElement>();
const passwordRef = useRef<HTMLInputElement>();
const history = useHistory();
@ -76,11 +76,9 @@ export const LoginPage: FC = () => {
);
const homeserverHost = useMemo(() => {
try {
// XXX: This isn't really correct: the server name of an HS may not
// be the same as the hostname of the client API endpoint.
return new URL(homeserver).host;
} catch (error) {
return defaultHomeserverHost;
}
}, [homeserver]);
return (

View file

@ -31,7 +31,6 @@ import { Trans, useTranslation } from "react-i18next";
import { FieldRow, InputField, ErrorMessage } from "../input/Input";
import { Button } from "../button";
import { useClient } from "../ClientContext";
import { defaultHomeserverHost } from "../matrix-utils";
import { useInteractiveRegistration } from "./useInteractiveRegistration";
import styles from "./LoginPage.module.css";
import { ReactComponent as Logo } from "../icons/LogoLarge.svg";
@ -40,6 +39,7 @@ import { useRecaptcha } from "./useRecaptcha";
import { Caption, Link } from "../typography/Typography";
import { usePageTitle } from "../usePageTitle";
import { PosthogAnalytics } from "../PosthogAnalytics";
import { Config } from "../config/Config";
export const RegisterPage: FC = () => {
const { t } = useTranslation();
@ -165,7 +165,7 @@ export const RegisterPage: FC = () => {
autoCorrect="off"
autoCapitalize="none"
prefix="@"
suffix={`:${defaultHomeserverHost}`}
suffix={`:${Config.defaultServerName()}`}
/>
</FieldRow>
<FieldRow>

View file

@ -18,7 +18,7 @@ import { useCallback } from "react";
import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth";
import { createClient, MatrixClient } from "matrix-js-sdk/src/matrix";
import { initClient, defaultHomeserver } from "../matrix-utils";
import { initClient } from "../matrix-utils";
import { Session } from "../ClientContext";
export const useInteractiveLogin = () =>
@ -59,7 +59,7 @@ export const useInteractiveLogin = () =>
const client = await initClient(
{
baseUrl: defaultHomeserver,
baseUrl: homeserver,
accessToken: access_token,
userId: user_id,
deviceId: device_id,

View file

@ -18,8 +18,9 @@ import { useState, useEffect, useCallback, useRef } from "react";
import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth";
import { createClient, MatrixClient } from "matrix-js-sdk/src/matrix";
import { initClient, defaultHomeserver } from "../matrix-utils";
import { initClient } from "../matrix-utils";
import { Session } from "../ClientContext";
import { Config } from "../config/Config";
export const useInteractiveRegistration = (): [
string,
@ -37,7 +38,9 @@ export const useInteractiveRegistration = (): [
const authClient = useRef<MatrixClient>();
if (!authClient.current) {
authClient.current = createClient({ baseUrl: defaultHomeserver });
authClient.current = createClient({
baseUrl: Config.defaultHomeserverUrl(),
});
}
useEffect(() => {
@ -92,7 +95,7 @@ export const useInteractiveRegistration = (): [
const client = await initClient(
{
baseUrl: defaultHomeserver,
baseUrl: Config.defaultHomeserverUrl(),
accessToken: access_token,
userId: user_id,
deviceId: device_id,

View file

@ -14,11 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {
DEFAULT_CONFIG,
ConfigOptions,
ResolvedConfigOptions,
} from "./ConfigOptions";
import { DEFAULT_CONFIG, ConfigOptions } from "./ConfigOptions";
export class Config {
private static internalInstance: Config;
@ -41,7 +37,26 @@ export class Config {
return Config.internalInstance.initPromise;
}
public config: ResolvedConfigOptions;
// Convenience accessors
public static defaultHomeserverUrl(): string | undefined {
const defaultServerConfig = Config.instance.config.default_server_config;
if (!defaultServerConfig) {
return undefined;
}
return defaultServerConfig["m.homeserver"]?.base_url;
}
public static defaultServerName(): string | undefined {
const defaultServerConfig = Config.instance.config.default_server_config;
if (!defaultServerConfig) {
return undefined;
}
return defaultServerConfig["m.homeserver"]?.server_name;
}
public config: ConfigOptions;
private initPromise: Promise<void>;
}
@ -59,7 +74,7 @@ async function downloadConfig(
// Lack of a config isn't an error, we should just use the defaults.
// Also treat a blank config as no config, assuming the status code is 0, because we don't get 404s from file:
// URIs so this is the only way we can not fail if the file doesn't exist when loading from a file:// URI.
return {};
return DEFAULT_CONFIG;
}
return res.json();

View file

@ -19,21 +19,24 @@ export interface ConfigOptions {
rageshake?: {
submit_url: string;
};
}
export interface ResolvedConfigOptions extends ConfigOptions {
sentry: {
DSN: string;
environment: string;
// Describes the default homeserver to use. The same format as Element Web
// (without identity servers as we don't use them).
default_server_config: {
["m.homeserver"]: {
base_url: string;
server_name: string;
};
rageshake: {
submit_url: string;
};
}
export const DEFAULT_CONFIG: ResolvedConfigOptions = {
sentry: { DSN: "", environment: "production" },
rageshake: {
submit_url: "https://element.io/bugreports/submit",
export const DEFAULT_CONFIG: ConfigOptions = {
default_server_config: {
["m.homeserver"]: {
// These are probably poor guesses - we may want to just not work without
// a config file.
base_url: `${window.location.protocol}//${window.location.host}`,
server_name: window.location.host,
},
},
};

View file

@ -23,7 +23,6 @@ import * as Sentry from "@sentry/react";
import { getUrlParams } from "./UrlParams";
import { Config } from "./config/Config";
import { DEFAULT_CONFIG } from "./config/ConfigOptions";
enum LoadState {
None,
@ -193,10 +192,8 @@ export class Initializer {
this.loadStates.config === LoadState.Loaded
) {
Sentry.init({
dsn: Config.instance.config.sentry?.DSN ?? DEFAULT_CONFIG.sentry.DSN,
environment:
Config.instance.config.sentry.environment ??
DEFAULT_CONFIG.sentry.environment,
dsn: Config.instance.config.sentry?.DSN,
environment: Config.instance.config.sentry?.environment,
integrations: [
new Integrations.BrowserTracing({
routingInstrumentation:

View file

@ -19,15 +19,11 @@ import type { Room } from "matrix-js-sdk/src/models/room";
import IndexedDBWorker from "./IndexedDBWorker?worker";
import { getUrlParams } from "./UrlParams";
import { loadOlm } from "./olm";
import { Config } from "./config/Config";
export const defaultHomeserver =
(import.meta.env.VITE_DEFAULT_HOMESERVER as string) ??
`${window.location.protocol}//${window.location.host}`;
export const fallbackICEServerAllowed =
import.meta.env.VITE_FALLBACK_STUN_ALLOWED === "true";
export const defaultHomeserverHost = new URL(defaultHomeserver).host;
export class CryptoStoreIntegrityError extends Error {
constructor() {
super("Crypto store data was expected, but none was found");
@ -206,7 +202,7 @@ export function roomNameFromRoomId(roomId: string): string {
.toLowerCase();
}
export function isLocalRoomId(roomId: string): boolean {
export function isLocalRoomId(roomId: string, client: MatrixClient): boolean {
if (!roomId) {
return false;
}
@ -217,7 +213,7 @@ export function isLocalRoomId(roomId: string): boolean {
return false;
}
return parts[1] === defaultHomeserverHost;
return parts[1] === client.getDomain();
}
export async function createRoom(
@ -291,11 +287,12 @@ export async function createRoom(
return [fullAliasFromRoomName(name, client), result.room_id];
}
// Returns a URL to that will load Element Call with the given room
export function getRoomUrl(roomIdOrAlias: string): string {
if (roomIdOrAlias.startsWith("#")) {
const [localPart, host] = roomIdOrAlias.replace("#", "").split(":");
if (host !== defaultHomeserverHost) {
if (host !== Config.defaultServerName()) {
return `${window.location.protocol}//${window.location.host}/room/${roomIdOrAlias}`;
} else {
return `${window.location.protocol}//${window.location.host}/${localPart}`;

View file

@ -17,9 +17,11 @@ limitations under the License.
import React, { useEffect } from "react";
import { useLocation, useHistory } from "react-router-dom";
import { defaultHomeserverHost } from "../matrix-utils";
import { Config } from "../config/Config";
import { LoadingView } from "../FullScreenView";
// A component that, when loaded, redirects the client to a full room URL
// based on the current URL being an abbreviated room URL
export function RoomRedirect() {
const { pathname } = useLocation();
const history = useHistory();
@ -32,7 +34,7 @@ export function RoomRedirect() {
}
if (!roomId.startsWith("#") && !roomId.startsWith("!")) {
roomId = `#${roomId}:${defaultHomeserverHost}`;
roomId = `#${roomId}:${Config.defaultServerName()}`;
}
history.replace(`/room/${roomId.toLowerCase()}`);

View file

@ -61,7 +61,7 @@ export const useLoadGroupCall = (
return room;
} catch (error) {
if (
isLocalRoomId(roomIdOrAlias) &&
isLocalRoomId(roomIdOrAlias, client) &&
(error.errcode === "M_NOT_FOUND" ||
(error.message &&
error.message.indexOf("Failed to fetch alias") !== -1))

View file

@ -18,7 +18,7 @@ import { useEffect } from "react";
export function usePageTitle(title: string): void {
useEffect(() => {
const productName = import.meta.env.VITE_PRODUCT_NAME || "Element Call";
const productName = "Element Call";
document.title = title ? `${productName} | ${title}` : productName;
}, [title]);
}

View file

@ -31,7 +31,7 @@ export default defineConfig(({ mode }) => {
svgrPlugin(),
htmlTemplate.default({
data: {
title: env.VITE_PRODUCT_NAME || "Element Call",
title: "Element Call",
},
}),
],