2016-08-02 13:04:20 +00:00
|
|
|
/*
|
|
|
|
Copyright 2015, 2016 OpenMarket Ltd
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2016-08-10 10:33:58 +00:00
|
|
|
import q from 'q';
|
|
|
|
|
2016-08-02 13:04:20 +00:00
|
|
|
import MatrixClientPeg from './MatrixClientPeg';
|
|
|
|
import Notifier from './Notifier'
|
|
|
|
import UserActivity from './UserActivity';
|
|
|
|
import Presence from './Presence';
|
|
|
|
import dis from './dispatcher';
|
|
|
|
|
2016-08-10 10:33:58 +00:00
|
|
|
/**
|
|
|
|
* Called at startup, to attempt to build a logged-in Matrix session. It tries
|
|
|
|
* a number of things:
|
|
|
|
*
|
|
|
|
* 0. if it looks like we are in the middle of a registration process, it does
|
|
|
|
* nothing.
|
|
|
|
*
|
|
|
|
* 1. if we have a guest access token in the query params, it uses that.
|
|
|
|
*
|
|
|
|
* 2. if an access token is stored in local storage (from a previous session),
|
|
|
|
* it uses that.
|
|
|
|
*
|
|
|
|
* 3. it attempts to auto-register as a guest user.
|
|
|
|
*
|
|
|
|
* If any of steps 1-3 are successful, it will call {setLoggedIn}, which in
|
|
|
|
* turn will raise on_logged_in and will_start_client events.
|
|
|
|
*
|
|
|
|
* It returns a promise which resolves when the above process completes.
|
|
|
|
*
|
|
|
|
* @param {object} opts.queryParams: string->string map of the query-parameters
|
|
|
|
* extracted from the #-fragment of the starting URI.
|
|
|
|
*
|
|
|
|
* @param {boolean} opts.enableGuest: set to true to enable guest access tokens
|
|
|
|
* and auto-guest registrations.
|
|
|
|
*
|
|
|
|
* @params {string} opts.hsUrl: homeserver URL. Only used if enableGuest is
|
|
|
|
* true; defines the HS to register against.
|
|
|
|
*
|
|
|
|
* @params {string} opts.isUrl: homeserver URL. Only used if enableGuest is
|
|
|
|
* true; defines the IS to use.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
export function loadSession(opts) {
|
|
|
|
const queryParams = opts.queryParams || {};
|
|
|
|
let enableGuest = opts.enableGuest || false;
|
|
|
|
const hsUrl = opts.hsUrl;
|
|
|
|
const isUrl = opts.isUrl;
|
|
|
|
|
|
|
|
if (queryParams.client_secret && queryParams.sid) {
|
|
|
|
// this happens during email validation: the email contains a link to the
|
|
|
|
// IS, which in turn redirects back to vector. We let MatrixChat create a
|
|
|
|
// Registration component which completes the next stage of registration.
|
|
|
|
console.log("Not registering as guest: registration already in progress.");
|
|
|
|
return q();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hsUrl) {
|
|
|
|
console.warn("Cannot enable guest access: can't determine HS URL to use");
|
|
|
|
enableGuest = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (enableGuest &&
|
|
|
|
queryParams.guest_user_id &&
|
|
|
|
queryParams.guest_access_token
|
|
|
|
) {
|
|
|
|
console.log("Using guest access credentials");
|
|
|
|
setLoggedIn({
|
|
|
|
userId: queryParams.guest_user_id,
|
|
|
|
accessToken: queryParams.guest_access_token,
|
|
|
|
homeserverUrl: hsUrl,
|
|
|
|
identityServerUrl: isUrl,
|
|
|
|
guest: true,
|
|
|
|
});
|
|
|
|
return q();
|
|
|
|
}
|
|
|
|
|
2016-08-10 09:33:27 +00:00
|
|
|
if (_restoreFromLocalStorage()) {
|
2016-08-10 10:33:58 +00:00
|
|
|
return q();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (enableGuest) {
|
|
|
|
return _registerAsGuest(hsUrl, isUrl);
|
|
|
|
}
|
|
|
|
|
|
|
|
// fall back to login screen
|
|
|
|
return q();
|
|
|
|
}
|
|
|
|
|
|
|
|
function _registerAsGuest(hsUrl, isUrl) {
|
|
|
|
console.log("Doing guest login on %s", hsUrl);
|
|
|
|
|
|
|
|
MatrixClientPeg.replaceUsingUrls(hsUrl, isUrl);
|
|
|
|
return MatrixClientPeg.get().registerGuest().then((creds) => {
|
|
|
|
console.log("Registered as guest: %s", creds.user_id);
|
|
|
|
setLoggedIn({
|
|
|
|
userId: creds.user_id,
|
|
|
|
accessToken: creds.access_token,
|
|
|
|
homeserverUrl: hsUrl,
|
|
|
|
identityServerUrl: isUrl,
|
|
|
|
guest: true,
|
|
|
|
});
|
|
|
|
}, (err) => {
|
|
|
|
console.error("Failed to register as guest: " + err + " " + err.data);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-08-10 09:33:27 +00:00
|
|
|
// returns true if a session is found in localstorage
|
|
|
|
function _restoreFromLocalStorage() {
|
|
|
|
if (!localStorage) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const hs_url = localStorage.getItem("mx_hs_url");
|
|
|
|
const is_url = localStorage.getItem("mx_is_url") || 'https://matrix.org';
|
|
|
|
const access_token = localStorage.getItem("mx_access_token");
|
|
|
|
const user_id = localStorage.getItem("mx_user_id");
|
|
|
|
|
|
|
|
let is_guest;
|
|
|
|
if (localStorage.getItem("mx_is_guest") !== null) {
|
|
|
|
is_guest = localStorage.getItem("mx_is_guest") === "true";
|
|
|
|
} else {
|
|
|
|
// legacy key name
|
|
|
|
is_guest = localStorage.getItem("matrix-is-guest") === "true";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (access_token && user_id && hs_url) {
|
|
|
|
console.log("Restoring session for %s", user_id);
|
|
|
|
setLoggedIn({
|
|
|
|
userId: user_id,
|
|
|
|
accessToken: access_token,
|
|
|
|
homeserverUrl: hs_url,
|
|
|
|
identityServerUrl: is_url,
|
|
|
|
guest: is_guest,
|
|
|
|
});
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
console.log("No previous session found.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2016-08-10 10:33:58 +00:00
|
|
|
|
2016-08-02 17:52:56 +00:00
|
|
|
/**
|
|
|
|
* Transitions to a logged-in state using the given credentials
|
2016-08-03 15:31:42 +00:00
|
|
|
* @param {MatrixClientCreds} credentials The credentials to use
|
2016-08-02 17:52:56 +00:00
|
|
|
*/
|
2016-08-10 10:33:58 +00:00
|
|
|
export function setLoggedIn(credentials) {
|
2016-08-02 13:04:20 +00:00
|
|
|
credentials.guest = Boolean(credentials.guest);
|
2016-08-10 10:33:58 +00:00
|
|
|
console.log("setLoggedIn => %s (guest=%s) hs=%s",
|
2016-08-09 23:03:29 +00:00
|
|
|
credentials.userId, credentials.guest,
|
|
|
|
credentials.homeserverUrl);
|
2016-08-03 09:46:42 +00:00
|
|
|
MatrixClientPeg.replaceUsingCreds(credentials);
|
2016-08-02 13:04:20 +00:00
|
|
|
|
|
|
|
dis.dispatch({action: 'on_logged_in'});
|
|
|
|
|
2016-08-02 17:52:56 +00:00
|
|
|
startMatrixClient();
|
2016-08-02 13:04:20 +00:00
|
|
|
}
|
|
|
|
|
2016-08-02 17:55:13 +00:00
|
|
|
/**
|
|
|
|
* Logs the current session out and transitions to the logged-out state
|
|
|
|
*/
|
2016-08-10 10:33:58 +00:00
|
|
|
export function logout() {
|
2016-08-02 13:04:20 +00:00
|
|
|
if (MatrixClientPeg.get().isGuest()) {
|
|
|
|
// logout doesn't work for guest sessions
|
|
|
|
// Also we sometimes want to re-log in a guest session
|
|
|
|
// if we abort the login
|
2016-08-03 10:47:29 +00:00
|
|
|
onLoggedOut();
|
2016-08-02 13:04:20 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-08-03 10:47:29 +00:00
|
|
|
return MatrixClientPeg.get().logout().then(onLoggedOut,
|
2016-08-03 09:01:23 +00:00
|
|
|
(err) => {
|
|
|
|
// Just throwing an error here is going to be very unhelpful
|
|
|
|
// if you're trying to log out because your server's down and
|
|
|
|
// you want to log into a different server, so just forget the
|
|
|
|
// access token. It's annoying that this will leave the access
|
|
|
|
// token still valid, but we should fix this by having access
|
|
|
|
// tokens expire (and if you really think you've been compromised,
|
|
|
|
// change your password).
|
|
|
|
console.log("Failed to call logout API: token will not be invalidated");
|
2016-08-03 10:47:29 +00:00
|
|
|
onLoggedOut();
|
2016-08-03 09:01:23 +00:00
|
|
|
}
|
2016-08-02 13:04:20 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-08-02 17:56:12 +00:00
|
|
|
/**
|
|
|
|
* Starts the matrix client and all other react-sdk services that
|
|
|
|
* listen for events while a session is logged in.
|
|
|
|
*/
|
2016-08-10 10:33:58 +00:00
|
|
|
export function startMatrixClient() {
|
2016-08-02 13:04:20 +00:00
|
|
|
// dispatch this before starting the matrix client: it's used
|
|
|
|
// to add listeners for the 'sync' event so otherwise we'd have
|
|
|
|
// a race condition (and we need to dispatch synchronously for this
|
|
|
|
// to work).
|
|
|
|
dis.dispatch({action: 'will_start_client'}, true);
|
|
|
|
|
|
|
|
Notifier.start();
|
|
|
|
UserActivity.start();
|
|
|
|
Presence.start();
|
2016-08-02 17:58:18 +00:00
|
|
|
|
2016-08-03 15:39:47 +00:00
|
|
|
MatrixClientPeg.start();
|
2016-08-02 13:04:20 +00:00
|
|
|
}
|
|
|
|
|
2016-08-04 09:49:34 +00:00
|
|
|
/*
|
|
|
|
* Stops a running client and all related services, used after
|
|
|
|
* a session has been logged out / ended.
|
|
|
|
*/
|
2016-08-10 10:33:58 +00:00
|
|
|
export function onLoggedOut() {
|
2016-08-02 13:04:20 +00:00
|
|
|
if (window.localStorage) {
|
|
|
|
const hsUrl = window.localStorage.getItem("mx_hs_url");
|
|
|
|
const isUrl = window.localStorage.getItem("mx_is_url");
|
|
|
|
window.localStorage.clear();
|
|
|
|
// preserve our HS & IS URLs for convenience
|
|
|
|
// N.B. we cache them in hsUrl/isUrl and can't really inline them
|
|
|
|
// as getCurrentHsUrl() may call through to localStorage.
|
|
|
|
if (hsUrl) window.localStorage.setItem("mx_hs_url", hsUrl);
|
|
|
|
if (isUrl) window.localStorage.setItem("mx_is_url", isUrl);
|
|
|
|
}
|
|
|
|
_stopMatrixClient();
|
|
|
|
|
|
|
|
dis.dispatch({action: 'on_logged_out'});
|
|
|
|
}
|
|
|
|
|
2016-08-04 09:49:34 +00:00
|
|
|
/**
|
|
|
|
* Stop all the background processes related to the current client
|
|
|
|
*/
|
2016-08-02 13:04:20 +00:00
|
|
|
function _stopMatrixClient() {
|
|
|
|
Notifier.stop();
|
|
|
|
UserActivity.stop();
|
|
|
|
Presence.stop();
|
|
|
|
MatrixClientPeg.get().stopClient();
|
|
|
|
MatrixClientPeg.get().removeAllListeners();
|
|
|
|
MatrixClientPeg.unset();
|
|
|
|
}
|