Merge pull request #2669 from matrix-org/jryans/default-server-name

Restores support for `default_server_name` which discovers URLs via `.well-known`
This commit is contained in:
J. Ryan Stinnett 2019-02-21 10:38:15 +00:00 committed by GitHub
commit 16b9688303
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 136 additions and 82 deletions

View file

@ -1887,6 +1887,7 @@ export default React.createClass({
sessionId={this.state.register_session_id} sessionId={this.state.register_session_id}
idSid={this.state.register_id_sid} idSid={this.state.register_id_sid}
email={this.props.startingFragmentQueryParams.email} email={this.props.startingFragmentQueryParams.email}
defaultServerName={this.getDefaultServerName()}
defaultServerDiscoveryError={this.state.defaultServerDiscoveryError} defaultServerDiscoveryError={this.state.defaultServerDiscoveryError}
defaultHsUrl={this.getDefaultHsUrl()} defaultHsUrl={this.getDefaultHsUrl()}
defaultIsUrl={this.getDefaultIsUrl()} defaultIsUrl={this.getDefaultIsUrl()}
@ -1923,6 +1924,7 @@ export default React.createClass({
<Login <Login
onLoggedIn={Lifecycle.setLoggedIn} onLoggedIn={Lifecycle.setLoggedIn}
onRegisterClick={this.onRegisterClick} onRegisterClick={this.onRegisterClick}
defaultServerName={this.getDefaultServerName()}
defaultServerDiscoveryError={this.state.defaultServerDiscoveryError} defaultServerDiscoveryError={this.state.defaultServerDiscoveryError}
defaultHsUrl={this.getDefaultHsUrl()} defaultHsUrl={this.getDefaultHsUrl()}
defaultIsUrl={this.getDefaultIsUrl()} defaultIsUrl={this.getDefaultIsUrl()}

View file

@ -41,20 +41,22 @@ module.exports = React.createClass({
displayName: 'ForgotPassword', displayName: 'ForgotPassword',
propTypes: { propTypes: {
// The default server name to use when the user hasn't specified
// one. If set, `defaultHsUrl` and `defaultHsUrl` were derived for this
// via `.well-known` discovery. The server name is used instead of the
// HS URL when talking about "your account".
defaultServerName: PropTypes.string,
// An error passed along from higher up explaining that something
// went wrong when finding the defaultHsUrl.
defaultServerDiscoveryError: PropTypes.string,
defaultHsUrl: PropTypes.string, defaultHsUrl: PropTypes.string,
defaultIsUrl: PropTypes.string, defaultIsUrl: PropTypes.string,
customHsUrl: PropTypes.string, customHsUrl: PropTypes.string,
customIsUrl: PropTypes.string, customIsUrl: PropTypes.string,
onLoginClick: PropTypes.func, onLoginClick: PropTypes.func,
onComplete: PropTypes.func.isRequired, onComplete: PropTypes.func.isRequired,
// The default server name to use when the user hasn't specified
// one. This is used when displaying the defaultHsUrl in the UI.
defaultServerName: PropTypes.string,
// An error passed along from higher up explaining that something
// went wrong when finding the defaultHsUrl.
defaultServerDiscoveryError: PropTypes.string,
}, },
getInitialState: function() { getInitialState: function() {
@ -234,19 +236,25 @@ module.exports = React.createClass({
errorText = <div className="mx_Login_error">{ err }</div>; errorText = <div className="mx_Login_error">{ err }</div>;
} }
let yourMatrixAccountText = _t('Your account'); let yourMatrixAccountText = _t('Your Matrix account');
try { if (this.state.enteredHsUrl === this.props.defaultHsUrl) {
const parsedHsUrl = new URL(this.state.enteredHsUrl); yourMatrixAccountText = _t('Your Matrix account on %(serverName)s', {
yourMatrixAccountText = _t('Your account on %(serverName)s', { serverName: this.props.defaultServerName,
serverName: parsedHsUrl.hostname,
}); });
} catch (e) { } else {
errorText = <div className="mx_Login_error">{_t( try {
"The homeserver URL %(hsUrl)s doesn't seem to be valid URL. Please " + const parsedHsUrl = new URL(this.state.enteredHsUrl);
"enter a valid URL including the protocol prefix.", yourMatrixAccountText = _t('Your Matrix account on %(serverName)s', {
{ serverName: parsedHsUrl.hostname,
hsUrl: this.state.enteredHsUrl, });
})}</div>; } catch (e) {
errorText = <div className="mx_Login_error">{_t(
"The homeserver URL %(hsUrl)s doesn't seem to be valid URL. Please " +
"enter a valid URL including the protocol prefix.",
{
hsUrl: this.state.enteredHsUrl,
})}</div>;
}
} }
// If custom URLs are allowed, wire up the server details edit link. // If custom URLs are allowed, wire up the server details edit link.

View file

@ -56,6 +56,15 @@ module.exports = React.createClass({
enableGuest: PropTypes.bool, enableGuest: PropTypes.bool,
// The default server name to use when the user hasn't specified
// one. If set, `defaultHsUrl` and `defaultHsUrl` were derived for this
// via `.well-known` discovery. The server name is used instead of the
// HS URL when talking about where to "sign in to".
defaultServerName: PropTypes.string,
// An error passed along from higher up explaining that something
// went wrong when finding the defaultHsUrl.
defaultServerDiscoveryError: PropTypes.string,
customHsUrl: PropTypes.string, customHsUrl: PropTypes.string,
customIsUrl: PropTypes.string, customIsUrl: PropTypes.string,
defaultHsUrl: PropTypes.string, defaultHsUrl: PropTypes.string,
@ -65,10 +74,6 @@ module.exports = React.createClass({
// different homeserver without confusing users. // different homeserver without confusing users.
fallbackHsUrl: PropTypes.string, fallbackHsUrl: PropTypes.string,
// An error passed along from higher up explaining that something
// went wrong when finding the defaultHsUrl.
defaultServerDiscoveryError: PropTypes.string,
defaultDeviceDisplayName: PropTypes.string, defaultDeviceDisplayName: PropTypes.string,
// login shouldn't know or care how registration is done. // login shouldn't know or care how registration is done.
@ -563,11 +568,20 @@ module.exports = React.createClass({
_renderPasswordStep: function() { _renderPasswordStep: function() {
const PasswordLogin = sdk.getComponent('auth.PasswordLogin'); const PasswordLogin = sdk.getComponent('auth.PasswordLogin');
let onEditServerDetailsClick = null; let onEditServerDetailsClick = null;
// If custom URLs are allowed, wire up the server details edit link. // If custom URLs are allowed, wire up the server details edit link.
if (PHASES_ENABLED && !SdkConfig.get()['disable_custom_urls']) { if (PHASES_ENABLED && !SdkConfig.get()['disable_custom_urls']) {
onEditServerDetailsClick = this.onEditServerDetailsClick; onEditServerDetailsClick = this.onEditServerDetailsClick;
} }
// If the current HS URL is the default HS URL, then we can label it
// with the default HS name (if it exists).
let hsName;
if (this.state.enteredHsUrl === this.props.defaultHsUrl) {
hsName = this.props.defaultServerName;
}
return ( return (
<PasswordLogin <PasswordLogin
onSubmit={this.onPasswordLogin} onSubmit={this.onPasswordLogin}
@ -583,6 +597,7 @@ module.exports = React.createClass({
onPhoneNumberBlur={this.onPhoneNumberBlur} onPhoneNumberBlur={this.onPhoneNumberBlur}
onForgotPasswordClick={this.props.onForgotPasswordClick} onForgotPasswordClick={this.props.onForgotPasswordClick}
loginIncorrect={this.state.loginIncorrect} loginIncorrect={this.state.loginIncorrect}
hsName={hsName}
hsUrl={this.state.enteredHsUrl} hsUrl={this.state.enteredHsUrl}
disableSubmit={this.state.findingHomeserver} disableSubmit={this.state.findingHomeserver}
/> />

View file

@ -48,15 +48,20 @@ module.exports = React.createClass({
sessionId: PropTypes.string, sessionId: PropTypes.string,
makeRegistrationUrl: PropTypes.func.isRequired, makeRegistrationUrl: PropTypes.func.isRequired,
idSid: PropTypes.string, idSid: PropTypes.string,
// The default server name to use when the user hasn't specified
// one. If set, `defaultHsUrl` and `defaultHsUrl` were derived for this
// via `.well-known` discovery. The server name is used instead of the
// HS URL when talking about "your account".
defaultServerName: PropTypes.string,
// An error passed along from higher up explaining that something
// went wrong when finding the defaultHsUrl.
defaultServerDiscoveryError: PropTypes.string,
customHsUrl: PropTypes.string, customHsUrl: PropTypes.string,
customIsUrl: PropTypes.string, customIsUrl: PropTypes.string,
defaultHsUrl: PropTypes.string, defaultHsUrl: PropTypes.string,
defaultIsUrl: PropTypes.string, defaultIsUrl: PropTypes.string,
brand: PropTypes.string, brand: PropTypes.string,
email: PropTypes.string, email: PropTypes.string,
// An error passed along from higher up explaining that something
// went wrong when finding the defaultHsUrl.
defaultServerDiscoveryError: PropTypes.string,
// registration shouldn't know or care how login is done. // registration shouldn't know or care how login is done.
onLoginClick: PropTypes.func.isRequired, onLoginClick: PropTypes.func.isRequired,
onServerConfigChange: PropTypes.func.isRequired, onServerConfigChange: PropTypes.func.isRequired,
@ -94,7 +99,7 @@ module.exports = React.createClass({
// If we've been given a session ID, we're resuming // If we've been given a session ID, we're resuming
// straight back into UI auth // straight back into UI auth
doingUIAuth: Boolean(this.props.sessionId), doingUIAuth: Boolean(this.props.sessionId),
serverType: null, serverType: ServerType.getTypeFromHsUrl(this.props.customHsUrl),
hsUrl: this.props.customHsUrl, hsUrl: this.props.customHsUrl,
isUrl: this.props.customIsUrl, isUrl: this.props.customIsUrl,
// Phase of the overall registration dialog. // Phase of the overall registration dialog.
@ -122,7 +127,7 @@ module.exports = React.createClass({
}); });
}, },
onServerTypeChange(type, initial) { onServerTypeChange(type) {
this.setState({ this.setState({
serverType: type, serverType: type,
}); });
@ -148,15 +153,10 @@ module.exports = React.createClass({
hsUrl: this.props.defaultHsUrl, hsUrl: this.props.defaultHsUrl,
isUrl: this.props.defaultIsUrl, isUrl: this.props.defaultIsUrl,
}); });
// if this is the initial value from the control and we're // Reset back to server details on type change.
// already in the registration phase, don't go back to the this.setState({
// server details phase (but do if it's actually a change resulting phase: PHASE_SERVER_DETAILS,
// from user interaction). });
if (!initial || !this.state.phase === PHASE_REGISTRATION) {
this.setState({
phase: PHASE_SERVER_DETAILS,
});
}
break; break;
} }
}, },
@ -389,12 +389,9 @@ module.exports = React.createClass({
// If we're on a different phase, we only show the server type selector, // If we're on a different phase, we only show the server type selector,
// which is always shown if we allow custom URLs at all. // which is always shown if we allow custom URLs at all.
if (PHASES_ENABLED && this.state.phase !== PHASE_SERVER_DETAILS) { if (PHASES_ENABLED && this.state.phase !== PHASE_SERVER_DETAILS) {
// if we've been given a custom HS URL we should actually pass that, so
// that the appropriate section is selected at the start to match the
// homeserver URL we're using
return <div> return <div>
<ServerTypeSelector <ServerTypeSelector
defaultHsUrl={this.props.customHsUrl || this.props.defaultHsUrl} selected={this.state.serverType}
onChange={this.onServerTypeChange} onChange={this.onServerTypeChange}
/> />
</div>; </div>;
@ -436,7 +433,7 @@ module.exports = React.createClass({
return <div> return <div>
<ServerTypeSelector <ServerTypeSelector
defaultHsUrl={this.props.defaultHsUrl} selected={this.state.serverType}
onChange={this.onServerTypeChange} onChange={this.onServerTypeChange}
/> />
{serverDetails} {serverDetails}
@ -478,6 +475,14 @@ module.exports = React.createClass({
) { ) {
onEditServerDetailsClick = this.onEditServerDetailsClick; onEditServerDetailsClick = this.onEditServerDetailsClick;
} }
// If the current HS URL is the default HS URL, then we can label it
// with the default HS name (if it exists).
let hsName;
if (this.state.hsUrl === this.props.defaultHsUrl) {
hsName = this.props.defaultServerName;
}
return <RegistrationForm return <RegistrationForm
defaultUsername={this.state.formVals.username} defaultUsername={this.state.formVals.username}
defaultEmail={this.state.formVals.email} defaultEmail={this.state.formVals.email}
@ -489,6 +494,7 @@ module.exports = React.createClass({
onRegisterClick={this.onFormSubmit} onRegisterClick={this.onFormSubmit}
onEditServerDetailsClick={onEditServerDetailsClick} onEditServerDetailsClick={onEditServerDetailsClick}
flows={this.state.flows} flows={this.state.flows}
hsName={hsName}
hsUrl={this.state.hsUrl} hsUrl={this.state.hsUrl}
/>; />;
} }

View file

@ -40,6 +40,10 @@ class PasswordLogin extends React.Component {
initialPhoneNumber: "", initialPhoneNumber: "",
initialPassword: "", initialPassword: "",
loginIncorrect: false, loginIncorrect: false,
// This is optional and only set if we used a server name to determine
// the HS URL via `.well-known` discovery. The server name is used
// instead of the HS URL when talking about where to "sign in to".
hsName: null,
hsUrl: "", hsUrl: "",
disableSubmit: false, disableSubmit: false,
} }
@ -54,6 +58,7 @@ class PasswordLogin extends React.Component {
loginType: PasswordLogin.LOGIN_FIELD_MXID, loginType: PasswordLogin.LOGIN_FIELD_MXID,
}; };
this.onForgotPasswordClick = this.onForgotPasswordClick.bind(this);
this.onSubmitForm = this.onSubmitForm.bind(this); this.onSubmitForm = this.onSubmitForm.bind(this);
this.onUsernameChanged = this.onUsernameChanged.bind(this); this.onUsernameChanged = this.onUsernameChanged.bind(this);
this.onUsernameBlur = this.onUsernameBlur.bind(this); this.onUsernameBlur = this.onUsernameBlur.bind(this);
@ -70,6 +75,12 @@ class PasswordLogin extends React.Component {
this._loginField = null; this._loginField = null;
} }
onForgotPasswordClick(ev) {
ev.preventDefault();
ev.stopPropagation();
this.props.onForgotPasswordClick();
}
onSubmitForm(ev) { onSubmitForm(ev) {
ev.preventDefault(); ev.preventDefault();
@ -240,7 +251,7 @@ class PasswordLogin extends React.Component {
forgotPasswordJsx = <span> forgotPasswordJsx = <span>
{_t('Not sure of your password? <a>Set a new one</a>', {}, { {_t('Not sure of your password? <a>Set a new one</a>', {}, {
a: sub => <a className="mx_Login_forgot" a: sub => <a className="mx_Login_forgot"
onClick={this.props.onForgotPasswordClick} onClick={this.onForgotPasswordClick}
href="#" href="#"
> >
{sub} {sub}
@ -249,14 +260,20 @@ class PasswordLogin extends React.Component {
</span>; </span>;
} }
let signInToText = _t('Sign in'); let signInToText = _t('Sign in to your Matrix account');
try { if (this.props.hsName) {
const parsedHsUrl = new URL(this.props.hsUrl); signInToText = _t('Sign in to your Matrix account on %(serverName)s', {
signInToText = _t('Sign in to %(serverName)s', { serverName: this.props.hsName,
serverName: parsedHsUrl.hostname,
}); });
} catch (e) { } else {
// ignore try {
const parsedHsUrl = new URL(this.props.hsUrl);
signInToText = _t('Sign in to your Matrix account on %(serverName)s', {
serverName: parsedHsUrl.hostname,
});
} catch (e) {
// ignore
}
} }
let editLink = null; let editLink = null;
@ -338,6 +355,8 @@ PasswordLogin.propTypes = {
onPhoneNumberChanged: PropTypes.func, onPhoneNumberChanged: PropTypes.func,
onPasswordChanged: PropTypes.func, onPasswordChanged: PropTypes.func,
loginIncorrect: PropTypes.bool, loginIncorrect: PropTypes.bool,
hsName: PropTypes.string,
hsUrl: PropTypes.string,
disableSubmit: PropTypes.bool, disableSubmit: PropTypes.bool,
}; };

View file

@ -50,6 +50,10 @@ module.exports = React.createClass({
onRegisterClick: PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise onRegisterClick: PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise
onEditServerDetailsClick: PropTypes.func, onEditServerDetailsClick: PropTypes.func,
flows: PropTypes.arrayOf(PropTypes.object).isRequired, flows: PropTypes.arrayOf(PropTypes.object).isRequired,
// This is optional and only set if we used a server name to determine
// the HS URL via `.well-known` discovery. The server name is used
// instead of the HS URL when talking about "your account".
hsName: PropTypes.string,
hsUrl: PropTypes.string, hsUrl: PropTypes.string,
}, },
@ -295,14 +299,20 @@ module.exports = React.createClass({
}, },
render: function() { render: function() {
let yourMatrixAccountText = _t('Create your account'); let yourMatrixAccountText = _t('Create your Matrix account');
try { if (this.props.hsName) {
const parsedHsUrl = new URL(this.props.hsUrl); yourMatrixAccountText = _t('Create your Matrix account on %(serverName)s', {
yourMatrixAccountText = _t('Create your %(serverName)s account', { serverName: this.props.hsName,
serverName: parsedHsUrl.hostname,
}); });
} catch (e) { } else {
// ignore try {
const parsedHsUrl = new URL(this.props.hsUrl);
yourMatrixAccountText = _t('Create your Matrix account on %(serverName)s', {
serverName: parsedHsUrl.hostname,
});
} catch (e) {
// ignore
}
} }
let editLink = null; let editLink = null;

View file

@ -56,14 +56,14 @@ export const TYPES = {
}, },
}; };
function getDefaultType(defaultHsUrl) { export function getTypeFromHsUrl(hsUrl) {
if (!defaultHsUrl) { if (!hsUrl) {
return null; return null;
} else if (defaultHsUrl === TYPES.FREE.hsUrl) { } else if (hsUrl === TYPES.FREE.hsUrl) {
return FREE; return FREE;
} else if (new URL(defaultHsUrl).hostname.endsWith('.modular.im')) { } else if (new URL(hsUrl).hostname.endsWith('.modular.im')) {
// TODO: Use a Riot config parameter to detect Modular-ness. // This is an unlikely case to reach, as Modular defaults to hiding the
// https://github.com/vector-im/riot-web/issues/8253 // server type selector.
return PREMIUM; return PREMIUM;
} else { } else {
return ADVANCED; return ADVANCED;
@ -72,8 +72,8 @@ function getDefaultType(defaultHsUrl) {
export default class ServerTypeSelector extends React.PureComponent { export default class ServerTypeSelector extends React.PureComponent {
static propTypes = { static propTypes = {
// The default HS URL as another way to set the initially selected type. // The default selected type.
defaultHsUrl: PropTypes.string, selected: PropTypes.string,
// Handler called when the selected type changes. // Handler called when the selected type changes.
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
} }
@ -82,20 +82,12 @@ export default class ServerTypeSelector extends React.PureComponent {
super(props); super(props);
const { const {
defaultHsUrl, selected,
onChange,
} = props; } = props;
const type = getDefaultType(defaultHsUrl);
this.state = { this.state = {
selected: type, selected,
}; };
if (onChange) {
// FIXME: Supply a second 'initial' param here to flag that this is
// initialising the value rather than from user interaction
// (which sometimes we'll want to ignore). Must be a better way
// to do this.
onChange(type, true);
}
} }
updateSelectedType(type) { updateSelectedType(type) {

View file

@ -1251,13 +1251,14 @@
"Username": "Username", "Username": "Username",
"Mobile phone number": "Mobile phone number", "Mobile phone number": "Mobile phone number",
"Not sure of your password? <a>Set a new one</a>": "Not sure of your password? <a>Set a new one</a>", "Not sure of your password? <a>Set a new one</a>": "Not sure of your password? <a>Set a new one</a>",
"Sign in to %(serverName)s": "Sign in to %(serverName)s", "Sign in to your Matrix account": "Sign in to your Matrix account",
"Sign in to your Matrix account on %(serverName)s": "Sign in to your Matrix account on %(serverName)s",
"Change": "Change", "Change": "Change",
"Sign in with": "Sign in with", "Sign in with": "Sign in with",
"Phone": "Phone", "Phone": "Phone",
"If you don't specify an email address, you won't be able to reset your password. Are you sure?": "If you don't specify an email address, you won't be able to reset your password. Are you sure?", "If you don't specify an email address, you won't be able to reset your password. Are you sure?": "If you don't specify an email address, you won't be able to reset your password. Are you sure?",
"Create your account": "Create your account", "Create your Matrix account": "Create your Matrix account",
"Create your %(serverName)s account": "Create your %(serverName)s account", "Create your Matrix account on %(serverName)s": "Create your Matrix account on %(serverName)s",
"Email": "Email", "Email": "Email",
"Email (optional)": "Email (optional)", "Email (optional)": "Email (optional)",
"Phone (optional)": "Phone (optional)", "Phone (optional)": "Phone (optional)",
@ -1407,8 +1408,8 @@
"A new password must be entered.": "A new password must be entered.", "A new password must be entered.": "A new password must be entered.",
"New passwords must match each other.": "New passwords must match each other.", "New passwords must match each other.": "New passwords must match each other.",
"Resetting password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Resetting password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.", "Resetting password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Resetting password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.",
"Your account": "Your account", "Your Matrix account": "Your Matrix account",
"Your account on %(serverName)s": "Your account on %(serverName)s", "Your Matrix account on %(serverName)s": "Your Matrix account on %(serverName)s",
"The homeserver URL %(hsUrl)s doesn't seem to be valid URL. Please enter a valid URL including the protocol prefix.": "The homeserver URL %(hsUrl)s doesn't seem to be valid URL. Please enter a valid URL including the protocol prefix.", "The homeserver URL %(hsUrl)s doesn't seem to be valid URL. Please enter a valid URL including the protocol prefix.": "The homeserver URL %(hsUrl)s doesn't seem to be valid URL. Please enter a valid URL including the protocol prefix.",
"A verification email will be sent to your inbox to confirm setting your new password.": "A verification email will be sent to your inbox to confirm setting your new password.", "A verification email will be sent to your inbox to confirm setting your new password.": "A verification email will be sent to your inbox to confirm setting your new password.",
"Send Reset Email": "Send Reset Email", "Send Reset Email": "Send Reset Email",
@ -1452,6 +1453,7 @@
"A phone number is required to register on this homeserver.": "A phone number is required to register on this homeserver.", "A phone number is required to register on this homeserver.": "A phone number is required to register on this homeserver.",
"You need to enter a username.": "You need to enter a username.", "You need to enter a username.": "You need to enter a username.",
"An unknown error occurred.": "An unknown error occurred.", "An unknown error occurred.": "An unknown error occurred.",
"Create your account": "Create your account",
"Commands": "Commands", "Commands": "Commands",
"Results from DuckDuckGo": "Results from DuckDuckGo", "Results from DuckDuckGo": "Results from DuckDuckGo",
"Emoji": "Emoji", "Emoji": "Emoji",