JWT client support
This commit is contained in:
parent
10b2746a3e
commit
8deb003ef6
2
Makefile
2
Makefile
|
@ -3,7 +3,7 @@ BROWSERIFY = ./node_modules/.bin/browserify
|
|||
UGLIFYJS = ./node_modules/.bin/uglifyjs
|
||||
EXORCIST = ./node_modules/.bin/exorcist
|
||||
CLEANCSS = ./node_modules/.bin/cleancss
|
||||
CSS_FILES = font.css toastr.css main.css videolayout_default.css font-awesome.css jquery-impromptu.css modaldialog.css notice.css popup_menu.css login_menu.css popover.css jitsi_popover.css contact_list.css chat.css welcome_page.css settingsmenu.css feedback.css jquery.contextMenu.css
|
||||
CSS_FILES = font.css toastr.css main.css overlay.css videolayout_default.css font-awesome.css jquery-impromptu.css modaldialog.css notice.css popup_menu.css login_menu.css popover.css jitsi_popover.css contact_list.css chat.css welcome_page.css settingsmenu.css feedback.css jquery.contextMenu.css
|
||||
DEPLOY_DIR = libs
|
||||
BROWSERIFY_FLAGS = -d
|
||||
OUTPUT_DIR = .
|
||||
|
|
22
app.js
22
app.js
|
@ -23,6 +23,7 @@ import conference from './conference';
|
|||
import API from './modules/API/API';
|
||||
|
||||
import UIEvents from './service/UI/UIEvents';
|
||||
import getTokenData from "./modules/TokenData/TokenData";
|
||||
|
||||
/**
|
||||
* Tries to push history state with the following parameters:
|
||||
|
@ -84,10 +85,24 @@ const APP = {
|
|||
require("./modules/keyboardshortcut/keyboardshortcut");
|
||||
this.translation = require("./modules/translation/translation");
|
||||
this.configFetch = require("./modules/config/HttpConfigFetch");
|
||||
this.tokenData = getTokenData();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* If JWT token data it will be used for local user settings
|
||||
*/
|
||||
function setTokenData() {
|
||||
let localUser = APP.tokenData.caller;
|
||||
if(localUser) {
|
||||
APP.settings.setEmail((localUser.getEmail() || "").trim());
|
||||
APP.settings.setAvatarUrl((localUser.getAvatarUrl() || "").trim());
|
||||
APP.settings.setDisplayName((localUser.getName() || "").trim());
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
setTokenData();
|
||||
var isUIReady = APP.UI.start();
|
||||
if (isUIReady) {
|
||||
APP.conference.init({roomName: buildRoomName()}).then(function () {
|
||||
|
@ -100,6 +115,11 @@ function init() {
|
|||
|
||||
APP.keyboardshortcut.init();
|
||||
}).catch(function (err) {
|
||||
APP.UI.hideRingOverLay();
|
||||
APP.API.sendPostisMessage({
|
||||
method: 'video-conference-left',
|
||||
params: {roomName: APP.conference.roomName}
|
||||
});
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
@ -151,7 +171,7 @@ $(document).ready(function () {
|
|||
|
||||
APP.translation.init(settings.getLanguage());
|
||||
|
||||
APP.API.init();
|
||||
APP.API.init(APP.tokenData.externalAPISettings);
|
||||
|
||||
obtainConfigAndInit();
|
||||
});
|
||||
|
|
135
conference.js
135
conference.js
|
@ -26,6 +26,18 @@ let currentAudioInputDevices, currentVideoInputDevices;
|
|||
|
||||
import {VIDEO_CONTAINER_TYPE} from "./modules/UI/videolayout/LargeVideo";
|
||||
|
||||
/**
|
||||
* Known custom conference commands.
|
||||
*/
|
||||
const commands = {
|
||||
CONNECTION_QUALITY: "stats",
|
||||
EMAIL: "email",
|
||||
AVATAR_URL: "avatar-url",
|
||||
ETHERPAD: "etherpad",
|
||||
SHARED_VIDEO: "shared-video",
|
||||
CUSTOM_ROLE: "custom-role"
|
||||
};
|
||||
|
||||
/**
|
||||
* Open Connection. When authentication failed it shows auth dialog.
|
||||
* @param roomName the room name to use
|
||||
|
@ -44,17 +56,13 @@ function connect(roomName) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Share email with other users.
|
||||
* @param emailCommand the email command
|
||||
* @param {string} email new email
|
||||
* Share data to other users.
|
||||
* @param command the command
|
||||
* @param {string} value new value
|
||||
*/
|
||||
function sendEmail (emailCommand, email) {
|
||||
room.sendCommand(emailCommand, {
|
||||
value: email,
|
||||
attributes: {
|
||||
id: room.myUserId()
|
||||
}
|
||||
});
|
||||
function sendData (command, value) {
|
||||
room.removeCommand(command);
|
||||
room.sendCommand(command, {value: value});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,7 +152,12 @@ function maybeRedirectToWelcomePage() {
|
|||
* @returns Promise.
|
||||
*/
|
||||
function disconnectAndShowFeedback(requestFeedback) {
|
||||
APP.UI.hideRingOverLay();
|
||||
connection.disconnect();
|
||||
APP.API.sendPostisMessage({
|
||||
method: 'video-conference-left',
|
||||
params: {roomName: APP.conference.roomName}
|
||||
});
|
||||
if (requestFeedback) {
|
||||
return APP.UI.requestFeedback();
|
||||
} else {
|
||||
|
@ -209,6 +222,55 @@ function setCurrentMediaDevices(devices) {
|
|||
d => d.kind === 'videoinput');
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the email for the local user
|
||||
* @param email {string} the new email
|
||||
*/
|
||||
function changeLocalEmail(email = '') {
|
||||
email = email.trim();
|
||||
|
||||
if (email === APP.settings.getEmail()) {
|
||||
return;
|
||||
}
|
||||
|
||||
APP.settings.setEmail(email);
|
||||
APP.UI.setUserEmail(room.myUserId(), email);
|
||||
sendData(commands.EMAIL, email);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes the local avatar url for the local user
|
||||
* @param avatarUrl {string} the new avatar url
|
||||
*/
|
||||
function changeLocalAvatarUrl(avatarUrl = '') {
|
||||
avatarUrl = avatarUrl.trim();
|
||||
|
||||
if (avatarUrl === APP.settings.getAvatarUrl()) {
|
||||
return;
|
||||
}
|
||||
|
||||
APP.settings.setAvatarUrl(avatarUrl);
|
||||
APP.UI.setUserAvatarUrl(room.myUserId(), avatarUrl);
|
||||
sendData(commands.AVATAR_URL, avatarUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the display name for the local user
|
||||
* @param nickname {string} the new display name
|
||||
*/
|
||||
function changeLocalDisplayName(nickname = '') {
|
||||
nickname = nickname.trim();
|
||||
|
||||
if (nickname === APP.settings.getDisplayName()) {
|
||||
return;
|
||||
}
|
||||
|
||||
APP.settings.setDisplayName(nickname);
|
||||
room.setDisplayName(nickname);
|
||||
APP.UI.changeDisplayName(APP.conference.localId, nickname);
|
||||
}
|
||||
|
||||
class ConferenceConnector {
|
||||
constructor(resolve, reject) {
|
||||
this._resolve = resolve;
|
||||
|
@ -227,6 +289,7 @@ class ConferenceConnector {
|
|||
}
|
||||
_onConferenceFailed(err, ...params) {
|
||||
console.error('CONFERENCE FAILED:', err, ...params);
|
||||
APP.UI.hideRingOverLay();
|
||||
switch (err) {
|
||||
// room is locked by the password
|
||||
case ConferenceErrors.PASSWORD_REQUIRED:
|
||||
|
@ -412,6 +475,9 @@ export default {
|
|||
this._createRoom(tracks);
|
||||
this.isDesktopSharingEnabled =
|
||||
JitsiMeetJS.isDesktopSharingEnabled();
|
||||
if(this.isDesktopSharingEnabled)
|
||||
APP.API.addPostisMessageListener('toggle-share-screen',
|
||||
() => this.toggleScreenSharing());
|
||||
|
||||
// if user didn't give access to mic or camera or doesn't have
|
||||
// them at all, we disable corresponding toolbar buttons
|
||||
|
@ -851,13 +917,7 @@ export default {
|
|||
/**
|
||||
* Known custom conference commands.
|
||||
*/
|
||||
defaults: {
|
||||
CONNECTION_QUALITY: "stats",
|
||||
EMAIL: "email",
|
||||
ETHERPAD: "etherpad",
|
||||
SHARED_VIDEO: "shared-video",
|
||||
CUSTOM_ROLE: "custom-role"
|
||||
},
|
||||
defaults: commands,
|
||||
/**
|
||||
* Receives notifications from other participants about commands aka
|
||||
* custom events (sent by sendCommand or sendCommandOnce methods).
|
||||
|
@ -910,7 +970,11 @@ export default {
|
|||
this._room = room; // FIXME do not use this
|
||||
|
||||
let email = APP.settings.getEmail();
|
||||
email && sendEmail(this.commands.defaults.EMAIL, email);
|
||||
email && sendData(this.commands.defaults.EMAIL, email);
|
||||
|
||||
let avatarUrl = APP.settings.getAvatarUrl();
|
||||
avatarUrl && sendData(this.commands.defaults.AVATAR_URL,
|
||||
avatarUrl);
|
||||
|
||||
let nick = APP.settings.getDisplayName();
|
||||
if (config.useNicks && !nick) {
|
||||
|
@ -1093,6 +1157,10 @@ export default {
|
|||
// add local streams when joined to the conference
|
||||
room.on(ConferenceEvents.CONFERENCE_JOINED, () => {
|
||||
APP.UI.mucJoined();
|
||||
APP.API.sendPostisMessage({
|
||||
method: 'video-conference-joined',
|
||||
params: {roomName: APP.conference.roomName}
|
||||
});
|
||||
});
|
||||
|
||||
room.on(
|
||||
|
@ -1297,33 +1365,20 @@ export default {
|
|||
APP.UI.initEtherpad(value);
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.EMAIL_CHANGED, (email = '') => {
|
||||
email = email.trim();
|
||||
|
||||
if (email === APP.settings.getEmail()) {
|
||||
return;
|
||||
}
|
||||
|
||||
APP.settings.setEmail(email);
|
||||
APP.UI.setUserAvatar(room.myUserId(), email);
|
||||
sendEmail(this.commands.defaults.EMAIL, email);
|
||||
});
|
||||
room.addCommandListener(this.commands.defaults.EMAIL, (data) => {
|
||||
APP.UI.setUserAvatar(data.attributes.id, data.value);
|
||||
APP.UI.addListener(UIEvents.EMAIL_CHANGED, changeLocalEmail);
|
||||
room.addCommandListener(this.commands.defaults.EMAIL, (data, from) => {
|
||||
APP.UI.setUserEmail(from, data.value);
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.NICKNAME_CHANGED, (nickname = '') => {
|
||||
nickname = nickname.trim();
|
||||
APP.UI.addListener(UIEvents.AVATAR_URL_CHANGED, changeLocalAvatarUrl);
|
||||
|
||||
if (nickname === APP.settings.getDisplayName()) {
|
||||
return;
|
||||
}
|
||||
|
||||
APP.settings.setDisplayName(nickname);
|
||||
room.setDisplayName(nickname);
|
||||
APP.UI.changeDisplayName(APP.conference.localId, nickname);
|
||||
room.addCommandListener(this.commands.defaults.AVATAR_URL,
|
||||
(data, from) => {
|
||||
APP.UI.setUserAvatarUrl(from, data.value);
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.NICKNAME_CHANGED, changeLocalDisplayName);
|
||||
|
||||
APP.UI.addListener(UIEvents.START_MUTED_CHANGED,
|
||||
(startAudioMuted, startVideoMuted) => {
|
||||
room.setStartMutedPolicy({
|
||||
|
|
|
@ -16,12 +16,13 @@
|
|||
* Executes createConnectionExternally function.
|
||||
*/
|
||||
(function () {
|
||||
var params = getConfigParamsFromUrl();
|
||||
|
||||
var hashParams = getConfigParamsFromUrl("hash", true);
|
||||
var searchParams = getConfigParamsFromUrl("search", true);
|
||||
|
||||
//Url params have higher proirity than config params
|
||||
var url = config.externalConnectUrl;
|
||||
if(params.hasOwnProperty('config.externalConnectUrl'))
|
||||
url = params["config.externalConnectUrl"];
|
||||
if(hashParams.hasOwnProperty('config.externalConnectUrl'))
|
||||
url = hashParams["config.externalConnectUrl"];
|
||||
|
||||
/**
|
||||
* Check if connect from connection.js was executed and executes the handler
|
||||
|
@ -57,7 +58,8 @@
|
|||
|
||||
url += "?room=" + room_name;
|
||||
|
||||
var token = params["config.token"] || config.token;
|
||||
var token = hashParams["config.token"] || config.token ||
|
||||
searchParams.jwt;
|
||||
if(token)
|
||||
url += "&token=" + token;
|
||||
|
||||
|
|
|
@ -33,6 +33,10 @@ html, body{
|
|||
display:none;
|
||||
}
|
||||
|
||||
#header_container {
|
||||
z-index: 1014;
|
||||
}
|
||||
|
||||
.toolbar_span {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1013;
|
||||
background: #000000; /* Old browsers */
|
||||
opacity: 0.75;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.overlay_container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
z-index: 1013;
|
||||
}
|
||||
|
||||
.overlay_content {
|
||||
color: #fff;
|
||||
font-weight: normal;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
width: 400px;
|
||||
height: 250px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
position:absolute;
|
||||
margin-top: -125px;
|
||||
margin-left: -200px;
|
||||
}
|
||||
|
||||
.overlay_avatar {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
position: relative;
|
||||
border-radius: 100px;
|
||||
z-index: 1013;
|
||||
float: left;
|
||||
margin-left: 100px;
|
||||
}
|
||||
|
||||
.overlay_text {
|
||||
position: relative;
|
||||
width: 400px;
|
||||
z-index: 1013;
|
||||
margin-top: 20px;
|
||||
float: left;
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1010;
|
||||
z-index: 1015;
|
||||
display: none;
|
||||
max-width: 300px;
|
||||
min-width: 100px;
|
||||
|
@ -121,4 +121,4 @@
|
|||
border-right-width: 0;
|
||||
border-left-color: #ffffff;
|
||||
bottom: -10px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ button.toast-close-button {
|
|||
}
|
||||
#toast-container {
|
||||
position: fixed;
|
||||
z-index: 999999;
|
||||
z-index: 1012;
|
||||
/*overrides*/
|
||||
|
||||
}
|
||||
|
|
|
@ -468,7 +468,7 @@
|
|||
position: absolute;
|
||||
width: 100%;
|
||||
top:50%;
|
||||
z-index: 10000;
|
||||
z-index: 1011;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
|
@ -488,7 +488,7 @@
|
|||
background: rgba(0,0,0,.5);
|
||||
padding: 10px;
|
||||
color: rgba(255,255,255,.5);
|
||||
z-index: 10000;
|
||||
z-index: 1011;
|
||||
}
|
||||
|
||||
.centeredVideoLabel {
|
||||
|
@ -506,7 +506,7 @@
|
|||
margin-left: auto;
|
||||
background: rgba(0,0,0,.5);
|
||||
color: #FFF;
|
||||
z-index: 10000;
|
||||
z-index: 1011;
|
||||
border-radius: 2px;
|
||||
-webkit-transition: all 2s 2s linear;
|
||||
transition: all 2s 2s linear;
|
||||
|
@ -522,4 +522,4 @@
|
|||
}
|
||||
|
||||
.hidden {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,8 +67,8 @@ case "$1" in
|
|||
sed -i 's/ --modules_enabled = { "token_verification" }/ modules_enabled = { "token_verification" }/g' $PROSODY_HOST_CONFIG
|
||||
|
||||
# Install luajwt
|
||||
if ! luarocks install luajwt; then
|
||||
echo "Failed to install luajwt - try installing it manually"
|
||||
if ! luarocks install jwt; then
|
||||
echo "Failed to install jwt - try installing it manually"
|
||||
fi
|
||||
|
||||
if [ -x "/etc/init.d/prosody" ]; then
|
||||
|
@ -85,7 +85,7 @@ case "$1" in
|
|||
else
|
||||
echo "Prosody config not found at $PROSODY_HOST_CONFIG - unable to auto-configure token authentication"
|
||||
fi
|
||||
|
||||
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
|
|
|
@ -241,6 +241,7 @@
|
|||
<div class="arrow-up"></div>
|
||||
<input type="text" id="setDisplayName" data-i18n="[placeholder]settings.name" placeholder="Name">
|
||||
<input type="text" id="setEmail" placeholder="E-Mail">
|
||||
<input type="text" id="setAvatarUrl" placeholder="Avatar URL" data-i18n="[placeholder]settings.avatar">
|
||||
<select id="languages_selectbox"></select>
|
||||
<div id = "startMutedOptions">
|
||||
<label class = "startMutedLabel">
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"speaker": "Speaker",
|
||||
"defaultNickname": "ex. Jane Pink",
|
||||
"defaultLink": "e.g. __url__",
|
||||
"calling": "Calling __name__ ...",
|
||||
"welcomepage":{
|
||||
"go": "GO",
|
||||
"roomname": "Enter room name",
|
||||
|
@ -94,7 +95,8 @@
|
|||
"selectAudioOutput": "Select audio output",
|
||||
"followMe": "Enable follow me",
|
||||
"noDevice": "None",
|
||||
"noPermission": "Permission to use device is not granted"
|
||||
"noPermission": "Permission to use device is not granted",
|
||||
"avatarUrl": "Avatar URL"
|
||||
},
|
||||
"videothumbnail":
|
||||
{
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* applications that embed Jitsi Meet
|
||||
*/
|
||||
|
||||
import postis from 'postis';
|
||||
|
||||
/**
|
||||
* List of the available commands.
|
||||
* @type {{
|
||||
|
@ -16,7 +18,28 @@
|
|||
* toggleContactList: toggleContactList
|
||||
* }}
|
||||
*/
|
||||
var commands = {};
|
||||
let commands = {};
|
||||
|
||||
/**
|
||||
* Object that will execute sendMessage
|
||||
*/
|
||||
let target = window.opener ? window.opener : window.parent;
|
||||
|
||||
/**
|
||||
* Array of functions that are going to receive the objects passed to this
|
||||
* window
|
||||
*/
|
||||
let messageListeners = [];
|
||||
|
||||
/**
|
||||
* Current status (enabled/disabled) of Postis.
|
||||
*/
|
||||
let enablePostis = false;
|
||||
|
||||
/**
|
||||
* Current status (enabled/disabled) of Post Message API.
|
||||
*/
|
||||
let enablePostMessage = false;
|
||||
|
||||
function initCommands() {
|
||||
commands = {
|
||||
|
@ -91,14 +114,6 @@ function processEvent(event) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends message to the external application.
|
||||
* @param object
|
||||
*/
|
||||
function sendMessage(object) {
|
||||
window.parent.postMessage(JSON.stringify(object), "*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a message event from the external application
|
||||
* @param event the message event
|
||||
|
@ -107,10 +122,11 @@ function processMessage(event) {
|
|||
var message;
|
||||
try {
|
||||
message = JSON.parse(event.data);
|
||||
} catch (e) {}
|
||||
|
||||
if(!message.type)
|
||||
} catch (e) {
|
||||
console.error("Cannot parse data", event.data);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (message.type) {
|
||||
case "command":
|
||||
processCommand(message);
|
||||
|
@ -119,18 +135,26 @@ function processMessage(event) {
|
|||
processEvent(message);
|
||||
break;
|
||||
default:
|
||||
console.error("Unknown type of the message");
|
||||
return;
|
||||
console.warn("Unknown message type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends message to the external application.
|
||||
* @param object {object} the object that will be sent as JSON string
|
||||
*/
|
||||
function sendMessage(object) {
|
||||
if(enablePostMessage)
|
||||
target.postMessage(JSON.stringify(object), "*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the API should be enabled or not.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isEnabled () {
|
||||
let hash = location.hash;
|
||||
return hash && hash.indexOf("external=true") > -1 && window.postMessage;
|
||||
return !!(hash && hash.indexOf("external=true") > -1 && window.postMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,7 +173,7 @@ function isEventEnabled (name) {
|
|||
* @param object data associated with the event
|
||||
*/
|
||||
function triggerEvent (name, object) {
|
||||
if (isEnabled() && isEventEnabled(name)) {
|
||||
if (isEventEnabled(name) && enablePostMessage) {
|
||||
sendMessage({
|
||||
type: "event",
|
||||
action: "result",
|
||||
|
@ -165,18 +189,34 @@ export default {
|
|||
* receive information from external applications that embed Jitsi Meet.
|
||||
* It also sends a message to the external application that APIConnector
|
||||
* is initialized.
|
||||
* @param options {object}
|
||||
* @param enablePostis {boolean} if true the postis npm
|
||||
* package for comminication with the parent window will be enabled.
|
||||
* @param enablePostMessage {boolean} if true the postMessageAPI for
|
||||
* comminication with the parent window will be enabled.
|
||||
*/
|
||||
init: function () {
|
||||
if (!isEnabled()) {
|
||||
init: function (options = {}) {
|
||||
options.enablePostMessage = options.enablePostMessage || isEnabled();
|
||||
if (!options.enablePostis &&
|
||||
!options.enablePostMessage) {
|
||||
return;
|
||||
}
|
||||
initCommands();
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener('message', processMessage, false);
|
||||
} else {
|
||||
window.attachEvent('onmessage', processMessage);
|
||||
enablePostis = options.enablePostis;
|
||||
enablePostMessage = options.enablePostMessage;
|
||||
|
||||
if(enablePostMessage) {
|
||||
initCommands();
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener('message', processMessage, false);
|
||||
} else {
|
||||
window.attachEvent('onmessage', processMessage);
|
||||
}
|
||||
sendMessage({type: "system", loaded: true});
|
||||
}
|
||||
|
||||
if(enablePostis) {
|
||||
this.postis = postis({window: target});
|
||||
}
|
||||
sendMessage({type: "system", loaded: true});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -187,6 +227,27 @@ export default {
|
|||
triggerEvent("outgoingMessage", {"message": body});
|
||||
},
|
||||
|
||||
/**
|
||||
* Sends message to the external application.
|
||||
* @param options {object}
|
||||
* @param method {string}
|
||||
* @param params {object} the object that will be sent as JSON string
|
||||
*/
|
||||
sendPostisMessage(options) {
|
||||
if(enablePostis)
|
||||
this.postis.send(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds listener for Postis messages.
|
||||
* @param method {string} postis mehtod
|
||||
* @param listener {function}
|
||||
*/
|
||||
addPostisMessageListener (method, listener) {
|
||||
if(enablePostis)
|
||||
this.postis.listen(method, listener);
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that
|
||||
* message was received.
|
||||
|
@ -238,14 +299,14 @@ export default {
|
|||
* Removes the listeners.
|
||||
*/
|
||||
dispose: function () {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.removeEventListener) {
|
||||
window.removeEventListener("message", processMessage, false);
|
||||
} else {
|
||||
window.detachEvent('onmessage', processMessage);
|
||||
if (enablePostMessage) {
|
||||
if (window.removeEventListener) {
|
||||
window.removeEventListener("message", processMessage, false);
|
||||
} else {
|
||||
window.detachEvent('onmessage', processMessage);
|
||||
}
|
||||
}
|
||||
if(enablePostis)
|
||||
this.postis.destroy();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/* global getConfigParamsFromUrl, config */
|
||||
|
||||
/**
|
||||
* Parses and handles JWT tokens. Sets config.token.
|
||||
*/
|
||||
|
||||
import * as jws from "jws";
|
||||
|
||||
/**
|
||||
* Get the JWT token from the URL.
|
||||
*/
|
||||
let params = getConfigParamsFromUrl("search", true);
|
||||
let jwt = params.jwt;
|
||||
|
||||
/**
|
||||
* Implements a user of conference.
|
||||
*/
|
||||
class User {
|
||||
/**
|
||||
* @param name {string} the name of the user.
|
||||
* @param email {string} the email of the user.
|
||||
* @param avatarUrl {string} the URL for the avatar of the user.
|
||||
*/
|
||||
constructor(name, email, avatarUrl) {
|
||||
this._name = name;
|
||||
this._email = email;
|
||||
this._avatarUrl = avatarUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* GETERS START.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the name property
|
||||
*/
|
||||
getName() {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the email property
|
||||
*/
|
||||
getEmail() {
|
||||
return this._email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL of the avatar
|
||||
*/
|
||||
getAvatarUrl() {
|
||||
return this._avatarUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* GETERS END.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Represent the data parsed from the JWT token
|
||||
*/
|
||||
class TokenData{
|
||||
/**
|
||||
* @param {string} the JWT token
|
||||
*/
|
||||
constructor(jwt) {
|
||||
if(!jwt)
|
||||
return;
|
||||
//Use jwt param as token if there is not other token set
|
||||
if(!config.token)
|
||||
config.token = jwt;
|
||||
this.jwt = jwt;
|
||||
|
||||
//External API settings
|
||||
this.externalAPISettings = {
|
||||
enablePostis: true
|
||||
};
|
||||
this._decode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the JWT token and sets the decoded data to properties.
|
||||
*/
|
||||
_decode() {
|
||||
this.decodedJWT = jws.decode(jwt);
|
||||
if(!this.decodedJWT || !this.decodedJWT.payload)
|
||||
return;
|
||||
this.payload = this.decodedJWT.payload;
|
||||
if(!this.payload.context)
|
||||
return;
|
||||
let callerData = this.payload.context.user;
|
||||
let calleeData = this.payload.context.callee;
|
||||
if(callerData)
|
||||
this.caller = new User(callerData.name, callerData.email,
|
||||
callerData.avatarUrl);
|
||||
if(calleeData)
|
||||
this.callee = new User(calleeData.name, calleeData.email,
|
||||
calleeData.avatarUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the TokenData instance.
|
||||
*/
|
||||
let data = null;
|
||||
|
||||
/**
|
||||
* Returns the data variable. Creates new TokenData instance if <tt>data</tt>
|
||||
* variable is null.
|
||||
*/
|
||||
export default function getTokenData() {
|
||||
if(!data)
|
||||
data = new TokenData(jwt);
|
||||
return data;
|
||||
}
|
|
@ -21,6 +21,7 @@ import FilmStrip from "./videolayout/FilmStrip";
|
|||
import SettingsMenu from "./side_pannels/settings/SettingsMenu";
|
||||
import Settings from "./../settings/Settings";
|
||||
import { reload } from '../util/helpers';
|
||||
import RingOverlay from "./ring_overlay/RingOverlay";
|
||||
|
||||
var EventEmitter = require("events");
|
||||
UI.messageHandler = require("./util/MessageHandler");
|
||||
|
@ -277,7 +278,7 @@ UI.initConference = function () {
|
|||
}
|
||||
|
||||
// Make sure we configure our avatar id, before creating avatar for us
|
||||
UI.setUserAvatar(id, Settings.getEmail());
|
||||
UI.setUserEmail(id, Settings.getEmail());
|
||||
|
||||
Toolbar.checkAutoEnableDesktopSharing();
|
||||
|
||||
|
@ -470,6 +471,10 @@ UI.start = function () {
|
|||
SettingsMenu.init(eventEmitter);
|
||||
}
|
||||
|
||||
if(APP.tokenData.callee) {
|
||||
UI.showRingOverLay();
|
||||
}
|
||||
|
||||
// Return true to indicate that the UI has been fully started and
|
||||
// conference ready.
|
||||
return true;
|
||||
|
@ -551,6 +556,7 @@ UI.getSharedDocumentManager = function () {
|
|||
* @param {string} displayName user nickname
|
||||
*/
|
||||
UI.addUser = function (id, displayName) {
|
||||
UI.hideRingOverLay();
|
||||
ContactList.addContact(id);
|
||||
|
||||
messageHandler.notify(
|
||||
|
@ -565,7 +571,7 @@ UI.addUser = function (id, displayName) {
|
|||
VideoLayout.addParticipantContainer(id);
|
||||
|
||||
// Configure avatar
|
||||
UI.setUserAvatar(id);
|
||||
UI.setUserEmail(id);
|
||||
|
||||
// set initial display name
|
||||
if(displayName)
|
||||
|
@ -800,21 +806,41 @@ UI.dockToolbar = function (isDock) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Update user avatar.
|
||||
* Updates the avatar for participant.
|
||||
* @param {string} id user id
|
||||
* @param {stirng} email user email
|
||||
* @param {stirng} avatarUrl the URL for the avatar
|
||||
*/
|
||||
UI.setUserAvatar = function (id, email) {
|
||||
// update avatar
|
||||
Avatar.setUserAvatar(id, email);
|
||||
|
||||
var avatarUrl = Avatar.getAvatarUrl(id);
|
||||
|
||||
function changeAvatar(id, avatarUrl) {
|
||||
VideoLayout.changeUserAvatar(id, avatarUrl);
|
||||
ContactList.changeUserAvatar(id, avatarUrl);
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
SettingsMenu.changeAvatar(avatarUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user email.
|
||||
* @param {string} id user id
|
||||
* @param {stirng} email user email
|
||||
*/
|
||||
UI.setUserEmail = function (id, email) {
|
||||
// update avatar
|
||||
Avatar.setUserEmail(id, email);
|
||||
|
||||
changeAvatar(id, Avatar.getAvatarUrl(id));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Update user avatar URL.
|
||||
* @param {string} id user id
|
||||
* @param {stirng} url user avatar url
|
||||
*/
|
||||
UI.setUserAvatarUrl = function (id, url) {
|
||||
// update avatar
|
||||
Avatar.setUserAvatarUrl(id, url);
|
||||
|
||||
changeAvatar(id, Avatar.getAvatarUrl(id));
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1216,7 +1242,7 @@ UI.showDeviceErrorDialog = function (micError, cameraError) {
|
|||
: ``;
|
||||
let doNotShowWarningAgainSection = showDoNotShowWarning
|
||||
? `<label>
|
||||
<input type='checkbox' id='doNotShowWarningAgain'>
|
||||
<input type='checkbox' id='doNotShowWarningAgain'>
|
||||
<span data-i18n='dialog.doNotShowWarningAgain'></span>
|
||||
</label>`
|
||||
: ``;
|
||||
|
@ -1343,4 +1369,19 @@ UI.enableMicrophoneButton = function () {
|
|||
Toolbar.markAudioIconAsDisabled(false);
|
||||
};
|
||||
|
||||
let bottomToolbarEnabled = null;
|
||||
|
||||
UI.showRingOverLay = function () {
|
||||
RingOverlay.show(APP.tokenData.callee);
|
||||
ToolbarToggler.setAlwaysVisibleToolbar(true);
|
||||
FilmStrip.toggleFilmStrip(false);
|
||||
};
|
||||
|
||||
UI.hideRingOverLay = function () {
|
||||
if(!RingOverlay.hide())
|
||||
return;
|
||||
ToolbarToggler.resetAlwaysVisibleToolbar();
|
||||
FilmStrip.toggleFilmStrip(true);
|
||||
};
|
||||
|
||||
module.exports = UI;
|
||||
|
|
|
@ -3,6 +3,19 @@
|
|||
let users = {};
|
||||
|
||||
export default {
|
||||
/**
|
||||
* Sets prop in users object.
|
||||
* @param id {string} user id
|
||||
* @param prop {string} name of the prop
|
||||
* @param val {string} value to be set
|
||||
*/
|
||||
_setUserProp: function (id, prop, val) {
|
||||
if(!val || (users[id] && users[id][prop] === val))
|
||||
return;
|
||||
if(!users[id])
|
||||
users[id] = {};
|
||||
users[id][prop] = val;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the user's avatar in the settings menu(if local user), contact list
|
||||
|
@ -10,13 +23,18 @@ export default {
|
|||
* @param id id of the user
|
||||
* @param email email or nickname to be used as a hash
|
||||
*/
|
||||
setUserAvatar: function (id, email) {
|
||||
if (email) {
|
||||
if (users[id] === email) {
|
||||
return;
|
||||
}
|
||||
users[id] = email;
|
||||
}
|
||||
setUserEmail: function (id, email) {
|
||||
this._setUserProp(id, "email", email);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the user's avatar in the settings menu(if local user), contact list
|
||||
* and thumbnail
|
||||
* @param id id of the user
|
||||
* @param url the url for the avatar
|
||||
*/
|
||||
setUserAvatarUrl: function (id, url) {
|
||||
this._setUserProp(id, "url", url);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -34,7 +52,15 @@ export default {
|
|||
return null;
|
||||
}
|
||||
|
||||
let avatarId = users[userId];
|
||||
let avatarId = null;
|
||||
const user = users[userId];
|
||||
|
||||
if(user) {
|
||||
if(user.url)
|
||||
return users[userId].url;
|
||||
|
||||
avatarId = users[userId].email;
|
||||
}
|
||||
|
||||
// If the ID looks like an email, we'll use gravatar.
|
||||
// Otherwise, it's a random avatar, and we'll use the configured
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/* global $ */
|
||||
|
||||
/**
|
||||
* Shows ring overlay
|
||||
*/
|
||||
class RingOverlay {
|
||||
/**
|
||||
* @param callee instance of User class from TokenData.js
|
||||
*/
|
||||
constructor(callee) {
|
||||
this.callee = callee;
|
||||
this._buildHtml();
|
||||
this.audio = $("#ring_overlay_ringing");
|
||||
this.audio[0].play();
|
||||
this._setAudioTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and appends the ring overlay to the html document
|
||||
*/
|
||||
_buildHtml() {
|
||||
$("body").append("<div class='overlay_container' >" +
|
||||
"<div class='overlay' /><div class='overlay_content'>" +
|
||||
"<img class='overlay_avatar' src='" +
|
||||
this.callee.getAvatarUrl() + "' />" +
|
||||
"<span data-i18n='calling' data-i18n-options='" +
|
||||
JSON.stringify({name: this.callee.getName()}) +
|
||||
"' class='overlay_text'>Calling " +
|
||||
this.callee.getName() + "...</span></div>" +
|
||||
"<audio id='ring_overlay_ringing' src='/sounds/ring.ogg' /></div>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the interval that is going to play the ringing sound.
|
||||
*/
|
||||
_setAudioTimeout() {
|
||||
this.interval = setInterval( () => {
|
||||
this.audio[0].play();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys and clears all the objects (html elements and audio interval)
|
||||
* related to the ring overlay.
|
||||
*/
|
||||
destroy() {
|
||||
if(this.interval)
|
||||
clearInterval(this.interval);
|
||||
$(".overlay_container").remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the current ring overlay instance.
|
||||
* Note: We want to have only 1 instance at a time.
|
||||
*/
|
||||
let overlay = null;
|
||||
|
||||
export default {
|
||||
/**
|
||||
* Shows the ring overlay for the passed callee.
|
||||
* @param callee {class User} the callee. Instance of User class from
|
||||
* TokenData.js
|
||||
*/
|
||||
show(callee) {
|
||||
if(overlay) {
|
||||
this.hide();
|
||||
}
|
||||
overlay = new RingOverlay(callee);
|
||||
},
|
||||
/**
|
||||
* Hides the ring overlay. Destroys all the elements related to the ring
|
||||
* overlay.
|
||||
*/
|
||||
hide() {
|
||||
if(!overlay)
|
||||
return false;
|
||||
overlay.destroy();
|
||||
overlay = null;
|
||||
return true;
|
||||
}
|
||||
};
|
|
@ -81,6 +81,12 @@ export default {
|
|||
function updateEmail () {
|
||||
emitter.emit(UIEvents.EMAIL_CHANGED, $('#setEmail').val());
|
||||
}
|
||||
|
||||
// AVATAR URL CHANGED
|
||||
function updateAvatarUrl () {
|
||||
emitter.emit(UIEvents.AVATAR_URL_CHANGED, $('#setAvatarUrl').val());
|
||||
}
|
||||
|
||||
$('#setEmail')
|
||||
.val(Settings.getEmail())
|
||||
.keyup(function (event) {
|
||||
|
@ -89,6 +95,14 @@ export default {
|
|||
}
|
||||
}).focusout(updateEmail);
|
||||
|
||||
$('#setAvatarUrl')
|
||||
.val(Settings.getAvatarUrl())
|
||||
.keyup(function (event) {
|
||||
if (event.keyCode === 13) { // enter
|
||||
updateAvatarUrl();
|
||||
}
|
||||
}).focusout(updateAvatarUrl);
|
||||
|
||||
|
||||
// START MUTED
|
||||
$("#startMutedOptions").change(function () {
|
||||
|
|
|
@ -7,6 +7,10 @@ import FilmStrip from '../videolayout/FilmStrip.js';
|
|||
|
||||
let toolbarTimeoutObject;
|
||||
let toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT;
|
||||
/**
|
||||
* If true the toolbar will be always displayed
|
||||
*/
|
||||
let alwaysVisibleToolbar = (config.alwaysVisibleToolbar === true);
|
||||
|
||||
function showDesktopSharingButton() {
|
||||
if (APP.conference.isDesktopSharingEnabled &&
|
||||
|
@ -21,7 +25,7 @@ function showDesktopSharingButton() {
|
|||
* Hides the toolbar.
|
||||
*/
|
||||
function hideToolbar() {
|
||||
if (config.alwaysVisibleToolbar) {
|
||||
if (alwaysVisibleToolbar) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -40,6 +44,19 @@ function hideToolbar() {
|
|||
}
|
||||
|
||||
const ToolbarToggler = {
|
||||
/**
|
||||
* Sets the value of alwaysVisibleToolbar variable.
|
||||
* @param value {boolean} the new value of alwaysVisibleToolbar variable
|
||||
*/
|
||||
setAlwaysVisibleToolbar(value) {
|
||||
alwaysVisibleToolbar = value;
|
||||
},
|
||||
/**
|
||||
* Resets the value of alwaysVisibleToolbar variable to the default one.
|
||||
*/
|
||||
resetAlwaysVisibleToolbar() {
|
||||
alwaysVisibleToolbar = (config.alwaysVisibleToolbar === true);
|
||||
},
|
||||
/**
|
||||
* Shows the main toolbar.
|
||||
*/
|
||||
|
|
|
@ -9,6 +9,7 @@ let cameraDeviceId = '';
|
|||
let micDeviceId = '';
|
||||
let welcomePageDisabled = false;
|
||||
let localFlipX = null;
|
||||
let avatarUrl = '';
|
||||
|
||||
function supportsLocalStorage() {
|
||||
try {
|
||||
|
@ -34,6 +35,7 @@ if (supportsLocalStorage()) {
|
|||
}
|
||||
|
||||
email = UIUtil.unescapeHtml(window.localStorage.email || '');
|
||||
avatarUrl = UIUtil.unescapeHtml(window.localStorage.avatarUrl || '');
|
||||
localFlipX = JSON.parse(window.localStorage.localFlipX || true);
|
||||
displayName = UIUtil.unescapeHtml(window.localStorage.displayname || '');
|
||||
language = window.localStorage.language;
|
||||
|
@ -98,6 +100,24 @@ export default {
|
|||
return email;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets new avatarUrl for local user and saves it to the local storage.
|
||||
* @param {string} newAvatarUrl new avatarUrl for the local user
|
||||
*/
|
||||
setAvatarUrl: function (newAvatarUrl) {
|
||||
avatarUrl = newAvatarUrl;
|
||||
window.localStorage.avatarUrl = UIUtil.escapeHtml(newAvatarUrl);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns avatarUrl address of the local user.
|
||||
* @returns {string} avatarUrl
|
||||
*/
|
||||
getAvatarUrl: function () {
|
||||
return avatarUrl;
|
||||
},
|
||||
|
||||
|
||||
getLanguage () {
|
||||
return language;
|
||||
},
|
||||
|
|
|
@ -29,8 +29,10 @@
|
|||
"jssha": "1.5.0",
|
||||
"retry": "0.6.1",
|
||||
"strophe": "^1.2.2",
|
||||
"strophejs-plugins": "^0.0.6",
|
||||
"toastr": "^2.0.3"
|
||||
"strophejs-plugins": "strophe/strophejs-plugins",
|
||||
"toastr": "^2.0.3",
|
||||
"postis": "^2.2.0",
|
||||
"jws": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"browserify": "11.1.x",
|
||||
|
|
|
@ -15,6 +15,7 @@ local host = module.host;
|
|||
local appId = module:get_option_string("app_id");
|
||||
local appSecret = module:get_option_string("app_secret");
|
||||
local allowEmptyToken = module:get_option_boolean("allow_empty_token");
|
||||
local disableRoomNameConstraints = module:get_option_boolean("disable_room_name_constraints");
|
||||
|
||||
if allowEmptyToken == true then
|
||||
module:log("warn", "WARNING - empty tokens allowed");
|
||||
|
@ -79,7 +80,7 @@ function provider.get_sasl_handler(session)
|
|||
|
||||
-- here we check if 'room' claim exists
|
||||
local room, roomErr = token_util.get_room_name(token, appSecret);
|
||||
if room == nil then
|
||||
if room == nil and disableRoomNameConstraints ~= true then
|
||||
if roomErr == nil then
|
||||
roomErr = "'room' claim is missing";
|
||||
end
|
||||
|
@ -88,7 +89,7 @@ function provider.get_sasl_handler(session)
|
|||
|
||||
-- now verify the whole token
|
||||
local result, msg
|
||||
= token_util.verify_token(token, appId, appSecret, room);
|
||||
= token_util.verify_token(token, appId, appSecret, room, disableRoomNameConstraints);
|
||||
if result == true then
|
||||
-- Binds room name to the session which is later checked on MUC join
|
||||
session.jitsi_meet_room = room;
|
||||
|
@ -121,4 +122,3 @@ local function anonymous(self, message)
|
|||
end
|
||||
|
||||
sasl.registerMechanism("ANONYMOUS", {"anonymous"}, anonymous);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ end
|
|||
local appId = parentCtx:get_option_string("app_id");
|
||||
local appSecret = parentCtx:get_option_string("app_secret");
|
||||
local allowEmptyToken = parentCtx:get_option_boolean("allow_empty_token");
|
||||
local disableRoomNameConstraints = parentCtx:get_option_boolean("disable_room_name_constraints")
|
||||
|
||||
log("debug",
|
||||
"%s - starting MUC token verifier app_id: %s app_secret: %s allow empty: %s",
|
||||
|
@ -35,13 +36,6 @@ local function verify_user(session, stanza)
|
|||
tostring(session.auth_token),
|
||||
tostring(session.jitsi_meet_room));
|
||||
|
||||
if allowEmptyToken and session.auth_token == nil then
|
||||
module:log(
|
||||
"debug",
|
||||
"Skipped room token verification - empty tokens are allowed");
|
||||
return nil;
|
||||
end
|
||||
|
||||
-- token not required for admin users
|
||||
local user_jid = stanza.attr.from;
|
||||
if is_admin(user_jid) then
|
||||
|
@ -49,6 +43,13 @@ local function verify_user(session, stanza)
|
|||
return nil;
|
||||
end
|
||||
|
||||
if allowEmptyToken and session.auth_token == nil then
|
||||
module:log(
|
||||
"debug",
|
||||
"Skipped room token verification - empty tokens are allowed");
|
||||
return nil;
|
||||
end
|
||||
|
||||
local room = string.match(stanza.attr.to, "^(%w+)@");
|
||||
log("debug", "Will verify token for user: %s, room: %s ", user_jid, room);
|
||||
if room == nil then
|
||||
|
@ -59,7 +60,7 @@ local function verify_user(session, stanza)
|
|||
|
||||
local token = session.auth_token;
|
||||
local auth_room = session.jitsi_meet_room;
|
||||
if room ~= auth_room then
|
||||
if room ~= auth_room and disableRoomNameConstraints ~= true then
|
||||
log("error", "Token %s not allowed to join: %s",
|
||||
tostring(token), tostring(auth_room));
|
||||
session.send(
|
||||
|
@ -81,4 +82,3 @@ module:hook("muc-occupant-pre-join", function(event)
|
|||
log("debug", "pre join: %s %s", tostring(room), tostring(stanza));
|
||||
return verify_user(origin, stanza);
|
||||
end);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
-- Token authentication
|
||||
-- Copyright (C) 2015 Atlassian
|
||||
|
||||
local jwt = require "luajwt";
|
||||
local jwt = require "jwt";
|
||||
|
||||
local _M = {};
|
||||
|
||||
|
@ -14,7 +14,7 @@ local function _get_room_name(token, appSecret)
|
|||
end
|
||||
end
|
||||
|
||||
local function _verify_token(token, appId, appSecret, roomName)
|
||||
local function _verify_token(token, appId, appSecret, roomName, disableRoomNameConstraints)
|
||||
|
||||
local claims, err = jwt.decode(token, appSecret, true);
|
||||
if claims == nil then
|
||||
|
@ -30,22 +30,22 @@ local function _verify_token(token, appId, appSecret, roomName)
|
|||
end
|
||||
|
||||
local roomClaim = claims["room"];
|
||||
if roomClaim == nil then
|
||||
if roomClaim == nil and disableRoomNameConstraints ~= true then
|
||||
return nil, "'room' claim is missing";
|
||||
end
|
||||
if roomName ~= nil and roomName ~= roomClaim then
|
||||
if roomName ~= nil and roomName ~= roomClaim and disableRoomNameConstraints ~= true then
|
||||
return nil, "Invalid room name('room' claim)";
|
||||
end
|
||||
|
||||
return true;
|
||||
end
|
||||
|
||||
function _M.verify_token(token, appId, appSecret, roomName)
|
||||
return _verify_token(token, appId, appSecret, roomName);
|
||||
function _M.verify_token(token, appId, appSecret, roomName, disableRoomNameConstraints)
|
||||
return _verify_token(token, appId, appSecret, roomName, disableRoomNameConstraints);
|
||||
end
|
||||
|
||||
function _M.get_room_name(token, appSecret)
|
||||
return _get_room_name(token, appSecret);
|
||||
end
|
||||
|
||||
return _M;
|
||||
return _M;
|
||||
|
|
|
@ -14,6 +14,10 @@ export default {
|
|||
* Notifies that local user changed email.
|
||||
*/
|
||||
EMAIL_CHANGED: "UI.email_changed",
|
||||
/**
|
||||
* Notifies that local user changed avatar url.
|
||||
*/
|
||||
AVATAR_URL_CHANGED: "UI.avatar_url_changed",
|
||||
/**
|
||||
* Notifies that "start muted" settings changed.
|
||||
*/
|
||||
|
|
Binary file not shown.
Binary file not shown.
29
utils.js
29
utils.js
|
@ -36,17 +36,32 @@ function getRoomName () {
|
|||
}
|
||||
|
||||
/**
|
||||
* Parses the hash parameters from the URL and returns them as a JS object.
|
||||
* Parses the parameters from the URL and returns them as a JS object.
|
||||
* @param source {string} values - "hash"/"search" if "search" the parameters
|
||||
* will parsed from location.search otherwise from location.hash
|
||||
* @param dontParse if false or undefined some transformations
|
||||
* (for parsing the value as JSON) are going to be executed
|
||||
*/
|
||||
function getConfigParamsFromUrl() {
|
||||
if (!location.hash)
|
||||
function getConfigParamsFromUrl(source, dontParse) {
|
||||
var paramStr = (source === "search")? location.search : location.hash;
|
||||
if (!paramStr)
|
||||
return {};
|
||||
var hash = location.hash.substr(1);
|
||||
paramStr = paramStr.substr(1);
|
||||
var result = {};
|
||||
hash.split("&").forEach(function (part) {
|
||||
paramStr.split("&").forEach(function (part) {
|
||||
var item = part.split("=");
|
||||
result[item[0]] = JSON.parse(
|
||||
decodeURIComponent(item[1]).replace(/\\&/, "&"));
|
||||
var value;
|
||||
try {
|
||||
value = (dontParse)? item[1] : JSON.parse(
|
||||
decodeURIComponent(item[1]).replace(/\\&/, "&"));
|
||||
} catch (e) {
|
||||
console.warn("Failed to parse URL argument", e);
|
||||
if(window.onerror)
|
||||
window.onerror("Failed to parse URL argument", null, null,
|
||||
null, e);
|
||||
return;
|
||||
}
|
||||
result[item[0]] = value;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue