Files
jitsi-meet/react/features/authentication/components/LoginDialog.native.js

271 lines
8.4 KiB
JavaScript
Raw Normal View History

2017-09-18 02:09:43 -05:00
import PropTypes from 'prop-types';
2017-09-08 15:36:42 +02:00
import React, { Component } from 'react';
2017-09-18 02:09:43 -05:00
import { Text, TextInput, View } from 'react-native';
2017-09-08 15:36:42 +02:00
import { connect as reduxConnect } from 'react-redux';
2017-09-18 02:09:43 -05:00
import { connect, toJid } from '../../base/connection';
import { Dialog } from '../../base/dialog';
2017-09-08 15:36:42 +02:00
import { translate } from '../../base/i18n';
import { JitsiConnectionErrors } from '../../base/lib-jitsi-meet';
2017-09-18 02:09:43 -05:00
import { authenticateAndUpgradeRole, cancelLogin } from '../actions';
2017-09-08 15:36:42 +02:00
import styles from './styles';
/**
* Dialog asks user for username and password.
*
* First authentication configuration that it will deal with is the main XMPP
* domain (config.hosts.domain) with password authentication. A LoginDialog
* will be opened after 'CONNECTION_FAILED' action with
* 'JitsiConnectionErrors.PASSWORD_REQUIRED' error. After username and password
* are entered a new 'connect' action from 'features/base/connection' will be
* triggered which will result in new XMPP connection. The conference will start
* if the credentials are correct.
*
* The second setup is the main XMPP domain with password plus guest domain with
* anonymous access configured under 'config.hosts.anonymousdomain'. In such
* case user connects from the anonymous domain, but if the room does not exist
* yet, Jicofo will not allow to start new conference. This will trigger
* 'CONFERENCE_FAILED' action with JitsiConferenceErrors.AUTHENTICATION_REQUIRED
* error and 'authRequired' value of 'features/base/conference' will hold
2017-09-18 02:09:43 -05:00
* the {@link JitsiConference} instance. If user decides to authenticate, a
* new/separate XMPP connection is established and authentication is performed.
* In case it succeeds, Jicofo will assign new session ID which then can be used
* from the anonymous domain connection to create and join the room. This part
* is done by {@link JitsiConference#authenticateAndUpgradeRole} in
* lib-jitsi-meet.
2017-09-08 15:36:42 +02:00
*
2017-09-18 02:09:43 -05:00
* See {@link https://github.com/jitsi/jicofo#secure-domain} for a description
* of the configuration parameters.
2017-09-08 15:36:42 +02:00
*/
class LoginDialog extends Component {
/**
* LoginDialog component's property types.
*
* @static
*/
static propTypes = {
/**
* {@link JitsiConference} that needs authentication - will hold a valid
* value in XMPP login + guest access mode.
*/
2017-09-18 02:09:43 -05:00
_conference: PropTypes.object,
2017-09-08 15:36:42 +02:00
/**
*
*/
2017-09-18 02:09:43 -05:00
_configHosts: PropTypes.object,
2017-09-08 15:36:42 +02:00
/**
* Indicates if the dialog should display "connecting" status message.
*/
2017-09-18 02:09:43 -05:00
_connecting: PropTypes.bool,
2017-09-08 15:36:42 +02:00
/**
2017-09-18 02:09:43 -05:00
* The error which occurred during login/authentication.
2017-09-08 15:36:42 +02:00
*/
2017-09-18 02:09:43 -05:00
_error: PropTypes.string,
2017-09-08 15:36:42 +02:00
/**
2017-09-18 02:09:43 -05:00
* Any extra details about the error provided by lib-jitsi-meet.
2017-09-08 15:36:42 +02:00
*/
2017-09-18 02:09:43 -05:00
_errorDetails: PropTypes.string,
2017-09-08 15:36:42 +02:00
/**
2017-09-18 02:09:43 -05:00
* Redux store dispatch method.
2017-09-08 15:36:42 +02:00
*/
2017-09-18 02:09:43 -05:00
dispatch: PropTypes.func,
2017-09-08 15:36:42 +02:00
/**
* Invoked to obtain translated strings.
*/
2017-09-18 02:09:43 -05:00
t: PropTypes.func
2017-09-08 15:36:42 +02:00
};
/**
* Initializes a new LoginDialog instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props) {
super(props);
this.state = {
username: '',
password: ''
};
2017-09-18 02:09:43 -05:00
// Bind event handlers so they are only bound once per instance.
this._onCancel = this._onCancel.bind(this);
this._onLogin = this._onLogin.bind(this);
this._onPasswordChange = this._onPasswordChange.bind(this);
this._onUsernameChange = this._onUsernameChange.bind(this);
2017-09-08 15:36:42 +02:00
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const {
2017-09-18 02:09:43 -05:00
_connecting: connecting,
_error: error,
_errorDetails: errorDetails,
2017-09-08 15:36:42 +02:00
t
} = this.props;
let messageKey = '';
2017-09-18 02:09:43 -05:00
const messageOptions = {};
2017-09-08 15:36:42 +02:00
if (error === JitsiConnectionErrors.PASSWORD_REQUIRED) {
messageKey = 'dialog.incorrectPassword';
} else if (error) {
messageKey = 'dialog.connectErrorWithMsg';
messageOptions.msg = `${error} ${errorDetails}`;
}
return (
2017-09-18 02:09:43 -05:00
<Dialog
okDisabled = { connecting }
onCancel = { this._onCancel }
onSubmit = { this._onLogin }
titleKey = 'dialog.passwordRequired'>
<View style = { styles.loginDialog }>
2017-09-08 15:36:42 +02:00
<TextInput
onChangeText = { this._onUsernameChange }
placeholder = { 'user@domain.com' }
2017-09-18 02:09:43 -05:00
style = { styles.loginDialogTextInput }
2017-09-08 15:36:42 +02:00
value = { this.state.username } />
<TextInput
onChangeText = { this._onPasswordChange }
placeholder = { t('dialog.userPassword') }
secureTextEntry = { true }
2017-09-18 02:09:43 -05:00
style = { styles.loginDialogTextInput }
2017-09-08 15:36:42 +02:00
value = { this.state.password } />
2017-09-18 02:09:43 -05:00
<Text style = { styles.loginDialogText }>
{
error
? t(messageKey, messageOptions)
: connecting
? t('connection.CONNECTING')
: ''
}
2017-09-08 15:36:42 +02:00
</Text>
</View>
2017-09-18 02:09:43 -05:00
</Dialog>
2017-09-08 15:36:42 +02:00
);
}
/**
* Called when user edits the username.
*
* @param {string} text - A new username value entered by user.
* @returns {void}
* @private
*/
_onUsernameChange(text) {
this.setState({
username: text
});
}
/**
* Called when user edits the password.
*
* @param {string} text - A new password value entered by user.
* @returns {void}
* @private
*/
_onPasswordChange(text) {
this.setState({
password: text
});
}
/**
* Notifies this LoginDialog that it has been dismissed by cancel.
*
* @private
* @returns {void}
*/
_onCancel() {
this.props.dispatch(cancelLogin());
}
/**
* Notifies this LoginDialog that the login button (OK) has been pressed by
* the user.
*
* @private
* @returns {void}
*/
_onLogin() {
2017-09-18 02:09:43 -05:00
const { _conference: conference } = this.props;
2017-09-08 15:36:42 +02:00
const { username, password } = this.state;
2017-09-18 02:09:43 -05:00
const jid = toJid(username, this.props._configHosts);
2017-09-08 15:36:42 +02:00
// If there's a conference it means that the connection has succeeded,
// but authentication is required in order to join the room.
if (conference) {
this.props.dispatch(
authenticateAndUpgradeRole(jid, password, conference));
} else {
this.props.dispatch(connect(jid, password));
}
}
}
/**
* Maps (parts of) the Redux state to the associated props for the
* {@code LoginDialog} component.
*
* @param {Object} state - The Redux state.
* @private
* @returns {{
2017-09-18 02:09:43 -05:00
* _conference: JitsiConference,
* _configHosts: Object,
* _connecting: boolean,
* _error: string,
* _errorDetails: string
2017-09-08 15:36:42 +02:00
* }}
*/
function _mapStateToProps(state) {
2017-09-18 02:09:43 -05:00
const {
upgradeRoleError,
upgradeRoleInProgress
} = state['features/authentication'];
const { authRequired } = state['features/base/conference'];
2017-09-08 15:36:42 +02:00
const { hosts: configHosts } = state['features/base/config'];
const {
connecting,
error: connectionError,
errorMessage: connectionErrorMessage
} = state['features/base/connection'];
2017-09-18 02:09:43 -05:00
let error;
let errorDetails;
if (connectionError) {
error = connectionError;
errorDetails = connectionErrorMessage;
} else if (upgradeRoleError) {
error
= upgradeRoleError.connectionError
|| upgradeRoleError.authenticationError;
errorDetails = upgradeRoleError.message;
}
2017-09-08 15:36:42 +02:00
return {
2017-09-18 02:09:43 -05:00
_conference: authRequired,
_configHosts: configHosts,
_connecting: Boolean(connecting) || Boolean(upgradeRoleInProgress),
_error: error,
_errorDetails: errorDetails
2017-09-08 15:36:42 +02:00
};
}
export default translate(reduxConnect(_mapStateToProps)(LoginDialog));