mirror of
https://github.com/UA-Fediland/synapse-admin.git
synced 2024-11-21 22:11:27 +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 React, { useState, useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
fetchUtils,
|
|
||||||
Form,
|
Form,
|
||||||
FormDataConsumer,
|
FormDataConsumer,
|
||||||
Notification,
|
Notification,
|
||||||
|
@ -27,6 +26,13 @@ import {
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { styled } from "@mui/material/styles";
|
import { styled } from "@mui/material/styles";
|
||||||
import LockIcon from "@mui/icons-material/Lock";
|
import LockIcon from "@mui/icons-material/Lock";
|
||||||
|
import {
|
||||||
|
getServerVersion,
|
||||||
|
getSupportedLoginFlows,
|
||||||
|
getWellKnownUrl,
|
||||||
|
isValidBaseUrl,
|
||||||
|
splitMxid,
|
||||||
|
} from "../synapse/synapse";
|
||||||
|
|
||||||
const FormBox = styled(Box)(({ theme }) => ({
|
const FormBox = styled(Box)(({ theme }) => ({
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
@ -170,87 +176,42 @@ const LoginPage = () => {
|
||||||
window.location.href = ssoFullUrl;
|
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 UserData = ({ formData }) => {
|
||||||
const form = useFormContext();
|
const form = useFormContext();
|
||||||
const [serverVersion, setServerVersion] = useState("");
|
const [serverVersion, setServerVersion] = useState("");
|
||||||
|
|
||||||
const handleUsernameChange = _ => {
|
const handleUsernameChange = _ => {
|
||||||
if (formData.base_url || cfg_base_url) return;
|
if (formData.base_url || cfg_base_url) return;
|
||||||
// check if username is a full qualified userId then set base_url accordially
|
// check if username is a full qualified userId then set base_url accordingly
|
||||||
const home_server = extractHomeServer(formData.username);
|
const domain = splitMxid(formData.username)?.domain;
|
||||||
const wellKnownUrl = `https://${home_server}/.well-known/matrix/client`;
|
if (domain) {
|
||||||
if (home_server) {
|
getWellKnownUrl(domain).then(url => form.setValue("base_url", url));
|
||||||
// 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}`);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(
|
useEffect(() => {
|
||||||
_ => {
|
if (!isValidBaseUrl(formData.base_url)) return;
|
||||||
if (
|
|
||||||
!formData.base_url ||
|
getServerVersion(formData.base_url)
|
||||||
!formData.base_url.match(
|
.then(serverVersion =>
|
||||||
/^(http|https):\/\/[a-zA-Z0-9\-.]+(:\d{1,5})?$/
|
setServerVersion(
|
||||||
|
`${translate("synapseadmin.auth.server_version")} ${serverVersion}`
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return;
|
.catch(() => setServerVersion(""));
|
||||||
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("");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set SSO Url
|
// Set SSO Url
|
||||||
const authMethodUrl = `${formData.base_url}/_matrix/client/r0/login`;
|
getSupportedLoginFlows(formData.base_url)
|
||||||
let supportPass = false,
|
.then(loginFlows => {
|
||||||
supportSSO = false;
|
const supportPass =
|
||||||
fetchUtils
|
loginFlows.find(f => f.type === "m.login.password") !== undefined;
|
||||||
.fetchJson(authMethodUrl, { method: "GET" })
|
const supportSSO =
|
||||||
.then(({ json }) => {
|
loginFlows.find(f => f.type === "m.login.sso") !== undefined;
|
||||||
json.flows.forEach(f => {
|
setSupportPassAuth(supportPass);
|
||||||
if (f.type === "m.login.password") {
|
setSSOBaseUrl(supportSSO ? formData.base_url : "");
|
||||||
supportPass = true;
|
})
|
||||||
} else if (f.type === "m.login.sso") {
|
.catch(() => setSSOBaseUrl(""));
|
||||||
supportSSO = true;
|
}, [formData.base_url]);
|
||||||
}
|
|
||||||
});
|
|
||||||
setSupportPassAuth(supportPass);
|
|
||||||
if (supportSSO) {
|
|
||||||
setSSOBaseUrl(formData.base_url);
|
|
||||||
} else {
|
|
||||||
setSSOBaseUrl("");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(_ => {
|
|
||||||
setSSOBaseUrl("");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[formData.base_url]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
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