From bc3e068e2e73caf6019096401d90cae22ed2d44f Mon Sep 17 00:00:00 2001
From: Bobak Oftadeh <bobakoftadeh@outlook.com>
Date: Tue, 19 Jun 2018 09:46:59 -0700
Subject: [PATCH] Client logger implemented

---
 bigbluebutton-html5/client/main.jsx           | 14 ++--
 .../log-client/server/methods/logClient.js    | 22 +++---
 .../imports/startup/client/auth.js            | 27 ++++++-
 .../imports/startup/client/logger.js          | 74 +++++++++++++++++++
 .../imports/ui/services/auth/index.js         | 53 ++++++++++++-
 bigbluebutton-html5/package-lock.json         | 39 ++++++++++
 bigbluebutton-html5/package.json              |  2 +
 .../private/config/settings-development.json  |  6 ++
 8 files changed, 216 insertions(+), 21 deletions(-)
 mode change 100644 => 100755 bigbluebutton-html5/client/main.jsx
 create mode 100755 bigbluebutton-html5/imports/startup/client/logger.js
 mode change 100644 => 100755 bigbluebutton-html5/imports/ui/services/auth/index.js

diff --git a/bigbluebutton-html5/client/main.jsx b/bigbluebutton-html5/client/main.jsx
old mode 100644
new mode 100755
index 2fee67cb38..9878237374
--- a/bigbluebutton-html5/client/main.jsx
+++ b/bigbluebutton-html5/client/main.jsx
@@ -2,15 +2,19 @@
 import React from 'react';
 import { Meteor } from 'meteor/meteor';
 import { render } from 'react-dom';
-import { log } from '/imports/ui/services/api';
 import renderRoutes from '/imports/startup/client/routes';
+import logger from '/imports/startup/client/logger';
 
 Meteor.startup(() => {
   render(renderRoutes(), document.getElementById('app'));
-
-  // Log all uncaught exceptions to the server
-  // TODO: There is no StackTrace on the ErrorEvent object
+  // Logs all uncaught exceptions to the client logger
   window.addEventListener('error', (e) => {
-    log('error', e);
+    const stack = e.error.stack;
+    let message = e.error.toString();
+
+    // Checks if stack includes the message, if not add the two together.
+    (stack.includes(message)) ? message = stack : message += `\n${stack}`;
+    logger.error(message);
   });
 });
+
diff --git a/bigbluebutton-html5/imports/api/log-client/server/methods/logClient.js b/bigbluebutton-html5/imports/api/log-client/server/methods/logClient.js
index 160e5a72b0..f116152949 100755
--- a/bigbluebutton-html5/imports/api/log-client/server/methods/logClient.js
+++ b/bigbluebutton-html5/imports/api/log-client/server/methods/logClient.js
@@ -7,23 +7,19 @@ const logClient = function (type, log, ...args) {
   const logContents = { ...args };
 
   if (User) {
-    const {
-      meetingId, name, intId, extId, authToken,
-    } = User;
-    const serverInfo = {
-      meetingId,
-      userName: name,
-      userIntId: intId,
-      userExtId: extId,
-      authToken,
-    };
-    logContents.serverInfo = serverInfo;
+    if (User.meetingId === args[0].meetingId) {
+      args[0].validUser = 'vaild';
+    } else {
+      args[0].validUser = 'invaild';
+    }
+  } else {
+    args[0].validUser = 'notFound';
   }
 
   if (typeof log === 'string' || log instanceof String) {
-    Logger.log(type, `CLIENT LOG: ${log}\n`, logContents);
+    Logger.log(type, `CLIENT LOG: ${log}`, logContents);
   } else {
-    Logger.log(type, `CLIENT LOG: ${JSON.stringify(log)}\n`, logContents);
+    Logger.log(type, `CLIENT LOG: ${JSON.stringify(log)}`, logContents);
   }
 };
 
diff --git a/bigbluebutton-html5/imports/startup/client/auth.js b/bigbluebutton-html5/imports/startup/client/auth.js
index 896e6370fc..590b752e9b 100755
--- a/bigbluebutton-html5/imports/startup/client/auth.js
+++ b/bigbluebutton-html5/imports/startup/client/auth.js
@@ -3,6 +3,7 @@ import SessionStorage from '/imports/ui/services/storage/session';
 import { setCustomLogoUrl } from '/imports/ui/components/user-list/service';
 import { log } from '/imports/ui/services/api';
 import deviceInfo from '/imports/utils/deviceInfo';
+import logger from '/imports/startup/client/logger';
 
 // disconnected and trying to open a new connection
 const STATUS_CONNECTING = 'connecting';
@@ -15,6 +16,9 @@ export function joinRouteHandler(nextState, replace, callback) {
     replace({ pathname: '/error/404' });
     callback();
   }
+  
+  // Old credentials stored in memory were being used when browsers was refreshed
+  Auth.clearCredentials();
 
   // use enter api to get params for the client
   const url = `/bigbluebutton/api/enter?sessionToken=${sessionToken}`;
@@ -24,6 +28,8 @@ export function joinRouteHandler(nextState, replace, callback) {
     .then(({ response }) => {
       const {
         returncode, meetingID, internalUserID, authToken, logoutUrl, customLogoURL, metadata,
+        externUserID, fullname, confname,
+
       } = response;
 
       if (returncode === 'FAILED') {
@@ -55,13 +61,32 @@ export function joinRouteHandler(nextState, replace, callback) {
         }) : {};
       SessionStorage.setItem(METADATA_KEY, metakeys);
 
-      Auth.set(meetingID, internalUserID, authToken, logoutUrl, sessionToken);
+      Auth.set(
+        meetingID, internalUserID, authToken, logoutUrl,
+        sessionToken, fullname, externUserID, confname,
+      );
 
       const path = deviceInfo.type().isPhone ? '/' : '/users';
+      const userInfo = window.navigator;
+
+      // Browser information is sent once on startup
+      // Sent here instead of Meteor.startup, as the
+      // user might not be validiated by then, thus user's data
+      // would not be sent with this information
+      const clientInfo = {
+        language: userInfo.language,
+        userAgent: userInfo.userAgent,
+        screenSize: { width: window.screen.width, height: window.screen.height },
+        windowSize: { width: window.innerWidth, height: window.innerHeight },
+        bbbVersion: Meteor.settings.public.app.bbbServerVersion,
+        location: window.location.href,
+      };
 
       replace({ pathname: path });
 
       callback();
+
+      logger.info(JSON.stringify(clientInfo));
     });
 }
 
diff --git a/bigbluebutton-html5/imports/startup/client/logger.js b/bigbluebutton-html5/imports/startup/client/logger.js
new file mode 100755
index 0000000000..7eef6f261e
--- /dev/null
+++ b/bigbluebutton-html5/imports/startup/client/logger.js
@@ -0,0 +1,74 @@
+import Auth from '/imports/ui/services/auth';
+import { Meteor } from 'meteor/meteor';
+import { createLogger, stdSerializers } from 'browser-bunyan';
+import { ConsoleFormattedStream } from '@browser-bunyan/console-formatted-stream';
+import { ServerStream } from '@browser-bunyan/server-stream';
+import { nameFromLevel } from '@browser-bunyan/levels';
+
+// The logger accepts "console","server", and "url" as targets
+// Multiple targets can be set as an array in the settings under public.log.target
+// Set the desired log levels to be sent under public.log.level
+// The accepted levels are "debug", "info", "warn", "error"
+// If sending to a url, provide the end-point on public.log.url
+// Call the logger by doing a function call with the level name, I.e, logger.warn('Hi on warn')
+
+const LOG_CONFIG = Meteor.settings.public.log || {};
+const loggerStreams = []; // Stores the targets streams
+const { fullInfo } = Auth;
+
+// create a custom stream that logs to an end-point
+class ServerLoggerStream extends ServerStream {
+  write(rec) {
+    if (fullInfo.meetingId != null) {
+      rec.clientInfo = fullInfo;
+    }
+    return super.write(rec);
+  }
+}
+
+// Created a custom stream to log to the meteor server
+class MeteorStream {
+  write(rec) {
+    if (fullInfo.meetingId != null) {
+      Meteor.call('logClient', nameFromLevel[rec.level], rec.msg, fullInfo);
+    } else {
+      Meteor.call('logClient', nameFromLevel[rec.level], rec.msg);
+    }
+  }
+}
+
+// Checks to see which targets have been chosen
+if (LOG_CONFIG.target.includes('console')) {
+  loggerStreams.unshift({
+    level: LOG_CONFIG.level, // sends logs that are this level and higher
+    stream: new ConsoleFormattedStream(),
+  });
+}
+
+if (LOG_CONFIG.target.includes('server')) {
+  loggerStreams.unshift({
+    level: LOG_CONFIG.level,
+    stream: new MeteorStream(),
+  });
+}
+
+if (LOG_CONFIG.target.includes('url')) {
+  loggerStreams.unshift({
+    level: LOG_CONFIG.level,
+    stream: new ServerLoggerStream({
+      url: LOG_CONFIG.url,
+      method: 'PUT',
+    }),
+  });
+}
+
+// Creates the logger with the array of streams of the chosen targets
+const logger = createLogger({
+  name: 'clientLogger',
+  streams: loggerStreams,
+  serializers: stdSerializers,
+  src: true,
+});
+
+
+export default logger;
diff --git a/bigbluebutton-html5/imports/ui/services/auth/index.js b/bigbluebutton-html5/imports/ui/services/auth/index.js
old mode 100644
new mode 100755
index 08d639ca57..d714597b58
--- a/bigbluebutton-html5/imports/ui/services/auth/index.js
+++ b/bigbluebutton-html5/imports/ui/services/auth/index.js
@@ -15,6 +15,9 @@ class Auth {
     this._authToken = Storage.getItem('authToken');
     this._sessionToken = Storage.getItem('sessionToken');
     this._logoutURL = Storage.getItem('logoutURL');
+    this._confname = Storage.getItem('confname');
+    this._externUserID = Storage.getItem('externUserID');
+    this._fullname = Storage.getItem('fullname');
     this._loggedIn = {
       value: false,
       tracker: new Tracker.Dependency(),
@@ -66,6 +69,33 @@ class Auth {
     return this._logoutURL;
   }
 
+  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;
+  }
+
   get loggedIn() {
     this._loggedIn.tracker.depend();
     return this._loggedIn.value;
@@ -83,15 +113,32 @@ class Auth {
       requesterToken: this.token,
       logoutURL: this.logoutURL,
       sessionToken: this.sessionToken,
+      fullname: this.fullname,
+      externUserID: this.externUserID,
+      confname: this.confname
+    };
+  }
+
+  get fullInfo() {
+    return {
+      sessionToken: this.sessionToken,
+      meetingId: this.meetingID,
+      requesterUserId: this.userID,
+      fullname: this.fullname,
+      confname: this.confname,
+      externUserID: this.externUserID,
     };
   }
 
-  set(meetingId, requesterUserId, requesterToken, logoutURL, sessionToken) {
+  set(meetingId, requesterUserId, requesterToken, logoutURL, sessionToken, fullname, externUserID, confname) {
     this.meetingID = meetingId;
     this.userID = requesterUserId;
     this.token = requesterToken;
     this.logoutURL = logoutURL;
     this.sessionToken = sessionToken;
+    this.fullname = fullname;
+    this.externUserID = externUserID;
+    this.confname = confname;
   }
 
   clearCredentials(...args) {
@@ -101,7 +148,9 @@ class Auth {
     this.loggedIn = false;
     this.logoutURL = null;
     this.sessionToken = null;
-
+    this.fullname = null;
+    this.externUserID = null
+    this.confname = null;
     return Promise.resolve(...args);
   }
 
diff --git a/bigbluebutton-html5/package-lock.json b/bigbluebutton-html5/package-lock.json
index f8b617f138..dbd84aa8a4 100755
--- a/bigbluebutton-html5/package-lock.json
+++ b/bigbluebutton-html5/package-lock.json
@@ -3,6 +3,32 @@
   "requires": true,
   "lockfileVersion": 1,
   "dependencies": {
+    "@browser-bunyan/console-formatted-stream": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@browser-bunyan/console-formatted-stream/-/console-formatted-stream-1.3.0.tgz",
+      "integrity": "sha1-PcBZqlwbKnofJuJwbiveuaCbvlc=",
+      "requires": {
+        "@browser-bunyan/levels": "1.3.0"
+      }
+    },
+    "@browser-bunyan/console-raw-stream": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@browser-bunyan/console-raw-stream/-/console-raw-stream-1.3.0.tgz",
+      "integrity": "sha1-zPJLVvImUFgpfGUX++zqhOu3gYw=",
+      "requires": {
+        "@browser-bunyan/levels": "1.3.0"
+      }
+    },
+    "@browser-bunyan/levels": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@browser-bunyan/levels/-/levels-1.3.0.tgz",
+      "integrity": "sha1-oFIwOuXRofm2Pus6lElaL0KfSDE="
+    },
+    "@browser-bunyan/server-stream": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@browser-bunyan/server-stream/-/server-stream-1.3.0.tgz",
+      "integrity": "sha1-U7MlP6T8WA6GrZoWNqA6ISo0W1Y="
+    },
     "abbrev": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -401,6 +427,19 @@
         "concat-map": "0.0.1"
       }
     },
+<<<<<<< HEAD
+=======
+    "browser-bunyan": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/browser-bunyan/-/browser-bunyan-1.3.0.tgz",
+      "integrity": "sha1-JjeNxY16mAAsyb/Pui6l1xJEmZI=",
+      "requires": {
+        "@browser-bunyan/console-formatted-stream": "1.3.0",
+        "@browser-bunyan/console-raw-stream": "1.3.0",
+        "@browser-bunyan/levels": "1.3.0"
+      }
+    },
+>>>>>>> 33222e3... Client logger configured
     "browser-detect": {
       "version": "0.2.28",
       "resolved": "https://registry.npmjs.org/browser-detect/-/browser-detect-0.2.28.tgz",
diff --git a/bigbluebutton-html5/package.json b/bigbluebutton-html5/package.json
index ae15a6a739..f83def4ff1 100755
--- a/bigbluebutton-html5/package.json
+++ b/bigbluebutton-html5/package.json
@@ -28,7 +28,9 @@
       "but Meteor 1.6.0.1 doesn't see it there for some reason",
       "need to investigate"
     ],
+    "@browser-bunyan/server-stream": "^1.3.0",
     "babel-runtime": "~6.26.0",
+    "browser-bunyan": "^1.3.0",
     "browser-detect": "^0.2.28",
     "classnames": "~2.2.5",
     "clipboard": "~1.7.1",
diff --git a/bigbluebutton-html5/private/config/settings-development.json b/bigbluebutton-html5/private/config/settings-development.json
index 178d9df90e..85ac58a62c 100755
--- a/bigbluebutton-html5/private/config/settings-development.json
+++ b/bigbluebutton-html5/private/config/settings-development.json
@@ -336,6 +336,12 @@
           }
         ]
       }
+      
+    },
+    "log": {
+      "level":"info",
+      "target": ["server"],
+      "url":""
     }
   },
 
-- 
GitLab