Adds auto-sign in feature and login/logout toolbar menu.

This commit is contained in:
paweldomas 2015-02-18 16:50:47 +01:00
parent b87cd9f842
commit a904e35c67
12 changed files with 17349 additions and 16807 deletions

61
css/login_menu.css Normal file
View File

@ -0,0 +1,61 @@
/*Initialize*/
ul.loginmenu {
display:none;
position: absolute;
margin: 0;
padding: 5px;
padding-bottom: 7px;
top: 45px;
left: -5px;
background-color: rgba(0,0,0,0.9);
border: 1px solid rgba(256, 256, 256, 0.2);
border-radius:8px;
}
ul.loginmenu li {
list-style-type: none;
padding: 7px;
}
ul.loginmenu li.identity {
color: #fff;
font-size: 11pt;
cursor: default;
}
ul.loginmenu:after {
content: url('../images/dropdownPointer.png');
display: block;
position: absolute;
top: -7px;
left: 18px;
}
li a.authButton{
background-color: #06a5df;
padding-top: 3px;
padding-bottom: 3px;
padding-left: 29px;
padding-right: 29px;
border-radius: 4px;
color: #fff;
font-size: 11pt;
cursor: pointer;
}
span.authentication:hover ul.loginmenu, ul.loginmenu:hover {
display:block !important;
}
a.disabled {
color: gray !important;
pointer-events: none;
}
.loginmenuPadding {
width: 50px;
height: 30px;
position: absolute;
top: -30px;
left: 0px;
}

BIN
images/dropdownPointer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

View File

@ -30,6 +30,7 @@
<link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
<link rel="stylesheet" href="css/modaldialog.css?v=3">
<link rel="stylesheet" href="css/popup_menu.css?v=4">
<link rel="stylesheet" href="css/login_menu.css?v=1">
<link rel="stylesheet" href="css/popover.css?v=2">
<link rel="stylesheet" href="css/jitsi_popover.css?v=2">
<link rel="stylesheet" href="css/contact_list.css?v=4">
@ -121,6 +122,22 @@
<div style="position: relative;" id="header_container">
<div id="header">
<span id="toolbar">
<span id="authentication" class="authentication" style="display: none">
<a class="button" id="toolbar_button_authentication" >
<i id="authButton" class="icon-avatar"></i>
</a>
<ul class="loginmenu">
<span class="loginmenuPadding"></span>
<li id="toolbar_auth_identity" class="identity"></li>
<li id="toolbar_button_login">
<a class="authButton" data-i18n="toolbar.login"></a>
</li>
<li id="toolbar_button_logout">
<a class="authButton" data-i18n="toolbar.logout"></a>
</li>
</ul>
<div class="header_button_separator"></div>
</span>
<a class="button" id="toolbar_button_mute" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="mutePopover" data-i18n="[content]toolbar.mute" content="Mute / Unmute">
<i id="mute" class="icon-microphone"></i>
</a>
@ -128,12 +145,6 @@
<a class="button" id="toolbar_button_camera" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="toggleVideoPopover" data-i18n="[content]toolbar.videomute" content="Start / stop camera">
<i id="video" class="icon-camera"></i>
</a>
<span id="authentication" style="display: none">
<div class="header_button_separator"></div>
<a class="button" id="toolbar_button_authentication" data-container="body" data-toggle="popover" data-placement="bottom" data-i18n="[content]toolbar.authenticate" content="Authenticate">
<i id="authButton" class="icon-avatar"></i>
</a>
</span>
<span id="recording" style="display: none">
<div class="header_button_separator"></div>
<a class="button" id="toolbar_button_record" data-container="body" data-toggle="popover" data-placement="bottom" data-i18n="[content]toolbar.record" content="Record">

View File

@ -54,7 +54,9 @@
"fullscreen": "Enter / Exit Full Screen",
"sip": "Call SIP number",
"Settings": "Settings",
"hangup": "Hang Up"
"hangup": "Hang Up",
"login": "Login",
"logout": "Logout"
},
"bottomtoolbar": {
"chat": "Open / close chat",

File diff suppressed because it is too large Load Diff

View File

@ -371,10 +371,6 @@ function onMucJoined(jid, info) {
// Once we've joined the muc show the toolbar
ToolbarToggler.showToolbar();
// Show authenticate button if needed
Toolbar.showAuthenticateButton(
APP.xmpp.isExternalAuthEnabled() && !APP.xmpp.isModerator());
var displayName = !config.displayJids
? info.displayName : Strophe.getResourceFromJid(jid);
@ -413,14 +409,12 @@ function onMucLeft(jid) {
};
function onLocalRoleChange(jid, info, pres, isModerator, isExternalAuthEnabled)
function onLocalRoleChange(jid, info, pres, isModerator)
{
console.info("My role changed, new role: " + info.role);
onModeratorStatusChanged(isModerator);
VideoLayout.showModeratorIndicator();
Toolbar.showAuthenticateButton(
isExternalAuthEnabled && !isModerator);
if (isModerator) {
Authentication.closeAuthenticationWindow();

View File

@ -16,7 +16,7 @@ var Authentication = {
// extract room name from 'room@muc.server.net'
var room = roomName.substr(0, roomName.indexOf('@'));
authDialog = messageHandler.openDialog(
authDialog = APP.UI.messageHandler.openDialog(
'Stop',
'Authentication is required to create room:<br/><b>' + room +
'</b></br> You can either authenticate to create the room or ' +
@ -58,7 +58,7 @@ var Authentication = {
}
},
createAuthenticationWindow: function (callback, url) {
authenticationWindow = messageHandler.openCenteredPopup(
authenticationWindow = APP.UI.messageHandler.openCenteredPopup(
url, 910, 660,
// On closed
function () {

View File

@ -1,4 +1,4 @@
/* global $, buttonClick, config, lockRoom,
/* global APP,$, buttonClick, config, lockRoom,
setSharedKey, Util */
var messageHandler = require("../util/MessageHandler");
var BottomToolbar = require("./BottomToolbar");
@ -7,6 +7,8 @@ var Etherpad = require("../etherpad/Etherpad");
var PanelToggler = require("../side_pannels/SidePanelToggler");
var Authentication = require("../authentication/Authentication");
var UIUtil = require("../util/UIUtil");
var AuthenticationEvents
= require("../../../service/authentication/AuthenticationEvents");
var roomUrl = null;
var sharedKey = '';
@ -20,9 +22,9 @@ var buttonHandlers =
"toolbar_button_camera": function () {
return APP.UI.toggleVideo();
},
"toolbar_button_authentication": function () {
/*"toolbar_button_authentication": function () {
return Toolbar.authenticateClicked();
},
},*/
"toolbar_button_record": function () {
return toggleRecording();
},
@ -57,6 +59,27 @@ var buttonHandlers =
},
"toolbar_button_hangup": function () {
return hangup();
},
"toolbar_button_login": function () {
Toolbar.authenticateClicked();
},
"toolbar_button_logout": function () {
// Ask for confirmation
messageHandler.openTwoButtonDialog(
"Logout",
"Are you sure you want to logout and stop the conference ?",
false, "Yes",
function (evt, yes) {
if (yes) {
APP.xmpp.logout(function (url) {
if (url) {
window.location.href = url;
} else {
hangup();
}
});
}
});
}
};
@ -222,7 +245,33 @@ var Toolbar = (function (my) {
for(var k in buttonHandlers)
$("#" + k).click(buttonHandlers[k]);
UI = ui;
}
// Update login info
APP.xmpp.addListener(
AuthenticationEvents.IDENTITY_UPDATED,
function (authenticationEnabled, userIdentity) {
var loggedIn = false;
if (userIdentity) {
loggedIn = true;
}
//FIXME: XMPP authentication need improvements for "live" login
if (!APP.xmpp.isExternalAuthEnabled() && !loggedIn)
{
authenticationEnabled = false;
}
Toolbar.showAuthenticateButton(authenticationEnabled);
if (authenticationEnabled) {
Toolbar.setAuthenticatedIdentity(userIdentity);
Toolbar.showLoginButton(!loggedIn);
Toolbar.showLogoutButton(loggedIn);
}
}
);
},
/**
* Sets shared key
@ -235,20 +284,30 @@ var Toolbar = (function (my) {
my.authenticateClicked = function () {
Authentication.focusAuthenticationWindow();
// Get authentication URL
APP.xmpp.getAuthUrl(APP.UI.getRoomName(), function (url) {
// Open popup with authentication URL
var authenticationWindow = Authentication.createAuthenticationWindow(function () {
// On popup closed - retry room allocation
APP.xmpp.allocateConferenceFocus(APP.UI.getRoomName(), APP.UI.checkForNicknameAndJoin);
}, url);
if (!authenticationWindow) {
Toolbar.showAuthenticateButton(true);
messageHandler.openMessageDialog(
null, "Your browser is blocking popup windows from this site." +
if (!APP.xmpp.getMUCJoined()) {
APP.xmpp.getLoginUrl(UI.getRoomName(), function (url) {
// If conference has not been started yet - redirect to login page
window.location.href = url;
});
} else {
APP.xmpp.getPopupLoginUrl(UI.getRoomName(), function (url) {
// Otherwise - open popup with authentication URL
var authenticationWindow = Authentication.createAuthenticationWindow(
function () {
// On popup closed - retry room allocation
APP.xmpp.allocateConferenceFocus(
APP.UI.getRoomName(),
function () { console.info("AUTH DONE"); }
);
}, url);
if (!authenticationWindow) {
messageHandler.openMessageDialog(
null, "Your browser is blocking popup windows from this site." +
" Please enable popups in your browser security settings" +
" and try again.");
}
});
}
});
}
};
/**
@ -489,12 +548,49 @@ var Toolbar = (function (my) {
// Shows or hides SIP calls button
my.showSipCallButton = function (show) {
if (APP.xmpp.isSipGatewayEnabled() && show) {
$('#sipCallButton').css({display: "inline"});
$('#sipCallButton').css({display: "inline-block"});
} else {
$('#sipCallButton').css({display: "none"});
}
};
/**
* Displays user authenticated identity name(login).
* @param authIdentity identity name to be displayed.
*/
my.setAuthenticatedIdentity = function (authIdentity) {
if (authIdentity) {
$('#toolbar_auth_identity').css({display: "list-item"});
$('#toolbar_auth_identity').text(authIdentity);
} else {
$('#toolbar_auth_identity').css({display: "none"});
}
};
/**
* Shows/hides login button.
* @param show <tt>true</tt> to show
*/
my.showLoginButton = function (show) {
if (show) {
$('#toolbar_button_login').css({display: "list-item"});
} else {
$('#toolbar_button_login').css({display: "none"});
}
};
/**
* Shows/hides logout button.
* @param show <tt>true</tt> to show
*/
my.showLogoutButton = function (show) {
if (show) {
$('#toolbar_button_logout').css({display: "list-item"});
} else {
$('#toolbar_button_logout').css({display: "none"});
}
};
/**
* Sets the state of the button. The button has blue glow if desktop
* streaming is active.

View File

@ -1,6 +1,10 @@
/* global $, $iq, config, connection, UI, messageHandler,
roomName, sessionTerminated, Strophe, Util */
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
var Settings = require("../settings/Settings");
var AuthenticationEvents
= require("../../service/authentication/AuthenticationEvents");
/**
* Contains logic responsible for enabling/disabling functionality available
@ -60,6 +64,25 @@ var Moderator = {
init: function (xmpp, emitter) {
this.xmppService = xmpp;
eventEmitter = emitter;
// Message listener that talks to POPUP window
function listener(event) {
if (event.data && event.data.sessionId) {
if (event.origin !== window.location.origin) {
console.warn(
"Ignoring sessionId from different origin: " + event.origin);
return;
}
localStorage.setItem('sessionId', event.data.sessionId);
// After popup is closed we will authenticate
}
}
// Register
if (window.addEventListener) {
window.addEventListener("message", listener, false);
} else {
window.attachEvent("onmessage", listener);
}
},
onMucLeft: function (jid) {
@ -99,10 +122,24 @@ var Moderator = {
createConferenceIq: function (roomName) {
// Generate create conference IQ
var elem = $iq({to: Moderator.getFocusComponent(), type: 'set'});
// Session Id used for authentication
var sessionId = localStorage.getItem('sessionId');
var machineUID = Settings.getSettings().uid;
console.info(
"Session ID: " + sessionId + " machine UID: " + machineUID);
elem.c('conference', {
xmlns: 'http://jitsi.org/protocol/focus',
room: roomName
room: roomName,
'machine-uid': machineUID
});
if (sessionId) {
elem.attrs({ 'session-id': sessionId});
}
if (config.hosts.bridge !== undefined) {
elem.c(
'property',
@ -152,22 +189,44 @@ var Moderator = {
},
parseConfigOptions: function (resultIq) {
Moderator.setFocusUserJid(
$(resultIq).find('conference').attr('focusjid'));
var extAuthParam
= $(resultIq).find('>conference>property[name=\'externalAuth\']');
if (extAuthParam.length) {
externalAuthEnabled = extAuthParam.attr('value') === 'true';
var authenticationEnabled
= $(resultIq).find(
'>conference>property' +
'[name=\'authentication\'][value=\'true\']').length > 0;
console.info("Authentication enabled: " + authenticationEnabled);
externalAuthEnabled
= $(resultIq).find(
'>conference>property' +
'[name=\'externalAuth\'][value=\'true\']').length > 0;
console.info('External authentication enabled: ' + externalAuthEnabled);
if (!externalAuthEnabled) {
// We expect to receive sessionId in 'internal' authentication mode
var sessionId
= $(resultIq).find('conference').attr('session-id');
if (sessionId) {
console.info('Received sessionId: ' + sessionId);
localStorage.setItem('sessionId', sessionId);
}
}
console.info("External authentication enabled: " + externalAuthEnabled);
var authIdentity = $(resultIq).find('>conference').attr('identity');
eventEmitter.emit(AuthenticationEvents.IDENTITY_UPDATED,
authenticationEnabled, authIdentity);
// Check if focus has auto-detected Jigasi component(this will be also
// included if we have passed our host from the config)
if ($(resultIq).find(
'>conference>property[name=\'sipGatewayEnabled\']').length) {
'>conference>property' +
'[name=\'sipGatewayEnabled\'][value=\'true\']').length) {
sipGatewayEnabled = true;
}
@ -185,12 +244,14 @@ var Moderator = {
connection.sendIQ(
iq,
function (result) {
// Setup config options
Moderator.parseConfigOptions(result);
if ('true' === $(result).find('conference').attr('ready')) {
// Reset both timers
getNextTimeout(true);
getNextErrorTimeout(true);
// Setup config options
Moderator.parseConfigOptions(result);
// Exec callback
callback();
} else {
@ -208,7 +269,14 @@ var Moderator = {
function (error) {
// Not authorized to create new room
if ($(error).find('>error>not-authorized').length) {
console.warn("Unauthorized to start the conference");
console.warn("Unauthorized to start the conference", error);
if ($(error).find('>error>session-invalid').length) {
// FIXME: just retry
console.info("Session expired! - removing");
localStorage.removeItem("sessionId");
}
var toDomain
= Strophe.getDomainFromJid(error.getAttribute('to'));
if (toDomain === config.hosts.anonymousdomain) {
@ -248,28 +316,83 @@ var Moderator = {
);
},
getAuthUrl: function (roomName, urlCallback) {
getLoginUrl: function (roomName, urlCallback) {
var iq = $iq({to: Moderator.getFocusComponent(), type: 'get'});
iq.c('auth-url', {
iq.c('login-url', {
xmlns: 'http://jitsi.org/protocol/focus',
room: roomName
room: roomName,
'machine-uid': Settings.getSettings().uid
});
connection.sendIQ(
iq,
function (result) {
var url = $(result).find('auth-url').attr('url');
var url = $(result).find('login-url').attr('url');
url = url = decodeURIComponent(url);
if (url) {
console.info("Got auth url: " + url);
urlCallback(url);
} else {
console.error(
"Failed to get auth url fro mthe focus", result);
"Failed to get auth url from the focus", result);
}
},
function (error) {
console.error("Get auth url error", error);
}
);
},
getPopupLoginUrl: function (roomName, urlCallback) {
var iq = $iq({to: Moderator.getFocusComponent(), type: 'get'});
iq.c('login-url', {
xmlns: 'http://jitsi.org/protocol/focus',
room: roomName,
'machine-uid': Settings.getSettings().uid,
popup: true
});
connection.sendIQ(
iq,
function (result) {
var url = $(result).find('login-url').attr('url');
url = url = decodeURIComponent(url);
if (url) {
console.info("Got POPUP auth url: " + url);
urlCallback(url);
} else {
console.error(
"Failed to get POPUP auth url from the focus", result);
}
},
function (error) {
console.error('Get POPUP auth url error', error);
}
);
},
logout: function (callback) {
var iq = $iq({to: Moderator.getFocusComponent(), type: 'set'});
var sessionId = localStorage.getItem('sessionId');
if (!sessionId) {
callback();
return;
}
iq.c('logout', {
xmlns: 'http://jitsi.org/protocol/focus',
'session-id': sessionId
});
connection.sendIQ(
iq,
function (result) {
var logoutUrl = $(result).find('logout').attr('logout-url');
if (logoutUrl) {
logoutUrl = decodeURIComponent(logoutUrl);
}
console.info("Log out OK, url: " + logoutUrl, result);
localStorage.removeItem('sessionId');
callback(logoutUrl);
},
function (error) {
console.error("Logout error", error);
}
);
}
};

View File

@ -183,8 +183,7 @@ module.exports = function(XMPP, eventEmitter) {
this.role = member.role;
eventEmitter.emit(XMPPEvents.LOCALROLE_CHANGED,
from, member, pres, Moderator.isModerator(),
Moderator.isExternalAuthEnabled());
from, member, pres, Moderator.isModerator());
}
if (!this.joined) {
this.joined = true;

View File

@ -230,6 +230,12 @@ var XMPP = {
allocateConferenceFocus: function(roomName, callback) {
Moderator.allocateConferenceFocus(roomName, callback);
},
getLoginUrl: function (roomName, callback) {
Moderator.getLoginUrl(roomName, callback);
},
getPopupLoginUrl: function (roomName, callback) {
Moderator.getPopupLoginUrl(roomName, callback);
},
isModerator: function () {
return Moderator.isModerator();
},
@ -421,6 +427,9 @@ var XMPP = {
eject: function (jid) {
connection.moderate.eject(jid);
},
logout: function (callback) {
Moderator.logout(callback);
},
findJidFromResource: function (resource) {
return connection.emuc.findJidFromResource(resource);
},

View File

@ -0,0 +1,12 @@
var AuthenticationEvents = {
/**
* Event callback arguments:
* function(authenticationEnabled, userIdentity)
* authenticationEnabled - indicates whether authentication has been enabled
* in this session
* userIdentity - if user has been logged in then it contains user name. If
* contains 'null' or 'undefined' then user is not logged in.
*/
IDENTITY_UPDATED: "authentication.identity_updated"
};
module.exports = AuthenticationEvents;