Skip to content

Commit

Permalink
closes RocketChat#7611 - append token auth in jitsi videoconference
Browse files Browse the repository at this point in the history
  • Loading branch information
rrzharikov committed Oct 4, 2018
1 parent 7aa8a26 commit 4d1d58b
Show file tree
Hide file tree
Showing 10 changed files with 3,496 additions and 3,100 deletions.
6,453 changes: 3,361 additions & 3,092 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
"ip-range-check": "^0.0.2",
"jquery": "^3.3.1",
"jschardet": "^1.6.0",
"jsrsasign": "^8.0.12",
"juice": "^4.3.2",
"ldapjs": "^1.0.2",
"less": "https://github.com/meteor/less.js/tarball/8130849eb3d7f0ecf0ca8d0af7c4207b0442e3f6",
Expand Down
5 changes: 4 additions & 1 deletion packages/rocketchat-i18n/i18n/de.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,9 @@
"It_works": "Es funktioniert",
"italics": "kursiv",
"Jitsi_Chrome_Extension": "Chrome Extension ID",
"Jitsi_Enabled_TokenAuth": "Einschalten JWT genehmigung",
"Jitsi_Application_ID": "Anwendungs ID (iss)",
"Jitsi_Application_Secret": "Anwendungsgeheimnis",
"Jitsi_Enable_Channels": "In Kanälen aktivieren",
"Job_Title": "Berufsbezeichnung",
"Join_audio_call": "Anruf beitreten",
Expand Down Expand Up @@ -2864,4 +2867,4 @@
"Your_push_was_sent_to_s_devices": "Eine Push-Nachricht wurde an %s Geräte gesendet.",
"Your_server_link": "Ihre Serververbindung",
"Your_workspace_is_ready": "Ihr Arbeitsbereich ist einsatzbereit 🎉"
}
}
3 changes: 3 additions & 0 deletions packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1509,6 +1509,9 @@
"It_works": "It works",
"italics": "italics",
"Jitsi_Chrome_Extension": "Chrome Extension Id",
"Jitsi_Enabled_TokenAuth": "Enable JWT auth",
"Jitsi_Application_ID": "Application ID (iss)",
"Jitsi_Application_Secret": "Application Secret",
"Jitsi_Enable_Channels": "Enable in Channels",
"Job_Title": "Job Title",
"join": "Join",
Expand Down
5 changes: 4 additions & 1 deletion packages/rocketchat-i18n/i18n/ru.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1467,6 +1467,9 @@
"It_works": "Оно работает",
"italics": "курсив",
"Jitsi_Chrome_Extension": "Идентификатор расширения для Chrome ",
"Jitsi_Enabled_TokenAuth": "Включить JWT авторизацию",
"Jitsi_Application_ID": "Идентификатор приложения (iss)",
"Jitsi_Application_Secret": "Секретный ключ",
"Jitsi_Enable_Channels": "Включить на канале",
"Job_Title": "Должность",
"join": "Присоединиться",
Expand Down Expand Up @@ -2852,4 +2855,4 @@
"Your_push_was_sent_to_s_devices": "Оповещение было отправлено на %s устройств.",
"Your_server_link": "Ссылка на ваш сервер",
"Your_workspace_is_ready": "Ваше рабочее пространство готово к работе 🎉"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,10 @@ var JitsiMeetExternalAPI;
* @param filmStripOnly if the value is true only the small videos will be
* visible.
* @param noSsl if the value is true https won't be used
* @param token if you need token authentication, then pass the token
* @constructor
*/
function JitsiMeetExternalAPI(domain, room_name, width, height, parentNode, configOverwrite, interfaceConfigOverwrite, noSsl) {
function JitsiMeetExternalAPI(domain, room_name, width, height, parentNode, configOverwrite, interfaceConfigOverwrite, noSsl, token) {
if (!width || width < MIN_WIDTH) width = MIN_WIDTH;
if (!height || height < MIN_HEIGHT) height = MIN_HEIGHT;

Expand All @@ -114,6 +115,9 @@ function JitsiMeetExternalAPI(domain, room_name, width, height, parentNode, conf
this.frameName = "jitsiConferenceFrame" + id;
this.url = (noSsl ? "http" : "https") + "://" + domain + "/";
if (room_name) this.url += room_name;
if (token) {
this.url += "?jwt=" + token;
}
this.url += "#jitsi_meet_external_api_id=" + id;

var key;
Expand Down
36 changes: 31 additions & 5 deletions packages/rocketchat-videobridge/client/views/videoFlexTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,22 @@ Template.videoFlexTab.onRendered(function() {
return closePanel();
}
this.timeout = null;
this.autorun(() => {
this.autorun(async() => {
if (RocketChat.settings.get('Jitsi_Enabled')) {
if (this.tabBar.getState() === 'opened') {
const roomId = Session.get('openedRoom');

const domain = RocketChat.settings.get('Jitsi_Domain');
const jitsiRoom = RocketChat.settings.get('Jitsi_URL_Room_Prefix') + RocketChat.settings.get('uniqueID') + roomId;
const uniqueID = RocketChat.settings.get('uniqueID');
const noSsl = !RocketChat.settings.get('Jitsi_SSL');
const isEnabledTokenAuth = RocketChat.settings.get('Jitsi_Enabled_TokenAuth');

let jitsiRoom = '';
if (typeof uniqueID !== 'undefined') {
jitsiRoom = RocketChat.settings.get('Jitsi_URL_Room_Prefix') + uniqueID + roomId;
} else {
jitsiRoom = RocketChat.settings.get('Jitsi_URL_Room_Prefix') + roomId;
}

if (jitsiRoomActive !== null && jitsiRoomActive !== jitsiRoom) {
jitsiRoomActive = null;
Expand All @@ -73,6 +81,19 @@ Template.videoFlexTab.onRendered(function() {
clearInterval(timeOut);
}
} else {

let accessToken = null;
if (isEnabledTokenAuth) {
accessToken = await new Promise((resolve, reject) =>
Meteor.call('jitsi:generateAccessToken', (error, result) => {
if (error) {
return reject(error);
}
resolve(result);
})
);
}

jitsiRoomActive = jitsiRoom;

RocketChat.TabBar.updateButton('video', { class: 'red' });
Expand All @@ -82,12 +103,16 @@ Template.videoFlexTab.onRendered(function() {

timeOut = Meteor.setInterval(() => Meteor.call('jitsi:updateTimeout', roomId), 10 * 1000);
let newWindow = null;
let queryString = '';
if (accessToken) {
queryString = `?jwt=${ accessToken }`;
}
if (Meteor.isCordova) {
newWindow = window.open(`${ (noSsl ? 'http://' : 'https://') + domain }/${ jitsiRoom }`, '_system');
newWindow = window.open(`${ (noSsl ? 'http://' : 'https://') + domain }/${ jitsiRoom }${ queryString }`, '_system');
closePanel();
clearInterval(timeOut);
} else {
newWindow = window.open(`${ (noSsl ? 'http://' : 'https://') + domain }/${ jitsiRoom }`, jitsiRoom);
newWindow = window.open(`${ (noSsl ? 'http://' : 'https://') + domain }/${ jitsiRoom }${ queryString }`, jitsiRoom);
const closeInterval = setInterval(() => {
if (newWindow.closed !== false) {
closePanel();
Expand All @@ -106,7 +131,8 @@ Template.videoFlexTab.onRendered(function() {

// Keep it from showing duplicates when re-evaluated on variable change.
if (!$('[id^=jitsiConference]').length) {
this.api = new JitsiMeetExternalAPI(domain, jitsiRoom, width, height, this.$('.video-container').get(0), configOverwrite, interfaceConfigOverwrite, noSsl);

this.api = new JitsiMeetExternalAPI(domain, jitsiRoom, width, height, this.$('.video-container').get(0), configOverwrite, interfaceConfigOverwrite, noSsl, accessToken);

/*
* Hack to send after frame is loaded.
Expand Down
1 change: 1 addition & 0 deletions packages/rocketchat-videobridge/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Package.onUse(function(api) {
api.addFiles('server/settings.js', 'server');
api.addFiles('server/models/Rooms.js', 'server');
api.addFiles('server/methods/jitsiSetTimeout.js', 'server');
api.addFiles('server/methods/jitsiGenerateToken.js', 'server');
api.addFiles('server/methods/bbb.js', 'server');
api.addFiles('server/actionLink.js', 'server');
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// we need only jws functionality
import { jws } from 'jsrsasign';

Meteor.methods({
'jitsi:generateAccessToken': () => {

if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'jitsi:generateToken' });
}

const jitsiDomain = RocketChat.settings.get('Jitsi_Domain');
const jitsiApplicationId = RocketChat.settings.get('Jitsi_Application_ID');
const jitsiApplicationSecret = RocketChat.settings.get('Jitsi_Application_Secret');

function addUserContextToPayload(payload) {
const user = Meteor.user();
payload.context = {
user: {
name: user.name,
email: user.emails[0].address,
avatar: Meteor.absoluteUrl(`avatar/${ user.username }`),
id: user._id,
},
};
return payload;
}

const JITSI_OPTIONS = {
jitsi_domain: jitsiDomain,
jitsi_lifetime_token: '1hour', // only 1 hour (for security reasons)
jitsi_application_id: jitsiApplicationId,
jitsi_application_secret: jitsiApplicationSecret,
};

const HEADER = {
typ: 'JWT',
alg: 'HS256',
};

const commonPayload = {
iss: JITSI_OPTIONS.jitsi_application_id,
sub: JITSI_OPTIONS.jitsi_domain,
iat: jws.IntDate.get('now'),
nbf: jws.IntDate.get('now'),
exp: jws.IntDate.get(`now + ${ JITSI_OPTIONS.jitsi_lifetime_token }`),
aud: 'RocketChat',
room: '*',
context: '', // first empty
};

const header = JSON.stringify(HEADER);
const payload = JSON.stringify(addUserContextToPayload(commonPayload));

return jws.JWS.sign(HEADER.alg, header, payload, { rstr: JITSI_OPTIONS.jitsi_application_secret });
},
});
30 changes: 30 additions & 0 deletions packages/rocketchat-videobridge/server/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,36 @@ Meteor.startup(function() {
i18nLabel: 'Jitsi_Chrome_Extension',
public: true,
});

this.add('Jitsi_Enabled_TokenAuth', false, {
type: 'boolean',
enableQuery: {
_id: 'Jitsi_Enabled',
value: true,
},
i18nLabel: 'Jitsi_Enabled_TokenAuth',
public: true,
});

this.add('Jitsi_Application_ID', '', {
type: 'string',
enableQuery: [
{ _id: 'Jitsi_Enabled', value: true },
{ _id: 'Jitsi_Enabled_TokenAuth', value: true },
],
i18nLabel: 'Jitsi_Application_ID',
public: true,
});

this.add('Jitsi_Application_Secret', '', {
type: 'string',
enableQuery: [
{ _id: 'Jitsi_Enabled', value: true },
{ _id: 'Jitsi_Enabled_TokenAuth', value: true },
],
i18nLabel: 'Jitsi_Application_Secret',
public: true,
});
});
});
});

0 comments on commit 4d1d58b

Please sign in to comment.