2017-12-14 01:40:46 +08:00
|
|
|
/* eslint prefer-promise-reject-errors: 0 */
|
2017-03-11 02:33:46 +08:00
|
|
|
import { Tracker } from 'meteor/tracker';
|
|
|
|
|
2016-07-07 20:50:32 +08:00
|
|
|
import Storage from '/imports/ui/services/storage/session';
|
2017-03-11 02:33:46 +08:00
|
|
|
|
2019-12-07 01:46:58 +08:00
|
|
|
import { initAnnotationsStreamListener } from '/imports/ui/components/whiteboard/service';
|
2020-10-08 17:15:05 +08:00
|
|
|
import allowRedirectToLogoutURL from '/imports/ui/components/meeting-ended/service';
|
2023-03-10 19:30:46 +08:00
|
|
|
import { initCursorStreamListener } from '/imports/ui/components/whiteboard/cursors/service';
|
2021-09-07 04:51:42 +08:00
|
|
|
import SubscriptionRegistry from '/imports/ui/services/subscription-registry/subscriptionRegistry';
|
2021-11-17 20:26:26 +08:00
|
|
|
import { ValidationStates } from '/imports/api/auth-token-validation';
|
2023-01-19 22:32:00 +08:00
|
|
|
import logger from '/imports/startup/client/logger';
|
2016-06-02 21:46:35 +08:00
|
|
|
|
2017-05-05 22:30:15 +08:00
|
|
|
const CONNECTION_TIMEOUT = Meteor.settings.public.app.connectionTimeout;
|
|
|
|
|
2016-07-11 21:45:24 +08:00
|
|
|
class Auth {
|
|
|
|
constructor() {
|
2018-08-11 01:51:12 +08:00
|
|
|
this._loggedIn = {
|
|
|
|
value: false,
|
|
|
|
tracker: new Tracker.Dependency(),
|
|
|
|
};
|
|
|
|
|
|
|
|
const queryParams = new URLSearchParams(document.location.search);
|
|
|
|
if (queryParams.has('sessionToken')
|
|
|
|
&& queryParams.get('sessionToken') !== Session.get('sessionToken')) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-11 21:45:24 +08:00
|
|
|
this._meetingID = Storage.getItem('meetingID');
|
|
|
|
this._userID = Storage.getItem('userID');
|
|
|
|
this._authToken = Storage.getItem('authToken');
|
2017-07-19 20:44:47 +08:00
|
|
|
this._sessionToken = Storage.getItem('sessionToken');
|
2017-07-15 00:59:02 +08:00
|
|
|
this._logoutURL = Storage.getItem('logoutURL');
|
2018-06-20 00:46:59 +08:00
|
|
|
this._confname = Storage.getItem('confname');
|
|
|
|
this._externUserID = Storage.getItem('externUserID');
|
|
|
|
this._fullname = Storage.getItem('fullname');
|
2021-10-29 01:21:30 +08:00
|
|
|
this._connectionID = Storage.getItem('connectionID');
|
2016-07-11 21:45:24 +08:00
|
|
|
}
|
2016-06-02 21:46:35 +08:00
|
|
|
|
2016-07-11 21:45:24 +08:00
|
|
|
get meetingID() {
|
|
|
|
return this._meetingID;
|
|
|
|
}
|
2016-06-02 21:46:35 +08:00
|
|
|
|
2016-07-11 21:45:24 +08:00
|
|
|
set meetingID(meetingID) {
|
|
|
|
this._meetingID = meetingID;
|
|
|
|
Storage.setItem('meetingID', this._meetingID);
|
|
|
|
}
|
2016-06-02 21:46:35 +08:00
|
|
|
|
2022-01-22 08:25:53 +08:00
|
|
|
set _connectionID(connectionId) {
|
|
|
|
this._connectionID = connectionId;
|
|
|
|
Storage.setItem('sessionToken', this._connectionID);
|
|
|
|
}
|
|
|
|
|
|
|
|
get sessionToken() {
|
|
|
|
return this._sessionToken;
|
|
|
|
}
|
|
|
|
|
2017-07-19 20:44:47 +08:00
|
|
|
set sessionToken(sessionToken) {
|
|
|
|
this._sessionToken = sessionToken;
|
|
|
|
Storage.setItem('sessionToken', this._sessionToken);
|
|
|
|
}
|
|
|
|
|
2016-07-11 21:45:24 +08:00
|
|
|
get userID() {
|
|
|
|
return this._userID;
|
|
|
|
}
|
2016-06-02 21:46:35 +08:00
|
|
|
|
2016-07-11 21:45:24 +08:00
|
|
|
set userID(userID) {
|
|
|
|
this._userID = userID;
|
|
|
|
Storage.setItem('userID', this._userID);
|
|
|
|
}
|
2016-06-18 06:15:11 +08:00
|
|
|
|
2016-07-11 21:45:24 +08:00
|
|
|
get token() {
|
|
|
|
return this._authToken;
|
2016-06-25 07:09:32 +08:00
|
|
|
}
|
2016-06-18 06:15:11 +08:00
|
|
|
|
2016-07-11 21:45:24 +08:00
|
|
|
set token(authToken) {
|
|
|
|
this._authToken = authToken;
|
|
|
|
Storage.setItem('authToken', this._authToken);
|
|
|
|
}
|
|
|
|
|
2017-07-15 00:59:02 +08:00
|
|
|
set logoutURL(logoutURL) {
|
|
|
|
this._logoutURL = logoutURL;
|
|
|
|
Storage.setItem('logoutURL', this._logoutURL);
|
|
|
|
}
|
|
|
|
|
|
|
|
get logoutURL() {
|
|
|
|
return this._logoutURL;
|
|
|
|
}
|
|
|
|
|
2018-06-20 00:46:59 +08:00
|
|
|
set confname(confname) {
|
|
|
|
this._confname = confname;
|
|
|
|
Storage.setItem('confname', this._confname);
|
|
|
|
}
|
|
|
|
|
|
|
|
get confname() {
|
|
|
|
return this._confname;
|
|
|
|
}
|
|
|
|
|
|
|
|
set externUserID(externUserID) {
|
|
|
|
this._externUserID = externUserID;
|
|
|
|
Storage.setItem('externUserID', this._externUserID);
|
|
|
|
}
|
|
|
|
|
|
|
|
get externUserID() {
|
|
|
|
return this._externUserID;
|
|
|
|
}
|
|
|
|
|
|
|
|
set fullname(fullname) {
|
|
|
|
this._fullname = fullname;
|
|
|
|
Storage.setItem('fullname', this._fullname);
|
|
|
|
}
|
|
|
|
|
|
|
|
get fullname() {
|
|
|
|
return this._fullname;
|
|
|
|
}
|
|
|
|
|
2017-03-10 03:50:21 +08:00
|
|
|
get loggedIn() {
|
2017-03-11 02:33:46 +08:00
|
|
|
this._loggedIn.tracker.depend();
|
|
|
|
return this._loggedIn.value;
|
2017-03-10 03:50:21 +08:00
|
|
|
}
|
|
|
|
|
2017-03-11 02:33:46 +08:00
|
|
|
set loggedIn(value) {
|
|
|
|
this._loggedIn.value = value;
|
|
|
|
this._loggedIn.tracker.changed();
|
|
|
|
}
|
|
|
|
|
2017-03-17 22:23:00 +08:00
|
|
|
get credentials() {
|
|
|
|
return {
|
|
|
|
meetingId: this.meetingID,
|
|
|
|
requesterUserId: this.userID,
|
|
|
|
requesterToken: this.token,
|
2017-07-15 00:59:02 +08:00
|
|
|
logoutURL: this.logoutURL,
|
2017-07-19 20:44:47 +08:00
|
|
|
sessionToken: this.sessionToken,
|
2018-06-20 00:46:59 +08:00
|
|
|
fullname: this.fullname,
|
|
|
|
externUserID: this.externUserID,
|
2018-08-14 03:52:44 +08:00
|
|
|
confname: this.confname,
|
2018-06-20 00:46:59 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
get fullInfo() {
|
|
|
|
return {
|
|
|
|
sessionToken: this.sessionToken,
|
|
|
|
meetingId: this.meetingID,
|
|
|
|
requesterUserId: this.userID,
|
|
|
|
fullname: this.fullname,
|
|
|
|
confname: this.confname,
|
|
|
|
externUserID: this.externUserID,
|
2019-06-29 05:47:18 +08:00
|
|
|
uniqueClientSession: this.uniqueClientSession,
|
2017-03-17 22:23:00 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-12-11 01:05:17 +08:00
|
|
|
set(
|
|
|
|
meetingId,
|
|
|
|
requesterUserId,
|
|
|
|
requesterToken,
|
|
|
|
logoutURL,
|
|
|
|
sessionToken,
|
|
|
|
fullname,
|
|
|
|
externUserID,
|
|
|
|
confname,
|
|
|
|
) {
|
2017-04-27 03:56:29 +08:00
|
|
|
this.meetingID = meetingId;
|
|
|
|
this.userID = requesterUserId;
|
|
|
|
this.token = requesterToken;
|
2017-07-15 00:59:02 +08:00
|
|
|
this.logoutURL = logoutURL;
|
2017-07-19 20:44:47 +08:00
|
|
|
this.sessionToken = sessionToken;
|
2018-06-20 00:46:59 +08:00
|
|
|
this.fullname = fullname;
|
|
|
|
this.externUserID = externUserID;
|
|
|
|
this.confname = confname;
|
2017-04-27 03:56:29 +08:00
|
|
|
}
|
|
|
|
|
2017-07-15 00:59:02 +08:00
|
|
|
clearCredentials(...args) {
|
2017-03-17 22:23:00 +08:00
|
|
|
this.meetingID = null;
|
|
|
|
this.userID = null;
|
|
|
|
this.token = null;
|
|
|
|
this.loggedIn = false;
|
2017-07-15 00:59:02 +08:00
|
|
|
this.logoutURL = null;
|
2017-07-19 20:44:47 +08:00
|
|
|
this.sessionToken = null;
|
2018-06-20 00:46:59 +08:00
|
|
|
this.fullname = null;
|
2018-08-14 03:52:44 +08:00
|
|
|
this.externUserID = null;
|
2018-06-20 00:46:59 +08:00
|
|
|
this.confname = null;
|
2019-06-29 05:47:18 +08:00
|
|
|
this.uniqueClientSession = null;
|
2017-07-15 00:59:02 +08:00
|
|
|
return Promise.resolve(...args);
|
2017-06-03 03:25:02 +08:00
|
|
|
}
|
2017-03-17 22:23:00 +08:00
|
|
|
|
|
|
|
logout() {
|
|
|
|
if (!this.loggedIn) {
|
2023-03-07 20:38:57 +08:00
|
|
|
if (allowRedirectToLogoutURL()) {
|
|
|
|
return Promise.resolve(this._logoutURL);
|
|
|
|
}
|
2017-03-17 22:23:00 +08:00
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
|
2017-07-15 00:59:02 +08:00
|
|
|
return new Promise((resolve) => {
|
2020-10-08 17:15:05 +08:00
|
|
|
if (allowRedirectToLogoutURL()) {
|
|
|
|
resolve(this._logoutURL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// do not redirect
|
|
|
|
resolve();
|
2017-03-17 22:23:00 +08:00
|
|
|
});
|
2017-06-03 03:25:02 +08:00
|
|
|
}
|
2017-03-17 22:23:00 +08:00
|
|
|
|
2017-04-27 03:56:29 +08:00
|
|
|
authenticate(force) {
|
2020-02-07 04:47:28 +08:00
|
|
|
if (this.loggedIn && !force) {
|
|
|
|
return Promise.resolve();
|
|
|
|
}
|
2017-04-18 01:14:31 +08:00
|
|
|
|
2017-12-14 01:40:46 +08:00
|
|
|
if (!(this.meetingID && this.userID && this.token)) {
|
|
|
|
return Promise.reject({
|
|
|
|
error: 401,
|
2020-10-08 03:50:17 +08:00
|
|
|
description: Session.get('errorMessageDescription') ? Session.get('errorMessageDescription') : 'Authentication failed due to missing credentials',
|
2017-03-11 02:33:46 +08:00
|
|
|
});
|
2017-12-14 01:40:46 +08:00
|
|
|
}
|
|
|
|
|
2018-03-17 03:22:27 +08:00
|
|
|
this.loggedIn = false;
|
2022-10-05 22:30:12 +08:00
|
|
|
this.isAuthenticating = true;
|
|
|
|
|
2018-03-17 03:22:27 +08:00
|
|
|
return this.validateAuthToken()
|
2019-06-29 05:47:18 +08:00
|
|
|
.then(() => {
|
|
|
|
this.loggedIn = true;
|
2019-07-03 05:15:32 +08:00
|
|
|
this.uniqueClientSession = `${this.sessionToken}-${Math.random().toString(36).substring(6)}`;
|
2022-10-05 22:30:12 +08:00
|
|
|
})
|
2023-01-20 19:44:21 +08:00
|
|
|
.catch((err) => {
|
2023-01-20 20:39:11 +08:00
|
|
|
logger.error(`Failed to validate token: ${err.description}`);
|
2023-03-02 02:51:33 +08:00
|
|
|
Session.set('codeError', err.error);
|
|
|
|
Session.set('errorMessageDescription', err.description);
|
2023-01-17 22:30:25 +08:00
|
|
|
})
|
2022-10-05 22:30:12 +08:00
|
|
|
.finally(() => {
|
|
|
|
this.isAuthenticating = false;
|
2019-06-29 05:47:18 +08:00
|
|
|
});
|
2017-03-11 02:33:46 +08:00
|
|
|
}
|
|
|
|
|
2017-12-14 01:40:46 +08:00
|
|
|
validateAuthToken() {
|
2021-10-29 01:21:30 +08:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
SubscriptionRegistry.createSubscription('current-user');
|
2017-03-11 02:33:46 +08:00
|
|
|
const validationTimeout = setTimeout(() => {
|
2017-04-18 01:14:31 +08:00
|
|
|
reject({
|
2020-10-08 03:50:17 +08:00
|
|
|
error: 408,
|
|
|
|
description: 'Authentication timeout',
|
2017-04-18 01:14:31 +08:00
|
|
|
});
|
2017-05-05 22:30:15 +08:00
|
|
|
}, CONNECTION_TIMEOUT);
|
2017-03-11 02:33:46 +08:00
|
|
|
|
2021-10-29 01:21:30 +08:00
|
|
|
Meteor.call('validateAuthToken', this.meetingID, this.userID, this.token, this.externUserID, (err, result) => {
|
|
|
|
const authenticationTokenValidation = result;
|
2020-09-02 00:31:11 +08:00
|
|
|
if (!authenticationTokenValidation) return;
|
|
|
|
|
|
|
|
switch (authenticationTokenValidation.validationStatus) {
|
|
|
|
case ValidationStates.INVALID:
|
2021-03-30 21:09:25 +08:00
|
|
|
reject({ error: 403, description: authenticationTokenValidation.reason });
|
2020-09-02 00:31:11 +08:00
|
|
|
break;
|
|
|
|
case ValidationStates.VALIDATED:
|
|
|
|
initCursorStreamListener();
|
|
|
|
initAnnotationsStreamListener();
|
|
|
|
clearTimeout(validationTimeout);
|
2021-10-29 01:21:30 +08:00
|
|
|
this.connectionID = authenticationTokenValidation.connectionId;
|
2022-05-18 00:09:41 +08:00
|
|
|
this.connectionAuthTime = new Date().getTime();
|
2021-10-20 04:35:39 +08:00
|
|
|
Session.set('userWillAuth', false);
|
2020-09-10 19:49:22 +08:00
|
|
|
setTimeout(() => resolve(true), 100);
|
2020-09-02 00:31:11 +08:00
|
|
|
break;
|
|
|
|
default:
|
2017-12-14 01:40:46 +08:00
|
|
|
}
|
2017-03-11 02:33:46 +08:00
|
|
|
});
|
|
|
|
});
|
2016-07-11 21:45:24 +08:00
|
|
|
}
|
2019-01-08 00:54:37 +08:00
|
|
|
|
|
|
|
authenticateURL(url) {
|
|
|
|
let authURL = url;
|
|
|
|
if (authURL.indexOf('sessionToken=') === -1) {
|
|
|
|
if (authURL.indexOf('?') !== -1) {
|
2019-05-15 04:13:15 +08:00
|
|
|
authURL = `${authURL}&sessionToken=${this.sessionToken}`;
|
2019-01-08 00:54:37 +08:00
|
|
|
} else {
|
2019-05-15 04:13:15 +08:00
|
|
|
authURL = `${authURL}?sessionToken=${this.sessionToken}`;
|
2019-01-08 00:54:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return authURL;
|
|
|
|
}
|
2017-06-03 03:25:02 +08:00
|
|
|
}
|
2016-06-29 02:50:44 +08:00
|
|
|
|
2017-06-03 03:25:02 +08:00
|
|
|
const AuthSingleton = new Auth();
|
2020-06-13 03:51:22 +08:00
|
|
|
export default AuthSingleton;
|