bigbluebutton-Github/bigbluebutton-html5/imports/ui/services/auth/index.js

204 lines
4.9 KiB
JavaScript

import { Tracker } from 'meteor/tracker';
import Storage from '/imports/ui/services/storage/session';
import Users2x from '/imports/api/2.0/users';
import { makeCall, logClient } from '/imports/ui/services/api';
const CONNECTION_TIMEOUT = Meteor.settings.public.app.connectionTimeout;
class Auth {
constructor() {
this._meetingID = Storage.getItem('meetingID');
this._userID = Storage.getItem('userID');
this._authToken = Storage.getItem('authToken');
this._loggedIn = {
value: false,
tracker: new Tracker.Dependency(),
};
}
get meetingID() {
return this._meetingID;
}
set meetingID(meetingID) {
this._meetingID = meetingID;
Storage.setItem('meetingID', this._meetingID);
}
get userID() {
return this._userID;
}
set userID(userID) {
this._userID = userID;
Storage.setItem('userID', this._userID);
}
get token() {
return this._authToken;
}
set token(authToken) {
this._authToken = authToken;
Storage.setItem('authToken', this._authToken);
}
get loggedIn() {
this._loggedIn.tracker.depend();
return this._loggedIn.value;
}
set loggedIn(value) {
this._loggedIn.value = value;
this._loggedIn.tracker.changed();
}
get credentials() {
return {
meetingId: this.meetingID,
requesterUserId: this.userID,
requesterToken: this.token,
};
}
set(meetingId, requesterUserId, requesterToken) {
this.meetingID = meetingId;
this.userID = requesterUserId;
this.token = requesterToken;
}
set credentials(value) {
throw 'Credentials are read-only';
}
clearCredentials() {
this.meetingID = null;
this.userID = null;
this.token = null;
this.loggedIn = false;
return Promise.resolve(...arguments);
}
logout() {
if (!this.loggedIn) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
const credentialsSnapshot = {
meetingId: this.meetingID,
requesterUserId: this.userID,
requesterToken: this.token,
};
// make sure users who did not connect are not added to the meeting
// do **not** use the custom call - it relies on expired data
Meteor.call('userLogout', credentialsSnapshot, (error, result) => {
if (error) {
logClient('error', { error, method: 'userLogout', credentialsSnapshot });
} else {
this.fetchLogoutUrl()
.then(this.clearCredentials)
.then(resolve);
}
});
});
}
authenticate(force) {
if (this.loggedIn && !force) return Promise.resolve();
return this._subscribeToCurrentUser()
.then(this._addObserverToValidatedField.bind(this));
}
_subscribeToCurrentUser() {
const credentials = this.credentials;
return new Promise((resolve, reject) => {
Tracker.autorun((c) => {
if (!(credentials.meetingId && credentials.requesterToken && credentials.requesterUserId)) {
return reject({
error: 500,
description: 'Authentication subscription failed due to missing credentials.',
});
}
setTimeout(() => {
c.stop();
reject({
error: 500,
description: 'Authentication subscription timeout.',
});
}, 5000);
const subscription = Meteor.subscribe('current-user2x', credentials);
if (!subscription.ready()) return;
resolve(c);
});
});
}
_addObserverToValidatedField(prevComp) {
return new Promise((resolve, reject) => {
const validationTimeout = setTimeout(() => {
clearTimeout(validationTimeout);
prevComp.stop();
this.clearCredentials();
reject({
error: 500,
description: 'Authentication timeout.',
});
}, CONNECTION_TIMEOUT);
const didValidate = () => {
this.loggedIn = true;
clearTimeout(validationTimeout);
prevComp.stop();
resolve();
};
Tracker.autorun((c) => {
const selector = { meetingId: this.meetingID, userId: this.userID };
const query = Users2x.find(selector);
const handle = query.observeChanges({
changed: (id, fields) => {
if (fields.validated === true) {
c.stop();
didValidate();
}
if (fields.validated === false) {
c.stop();
this.clearCredentials();
reject({
error: 401,
description: 'Authentication failed.',
});
}
},
});
});
makeCall('validateAuthToken2x');
});
}
fetchLogoutUrl() {
const url = '/bigbluebutton/api/enter';
return fetch(url)
.then(response => response.json())
.then(data => Promise.resolve(data.response.logoutURL));
}
}
const AuthSingleton = new Auth();
export default AuthSingleton;