Extract homeserver URL from fully qualified user id

Also lookup the .well-known entry and use it if available.

Change-Id: I609046f01860fd5e3ba8cb801006e6098a4ad840
This commit is contained in:
Michael Albert 2020-04-30 21:22:35 +02:00 committed by Manuel Stahl
parent 2d0ce50444
commit 50b770a312
3 changed files with 88 additions and 46 deletions

View file

@ -1,5 +1,7 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { import {
fetchUtils,
FormDataConsumer,
Notification, Notification,
useLogin, useLogin,
useNotify, useNotify,
@ -9,7 +11,7 @@ import {
PasswordInput, PasswordInput,
TextInput, TextInput,
} from "react-admin"; } from "react-admin";
import { Form } from "react-final-form"; import { Form, useForm } from "react-final-form";
import { import {
Avatar, Avatar,
Button, Button,
@ -36,7 +38,7 @@ const useStyles = makeStyles(theme => ({
backgroundSize: "cover", backgroundSize: "cover",
}, },
card: { card: {
minWidth: 300, minWidth: "30em",
marginTop: "6em", marginTop: "6em",
}, },
avatar: { avatar: {
@ -72,7 +74,7 @@ const LoginPage = ({ theme }) => {
var locale = useLocale(); var locale = useLocale();
const setLocale = useSetLocale(); const setLocale = useSetLocale();
const translate = useTranslate(); const translate = useTranslate();
const homeserver = localStorage.getItem("base_url"); const base_url = localStorage.getItem("base_url");
const renderInput = ({ const renderInput = ({
meta: { touched, error } = {}, meta: { touched, error } = {},
@ -90,23 +92,21 @@ const LoginPage = ({ theme }) => {
const validate = values => { const validate = values => {
const errors = {}; const errors = {};
if (!values.homeserver) {
errors.homeserver = translate("ra.validation.required");
} else {
if (!values.homeserver.match(/^(http|https):\/\//)) {
errors.homeserver = translate("synapseadmin.auth.protocol_error");
} else if (
!values.homeserver.match(/^(http|https):\/\/[a-zA-Z0-9\-.]+$/)
) {
errors.homeserver = translate("synapseadmin.auth.url_error");
}
}
if (!values.username) { if (!values.username) {
errors.username = translate("ra.validation.required"); errors.username = translate("ra.validation.required");
} }
if (!values.password) { if (!values.password) {
errors.password = translate("ra.validation.required"); errors.password = translate("ra.validation.required");
} }
if (!values.base_url) {
errors.base_url = translate("ra.validation.required");
} else {
if (!values.base_url.match(/^(http|https):\/\//)) {
errors.base_url = translate("synapseadmin.auth.protocol_error");
} else if (!values.base_url.match(/^(http|https):\/\/[a-zA-Z0-9\-.]+$/)) {
errors.base_url = translate("synapseadmin.auth.url_error");
}
}
return errors; return errors;
}; };
@ -125,9 +125,75 @@ const LoginPage = ({ theme }) => {
}); });
}; };
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 = useForm();
const handleUsernameChange = _ => {
if (formData.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.change("base_url", json["m.homeserver"].base_url);
})
.catch(_ => {
// if there is no .well-known entry, try the home server name
form.change("base_url", `https://${home_server}`);
});
}
};
return (
<div>
<div className={classes.input}>
<TextInput
autoFocus
name="username"
component={renderInput}
label={translate("ra.auth.username")}
disabled={loading}
onBlur={handleUsernameChange}
fullWidth
/>
</div>
<div className={classes.input}>
<PasswordInput
name="password"
component={renderInput}
label={translate("ra.auth.password")}
type="password"
disabled={loading}
fullWidth
/>
</div>
<div className={classes.input}>
<TextInput
name="base_url"
component={renderInput}
label={translate("synapseadmin.auth.base_url")}
disabled={loading}
fullWidth
/>
</div>
</div>
);
};
return ( return (
<Form <Form
initialValues={{ homeserver: homeserver }} initialValues={{ base_url: base_url }}
onSubmit={handleSubmit} onSubmit={handleSubmit}
validate={validate} validate={validate}
render={({ handleSubmit }) => ( render={({ handleSubmit }) => (
@ -156,35 +222,9 @@ const LoginPage = ({ theme }) => {
<MenuItem value="en">English</MenuItem> <MenuItem value="en">English</MenuItem>
</Select> </Select>
</div> </div>
<div className={classes.input}> <FormDataConsumer>
<TextInput {formDataProps => <UserData {...formDataProps} />}
name="homeserver" </FormDataConsumer>
component={renderInput}
label={translate("synapseadmin.auth.homeserver")}
disabled={loading}
fullWidth
/>
</div>
<div className={classes.input}>
<TextInput
autoFocus
name="username"
component={renderInput}
label={translate("ra.auth.username")}
disabled={loading}
fullWidth
/>
</div>
<div className={classes.input}>
<PasswordInput
name="password"
component={renderInput}
label={translate("ra.auth.password")}
type="password"
disabled={loading}
fullWidth
/>
</div>
</div> </div>
<CardActions className={classes.actions}> <CardActions className={classes.actions}>
<Button <Button

View file

@ -4,8 +4,9 @@ export default {
...germanMessages, ...germanMessages,
synapseadmin: { synapseadmin: {
auth: { auth: {
homeserver: "Heimserver", base_url: "Heimserver URL",
welcome: "Willkommen bei Synapse-admin", welcome: "Willkommen bei Synapse-admin",
username_error: "Bitte vollständigen Nutzernamen angeben: '@user:domain'",
protocol_error: "Die URL muss mit 'http://' oder 'https://' beginnen", protocol_error: "Die URL muss mit 'http://' oder 'https://' beginnen",
url_error: "Keine gültige Matrix Server URL", url_error: "Keine gültige Matrix Server URL",
}, },

View file

@ -4,8 +4,9 @@ export default {
...englishMessages, ...englishMessages,
synapseadmin: { synapseadmin: {
auth: { auth: {
homeserver: "Homeserver", base_url: "Homeserver URL",
welcome: "Welcome to Synapse-admin", welcome: "Welcome to Synapse-admin",
username_error: "Please enter fully qualified user ID: '@user:domain'",
protocol_error: "URL has to start with 'http://' or 'https://'", protocol_error: "URL has to start with 'http://' or 'https://'",
url_error: "Not a valid Matrix server URL", url_error: "Not a valid Matrix server URL",
}, },