mirror of
https://github.com/UA-Fediland/synapse-admin.git
synced 2024-11-24 23:35:24 +00:00
Extract helper functions from LoginPage
Change-Id: I507e223d0eff00bac3963d0b71f9bd648b9ab7b1
This commit is contained in:
parent
5b8882bd80
commit
64a89f6552
3 changed files with 110 additions and 70 deletions
|
@ -1,6 +1,5 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import {
|
||||
fetchUtils,
|
||||
Form,
|
||||
FormDataConsumer,
|
||||
Notification,
|
||||
|
@ -27,6 +26,13 @@ import {
|
|||
} from "@mui/material";
|
||||
import { styled } from "@mui/material/styles";
|
||||
import LockIcon from "@mui/icons-material/Lock";
|
||||
import {
|
||||
getServerVersion,
|
||||
getSupportedLoginFlows,
|
||||
getWellKnownUrl,
|
||||
isValidBaseUrl,
|
||||
splitMxid,
|
||||
} from "../synapse/synapse";
|
||||
|
||||
const FormBox = styled(Box)(({ theme }) => ({
|
||||
display: "flex",
|
||||
|
@ -170,87 +176,42 @@ const LoginPage = () => {
|
|||
window.location.href = ssoFullUrl;
|
||||
};
|
||||
|
||||
const extractHomeServer = username => {
|
||||
const usernameRegex = /@[a-zA-Z0-9._=\-/]+:([a-zA-Z0-9\-.]+\.[a-zA-Z]+)/;
|
||||
if (!username) return null;
|
||||
const res = username.match(usernameRegex);
|
||||
if (res) return res[1];
|
||||
return null;
|
||||
};
|
||||
|
||||
const UserData = ({ formData }) => {
|
||||
const form = useFormContext();
|
||||
const [serverVersion, setServerVersion] = useState("");
|
||||
|
||||
const handleUsernameChange = _ => {
|
||||
if (formData.base_url || cfg_base_url) return;
|
||||
// check if username is a full qualified userId then set base_url accordially
|
||||
const home_server = extractHomeServer(formData.username);
|
||||
const wellKnownUrl = `https://${home_server}/.well-known/matrix/client`;
|
||||
if (home_server) {
|
||||
// fetch .well-known entry to get base_url
|
||||
fetchUtils
|
||||
.fetchJson(wellKnownUrl, { method: "GET" })
|
||||
.then(({ json }) => {
|
||||
form.setValue("base_url", json["m.homeserver"].base_url);
|
||||
})
|
||||
.catch(_ => {
|
||||
// if there is no .well-known entry, try the home server name
|
||||
form.setValue("base_url", `https://${home_server}`);
|
||||
});
|
||||
// check if username is a full qualified userId then set base_url accordingly
|
||||
const domain = splitMxid(formData.username)?.domain;
|
||||
if (domain) {
|
||||
getWellKnownUrl(domain).then(url => form.setValue("base_url", url));
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(
|
||||
_ => {
|
||||
if (
|
||||
!formData.base_url ||
|
||||
!formData.base_url.match(
|
||||
/^(http|https):\/\/[a-zA-Z0-9\-.]+(:\d{1,5})?$/
|
||||
useEffect(() => {
|
||||
if (!isValidBaseUrl(formData.base_url)) return;
|
||||
|
||||
getServerVersion(formData.base_url)
|
||||
.then(serverVersion =>
|
||||
setServerVersion(
|
||||
`${translate("synapseadmin.auth.server_version")} ${serverVersion}`
|
||||
)
|
||||
)
|
||||
return;
|
||||
const versionUrl = `${formData.base_url}/_synapse/admin/v1/server_version`;
|
||||
fetchUtils
|
||||
.fetchJson(versionUrl, { method: "GET" })
|
||||
.then(({ json }) => {
|
||||
setServerVersion(
|
||||
`${translate("synapseadmin.auth.server_version")} ${
|
||||
json["server_version"]
|
||||
}`
|
||||
);
|
||||
})
|
||||
.catch(_ => {
|
||||
setServerVersion("");
|
||||
});
|
||||
.catch(() => setServerVersion(""));
|
||||
|
||||
// Set SSO Url
|
||||
const authMethodUrl = `${formData.base_url}/_matrix/client/r0/login`;
|
||||
let supportPass = false,
|
||||
supportSSO = false;
|
||||
fetchUtils
|
||||
.fetchJson(authMethodUrl, { method: "GET" })
|
||||
.then(({ json }) => {
|
||||
json.flows.forEach(f => {
|
||||
if (f.type === "m.login.password") {
|
||||
supportPass = true;
|
||||
} else if (f.type === "m.login.sso") {
|
||||
supportSSO = true;
|
||||
}
|
||||
});
|
||||
setSupportPassAuth(supportPass);
|
||||
if (supportSSO) {
|
||||
setSSOBaseUrl(formData.base_url);
|
||||
} else {
|
||||
setSSOBaseUrl("");
|
||||
}
|
||||
})
|
||||
.catch(_ => {
|
||||
setSSOBaseUrl("");
|
||||
});
|
||||
},
|
||||
[formData.base_url]
|
||||
);
|
||||
// Set SSO Url
|
||||
getSupportedLoginFlows(formData.base_url)
|
||||
.then(loginFlows => {
|
||||
const supportPass =
|
||||
loginFlows.find(f => f.type === "m.login.password") !== undefined;
|
||||
const supportSSO =
|
||||
loginFlows.find(f => f.type === "m.login.sso") !== undefined;
|
||||
setSupportPassAuth(supportPass);
|
||||
setSSOBaseUrl(supportSSO ? formData.base_url : "");
|
||||
})
|
||||
.catch(() => setSSOBaseUrl(""));
|
||||
}, [formData.base_url]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
48
src/synapse/synapse.js
Normal file
48
src/synapse/synapse.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
import { fetchUtils } from "react-admin";
|
||||
|
||||
export const splitMxid = mxid => {
|
||||
const re =
|
||||
/^@(?<name>[a-zA-Z0-9._=\-/]+):(?<domain>[a-zA-Z0-9\-.]+\.[a-zA-Z]+)$/;
|
||||
return re.exec(mxid)?.groups;
|
||||
};
|
||||
|
||||
export const isValidBaseUrl = baseUrl =>
|
||||
/^(http|https):\/\/[a-zA-Z0-9\-.]+(:\d{1,5})?$/.test(baseUrl);
|
||||
|
||||
/**
|
||||
* Resolve the homeserver URL using the well-known lookup
|
||||
* @param domain the domain part of an MXID
|
||||
* @returns homeserver base URL
|
||||
*/
|
||||
export const getWellKnownUrl = async domain => {
|
||||
const wellKnownUrl = `https://${domain}/.well-known/matrix/client`;
|
||||
try {
|
||||
const json = await fetchUtils.fetchJson(wellKnownUrl, { method: "GET" });
|
||||
return json["m.homeserver"].base_url;
|
||||
} catch {
|
||||
// if there is no .well-known entry, return the domain itself
|
||||
return `https://${domain}`;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get synapse server version
|
||||
* @param base_url the base URL of the homeserver
|
||||
* @returns server version
|
||||
*/
|
||||
export const getServerVersion = async baseUrl => {
|
||||
const versionUrl = `${baseUrl}/_synapse/admin/v1/server_version`;
|
||||
const response = await fetchUtils.fetchJson(versionUrl, { method: "GET" });
|
||||
return response.json.server_version;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get supported login flows
|
||||
* @param baseUrl the base URL of the homeserver
|
||||
* @returns array of supported login flows
|
||||
*/
|
||||
export const getSupportedLoginFlows = async baseUrl => {
|
||||
const loginFlowsUrl = `${baseUrl}/_matrix/client/r0/login`;
|
||||
const response = await fetchUtils.fetchJson(loginFlowsUrl, { method: "GET" });
|
||||
return response.json.flows;
|
||||
};
|
31
src/synapse/synapse.test.js
Normal file
31
src/synapse/synapse.test.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { isValidBaseUrl, splitMxid } from "./synapse";
|
||||
|
||||
describe("splitMxid", () => {
|
||||
it("splits valid MXIDs", () =>
|
||||
expect(splitMxid("@name:domain.tld")).toEqual({
|
||||
name: "name",
|
||||
domain: "domain.tld",
|
||||
}));
|
||||
it("rejects invalid MXIDs", () => expect(splitMxid("foo")).toBeUndefined());
|
||||
});
|
||||
|
||||
describe("isValidBaseUrl", () => {
|
||||
it("accepts a http URL", () =>
|
||||
expect(isValidBaseUrl("http://foo.bar")).toBeTruthy());
|
||||
it("accepts a https URL", () =>
|
||||
expect(isValidBaseUrl("https://foo.bar")).toBeTruthy());
|
||||
it("accepts a valid URL with port", () =>
|
||||
expect(isValidBaseUrl("https://foo.bar:1234")).toBeTruthy());
|
||||
it("rejects undefined base URLs", () =>
|
||||
expect(isValidBaseUrl(undefined)).toBeFalsy());
|
||||
it("rejects null base URLs", () => expect(isValidBaseUrl(null)).toBeFalsy());
|
||||
it("rejects empty base URLs", () => expect(isValidBaseUrl("")).toBeFalsy());
|
||||
it("rejects non-string base URLs", () =>
|
||||
expect(isValidBaseUrl({})).toBeFalsy());
|
||||
it("rejects base URLs without protocol", () =>
|
||||
expect(isValidBaseUrl("foo.bar")).toBeFalsy());
|
||||
it("rejects base URLs with path", () =>
|
||||
expect(isValidBaseUrl("http://foo.bar/path")).toBeFalsy());
|
||||
it("rejects invalid base URLs", () =>
|
||||
expect(isValidBaseUrl("http:/foo.bar")).toBeFalsy());
|
||||
});
|
Loading…
Reference in a new issue