Fix server info version display with restrictBaseUrl values

This commit is contained in:
Borislav Pantaleev 2025-06-03 23:37:51 +03:00
parent f7d46a4cec
commit 9c1838031c

View File

@ -23,6 +23,7 @@ import {
useTranslate, useTranslate,
PasswordInput, PasswordInput,
TextInput, TextInput,
SelectInput,
useLocales, useLocales,
} from "react-admin"; } from "react-admin";
import { useFormContext } from "react-hook-form"; import { useFormContext } from "react-hook-form";
@ -51,16 +52,31 @@ const LoginPage = () => {
restrictBaseUrl.length > 0 && restrictBaseUrl.length > 0 &&
restrictBaseUrl[0] !== "" && restrictBaseUrl[0] !== "" &&
restrictBaseUrl[0] !== null; restrictBaseUrl[0] !== null;
const baseUrlChoices = allowMultipleBaseUrls ? restrictBaseUrl.map(url => ({ id: url, name: url })) : [];
const allowAnyBaseUrl = !(allowSingleBaseUrl || allowMultipleBaseUrls); const allowAnyBaseUrl = !(allowSingleBaseUrl || allowMultipleBaseUrls);
const localStorageBaseUrl = localStorage.getItem("base_url");
let base_url = allowSingleBaseUrl ? restrictBaseUrl : localStorageBaseUrl;
if (allowMultipleBaseUrls && localStorageBaseUrl && !restrictBaseUrl.includes(localStorageBaseUrl)) {
// don't set base_url if it is not in the restrictBaseUrl array
base_url = null;
}
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [supportPassAuth, setSupportPassAuth] = useState(true); const [supportPassAuth, setSupportPassAuth] = useState(true);
const [locale, setLocale] = useLocaleState(); const [locale, setLocale] = useLocaleState();
const locales = useLocales(); const locales = useLocales();
const translate = useTranslate(); const translate = useTranslate();
const base_url = allowSingleBaseUrl ? restrictBaseUrl : localStorage.getItem("base_url");
const [ssoBaseUrl, setSSOBaseUrl] = useState(""); const [ssoBaseUrl, setSSOBaseUrl] = useState("");
const loginToken = new URLSearchParams(window.location.search).get("loginToken"); const loginToken = new URLSearchParams(window.location.search).get("loginToken");
const [loginMethod, setLoginMethod] = useState<LoginMethod>("credentials"); const [loginMethod, setLoginMethod] = useState<LoginMethod>("credentials");
const [serverVersion, setServerVersion] = useState("");
const [matrixVersions, setMatrixVersions] = useState("");
useEffect(() => {
if (base_url) {
checkServerInfo(base_url);
}
}, []);
useEffect(() => { useEffect(() => {
if (!loginToken) { if (!loginToken) {
@ -133,66 +149,77 @@ const LoginPage = () => {
window.location.href = ssoFullUrl; window.location.href = ssoFullUrl;
}; };
const checkServerInfo = async (url: string) => {
if (!isValidBaseUrl(url)) {
setServerVersion("");
setMatrixVersions("");
setSupportPassAuth(false);
setSSOBaseUrl("");
return;
}
try {
const serverVersion = await getServerVersion(url);
setServerVersion(`${translate("synapseadmin.auth.server_version")} ${serverVersion}`);
} catch (error) {
setServerVersion("");
}
try {
const features = await getSupportedFeatures(url);
setMatrixVersions(`${translate("synapseadmin.auth.supports_specs")} ${features.versions.join(", ")}`);
} catch (error) {
setMatrixVersions("");
}
// Set SSO Url
try {
const loginFlows = await getSupportedLoginFlows(url);
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 ? url : "");
} catch (error) {
setSupportPassAuth(false);
setSSOBaseUrl("");
}
};
const UserData = ({ formData }) => { const UserData = ({ formData }) => {
const form = useFormContext(); const form = useFormContext();
const [serverVersion, setServerVersion] = useState("");
const [matrixVersions, setMatrixVersions] = useState("");
const handleUsernameChange = () => { const handleUsernameChange = async () => {
if (formData.base_url || allowSingleBaseUrl) { if (formData.base_url || allowSingleBaseUrl) {
return; return;
} }
// check if username is a full qualified userId then set base_url accordingly // check if username is a full qualified userId then set base_url accordingly
const domain = splitMxid(formData.username)?.domain; const domain = splitMxid(formData.username)?.domain;
if (domain) { if (domain) {
getWellKnownUrl(domain).then(url => { const url = await getWellKnownUrl(domain);
if (allowAnyBaseUrl || (allowMultipleBaseUrls && restrictBaseUrl.includes(url))) { if (allowAnyBaseUrl || (allowMultipleBaseUrls && restrictBaseUrl.includes(url))) {
form.setValue("base_url", url, { form.setValue("base_url", url, {
shouldValidate: true, shouldValidate: true,
shouldDirty: true, shouldDirty: true,
}); });
checkServerInfo(url); checkServerInfo(url);
} }
});
} }
}; };
const checkServerInfo = (url: string) => { const handleBaseUrlBlurOrChange = (event) => {
if (!isValidBaseUrl(url)) return; // Get the value either from the event (onChange) or from formData (onBlur)
const value = event?.target?.value || formData.base_url;
getServerVersion(url) if (!value) {
.then(serverVersion => setServerVersion(`${translate("synapseadmin.auth.server_version")} ${serverVersion}`)) return;
.catch(() => setServerVersion("")); }
getSupportedFeatures(url) // Trigger validation only when user finishes typing/selecting
.then(features =>
setMatrixVersions(`${translate("synapseadmin.auth.supports_specs")} ${features.versions.join(", ")}`)
)
.catch(() => setMatrixVersions(""));
// Set SSO Url
getSupportedLoginFlows(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 ? url : "");
})
.catch(() => setSSOBaseUrl(""));
};
const handleBaseUrlBlur = () => {
// Trigger validation only when user finishes typing
form.trigger("base_url"); form.trigger("base_url");
checkServerInfo(formData.base_url); checkServerInfo(value);
}; };
useEffect(() => {
if (formData.base_url === "" && allowMultipleBaseUrls) {
form.setValue("base_url", restrictBaseUrl[0]);
}
}, [formData.base_url, form]);
useEffect(() => { useEffect(() => {
const params = new URLSearchParams(window.location.search); const params = new URLSearchParams(window.location.search);
const hostname = window.location.hostname; const hostname = window.location.hostname;
@ -280,24 +307,29 @@ const LoginPage = () => {
</Box> </Box>
)} )}
<Box> <Box>
<TextInput {allowMultipleBaseUrls && (
<SelectInput
source="base_url"
label="synapseadmin.auth.base_url"
select={allowMultipleBaseUrls}
autoComplete="url"
{...(loading ? { disabled: true } : {})}
onChange={handleBaseUrlBlurOrChange}
validate={[required(), validateBaseUrl]}
choices={baseUrlChoices}
/>
)}
{!allowMultipleBaseUrls && (<TextInput
source="base_url" source="base_url"
label="synapseadmin.auth.base_url" label="synapseadmin.auth.base_url"
select={allowMultipleBaseUrls}
autoComplete="url" autoComplete="url"
{...(loading ? { disabled: true } : {})} {...(loading ? { disabled: true } : {})}
readOnly={allowSingleBaseUrl} readOnly={allowSingleBaseUrl}
resettable={allowAnyBaseUrl} resettable={allowAnyBaseUrl}
validate={[required(), validateBaseUrl]} validate={[required(), validateBaseUrl]}
onBlur={handleBaseUrlBlur} onBlur={handleBaseUrlBlurOrChange}
> />
{allowMultipleBaseUrls && )}
restrictBaseUrl.map(url => (
<MenuItem key={url} value={url}>
{url}
</MenuItem>
))}
</TextInput>
</Box> </Box>
<Typography className="serverVersion">{serverVersion}</Typography> <Typography className="serverVersion">{serverVersion}</Typography>
<Typography className="matrixVersions">{matrixVersions}</Typography> <Typography className="matrixVersions">{matrixVersions}</Typography>