| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 | /* global APP, config, JitsiMeetJS, Promise */
import { openConnection } from '../../../connection';
import { setJWT } from '../../../react/features/jwt';
import UIUtil from '../util/UIUtil';
import LoginDialog from './LoginDialog';
const ConnectionErrors = JitsiMeetJS.errors.connection;
const logger = require("jitsi-meet-logger").getLogger(__filename);
let externalAuthWindow;
let authRequiredDialog;
let isTokenAuthEnabled
    = typeof config.tokenAuthUrl === "string" && config.tokenAuthUrl.length;
let getTokenAuthUrl
    = JitsiMeetJS.util.AuthUtil.getTokenAuthUrl.bind(null, config.tokenAuthUrl);
/**
 * Authenticate using external service or just focus
 * external auth window if there is one already.
 *
 * @param {JitsiConference} room
 * @param {string} [lockPassword] password to use if the conference is locked
 */
function doExternalAuth (room, lockPassword) {
    if (externalAuthWindow) {
        externalAuthWindow.focus();
        return;
    }
    if (room.isJoined()) {
        let getUrl;
        if (isTokenAuthEnabled) {
            getUrl = Promise.resolve(getTokenAuthUrl(room.getName(), true));
            initJWTTokenListener(room);
        } else {
            getUrl = room.getExternalAuthUrl(true);
        }
        getUrl.then(function (url) {
            externalAuthWindow = LoginDialog.showExternalAuthDialog(
                url,
                function () {
                    externalAuthWindow = null;
                    if (!isTokenAuthEnabled) {
                        room.join(lockPassword);
                    }
                }
            );
        });
    } else {
        // If conference has not been started yet
        // then  redirect to login page
        if (isTokenAuthEnabled) {
            redirectToTokenAuthService(room.getName());
        } else {
            room.getExternalAuthUrl().then(UIUtil.redirect);
        }
    }
}
/**
 * Redirect the user to the token authentication service for the login to be
 * performed. Once complete it is expected that the service wil bring the user
 * back with "?jwt={the JWT token}" query parameter added.
 * @param {string} [roomName] the name of the conference room.
 */
function redirectToTokenAuthService(roomName) {
    UIUtil.redirect(getTokenAuthUrl(roomName, false));
}
/**
 * Initializes 'message' listener that will wait for a JWT token to be received
 * from the token authentication service opened in a popup window.
 * @param room the name fo the conference room.
 */
function initJWTTokenListener(room) {
    var listener = function ({ data, source }) {
        if (externalAuthWindow !== source) {
            logger.warn("Ignored message not coming " +
                "from external authnetication window");
            return;
        }
        let jwt;
        if (data && (jwt = data.jwtToken)) {
            logger.info("Received JSON Web Token (JWT):", jwt);
            APP.store.dispatch(setJWT(jwt));
            var roomName = room.getName();
            openConnection({retry: false, roomName: roomName })
                .then(function (connection) {
                    // Start new connection
                    let newRoom = connection.initJitsiConference(
                        roomName, APP.conference._getConferenceOptions());
                    // Authenticate from the new connection to get
                    // the session-ID from the focus, which wil then be used
                    // to upgrade current connection's user role
                    newRoom.room.moderator.authenticate().then(function () {
                        connection.disconnect();
                        // At this point we'll have session-ID stored in
                        // the settings. It wil be used in the call below
                        // to upgrade user's role
                        room.room.moderator.authenticate()
                            .then(function () {
                                logger.info("User role upgrade done !");
                                unregister();
                            }).catch(function (err, errCode) {
                                logger.error(
                                    "Authentication failed: ", err, errCode);
                                unregister();
                            }
                        );
                    }).catch(function (error, code) {
                        unregister();
                        connection.disconnect();
                        logger.error(
                            'Authentication failed on the new connection',
                            error, code);
                    });
                }, function (err) {
                    unregister();
                    logger.error("Failed to open new connection", err);
                });
        }
    };
    var unregister = function () {
        window.removeEventListener("message", listener);
    };
    if (window.addEventListener) {
        window.addEventListener("message", listener, false);
    }
}
/**
 * Authenticate on the server.
 * @param {JitsiConference} room
 * @param {string} [lockPassword] password to use if the conference is locked
 */
function doXmppAuth (room, lockPassword) {
    let loginDialog = LoginDialog.showAuthDialog(function (id, password) {
        // auth "on the fly":
        // 1. open new connection with proper id and password
        // 2. connect to the room
        // (this will store sessionId in the localStorage)
        // 3. close new connection
        // 4. reallocate focus in current room
        openConnection({id, password, roomName: room.getName()}).then(
        function (connection) {
            // open room
            let newRoom = connection.initJitsiConference(
                room.getName(), APP.conference._getConferenceOptions()
            );
            loginDialog.displayConnectionStatus('connection.FETCH_SESSION_ID');
            newRoom.room.moderator.authenticate().then(function () {
                connection.disconnect();
                loginDialog.displayConnectionStatus(
                    'connection.GOT_SESSION_ID');
                // authenticate conference on the fly
                room.join(lockPassword);
                loginDialog.close();
            }).catch(function (error, code) {
                connection.disconnect();
                logger.error('Auth on the fly failed', error);
                loginDialog.displayError(
                    'connection.GET_SESSION_ID_ERROR', {code: code});
            });
        }, function (err) {
            loginDialog.displayError(err);
        });
    }, function () { // user canceled
        loginDialog.close();
    });
}
/**
 * Authenticate for the conference.
 * Uses external service for auth if conference supports that.
 * @param {JitsiConference} room
 * @param {string} [lockPassword] password to use if the conference is locked
 */
function authenticate (room, lockPassword) {
    if (isTokenAuthEnabled || room.isExternalAuthEnabled()) {
        doExternalAuth(room, lockPassword);
    } else {
        doXmppAuth(room, lockPassword);
    }
}
/**
 * De-authenticate local user.
 *
 * @param {JitsiConference} room
 * @param {string} [lockPassword] password to use if the conference is locked
 * @returns {Promise}
 */
function logout (room) {
    return new Promise(function (resolve) {
        room.room.moderator.logout(resolve);
    }).then(function (url) {
        // de-authenticate conference on the fly
        if (room.isJoined()) {
            room.join();
        }
        return url;
    });
}
/**
 * Notify user that authentication is required to create the conference.
 * @param {JitsiConference} room
 * @param {string} [lockPassword] password to use if the conference is locked
 */
function requireAuth(room, lockPassword) {
    if (authRequiredDialog) {
        return;
    }
    authRequiredDialog = LoginDialog.showAuthRequiredDialog(
        room.getName(), authenticate.bind(null, room, lockPassword)
    );
}
/**
 * Close auth-related dialogs if there are any.
 */
function closeAuth() {
    if (externalAuthWindow) {
        externalAuthWindow.close();
        externalAuthWindow = null;
    }
    if (authRequiredDialog) {
        authRequiredDialog.close();
        authRequiredDialog = null;
    }
}
function showXmppPasswordPrompt(roomName, connect) {
    return new Promise(function (resolve, reject) {
        let authDialog = LoginDialog.showAuthDialog(
            function (id, password) {
                connect(id, password, roomName).then(function (connection) {
                    authDialog.close();
                    resolve(connection);
                }, function (err) {
                    if (err === ConnectionErrors.PASSWORD_REQUIRED) {
                        authDialog.displayError(err);
                    } else {
                        authDialog.close();
                        reject(err);
                    }
                });
            }
        );
    });
}
/**
 * Show Authentication Dialog and try to connect with new credentials.
 * If failed to connect because of PASSWORD_REQUIRED error
 * then ask for password again.
 * @param {string} [roomName] name of the conference room
 * @param {function(id, password, roomName)} [connect] function that returns
 * a Promise which resolves with JitsiConnection or fails with one of
 * ConnectionErrors.
 * @returns {Promise<JitsiConnection>}
 */
function requestAuth(roomName, connect) {
    if (isTokenAuthEnabled) {
        // This Promise never resolves as user gets redirected to another URL
        return new Promise(() => redirectToTokenAuthService(roomName));
    } else {
        return showXmppPasswordPrompt(roomName, connect);
    }
}
export default {
    authenticate,
    requireAuth,
    requestAuth,
    closeAuth,
    logout
};
 |