/* *+------------------------------------------------------------------------+ *| Licensed Materials - Property of IBM *| IBM Cognos Products: BI Content Explorer *| (C) Copyright IBM Corp. 2015, 2019 *| *| US Government Users Restricted Rights - Use, duplication or disclosure *| restricted by GSA ADP Schedule Contract with IBM Corp. *+------------------------------------------------------------------------+ */ define([ 'bi/glass/app/ContentView', './nls/StringResource', 'jquery', 'underscore', 'doT', 'text!./templates/QRSlideoutViewTemplate.html', './lib/qrcode/build/qrcode' ], function (ContentView, StringResource, $, _, dot, CAMobileTemplate, QRCode) { 'use strict'; var QRSlideoutView = ContentView.extend({ init: function(options) { QRSlideoutView.inherited('init', this, arguments); _.extend(this, options); this.$el.addClass('caMobilePaneContainer'); }, open: function(context, options) { this.glassContext = __glassAppController.glassContext; // eslint-disable-line no-undef this.options = options; this.render(); return Promise.resolve(); }, generateSlideout: function () { return dot.template(CAMobileTemplate)({ 'strings': { 'getMobileApp': StringResource.get('getMobileApp').toUpperCase(), 'cognosAnalytics': StringResource.get('cognosAnalytics'), 'downloadMobileApp': StringResource.get('downloadMobileApp'), 'genQRCode': StringResource.get('genQRCode'), 'mobileTwoFactor': StringResource.get('mobileTwoFactor'), 'learnMore': StringResource.get('learnMore'), 'appIos': StringResource.get('appIos'), 'appAndroid': StringResource.get('appAndroid'), 'appUseMessage': StringResource.get('appUseMessage').toUpperCase(), 'getAppMessage': StringResource.get('getAppMessage'), 'appIcon': this.options.appIcon } }); }, addEventListeners: function () { $('#mobileGenQR').click(this.onGenerateQRClick.bind(this)); $('.mobileTwoFactorMessage').click(this.onSecondFactorClick.bind(this)); }, /** * Render the mobile app property page view. */ render: function() { var slideoutHtml = this.generateSlideout(); this.$el.append(slideoutHtml); this.addEventListeners(); return Promise.resolve(this.$el); }, formatSecondFactorCountdownTime: function(startTime, expirationTime) { const differenceInTime = expirationTime - startTime; const minutes = Math.floor((differenceInTime % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((differenceInTime % (1000 * 60)) / 1000); const timeAsString = this.padTimeNumber(minutes) + ':' + this.padTimeNumber(seconds); return timeAsString; }, padTimeNumber: function(number) { number = String(number); while (number.length < 2) {number = '0' + number;} return number; }, setCountdownInterval: function(secondFactor) { const displayElement = $('.mobileQRTwoFactorTimer'); const finalTime = Date.parse(secondFactor.expires); var now; var timer = setInterval(function() { now = new Date().getTime(); var differenceInTime = finalTime - now; displayElement.html(this.formatSecondFactorCountdownTime(now, finalTime)); if (differenceInTime < 0) { clearInterval(timer); displayElement.html(StringResource.get('tokenExpired')); } }.bind(this), 1000); }, generateQR: function (deepLink) { QRCode.toCanvas(document.getElementById('mobileQRCodeCanvas'), deepLink, function(err) { if(err) console.log(err); }); this.hideGenerateQRDialog(); }, hideGenerateQRDialog: function () { $('#mobileQRCodeCanvas').style = 'width: 200px; height: 200px'; $('#mobileGenQR').addClass('hidden'); }, displayTwoFactor: function (secondFactor) { const startTime = new Date().getTime(); const expirationTime = Date.parse(secondFactor.expires); $('.mobileQRTwoFactor').removeClass('hidden'); $('.mobileQRTwoFactorPin').html(secondFactor.value); $('.mobileQRTwoFactorTimer').html(this.formatSecondFactorCountdownTime(startTime, expirationTime)); }, /** * Generates a QR code and places it into the QRCodeCanvas element */ onGenerateQRClick: function() { this.retrieveLoginToken().then(function(response) { const secondFactor = response.secondFactor; const deepLink = this.formatDeepLink(response); this.generateQR(deepLink); this.displayTwoFactor(secondFactor); this.setCountdownInterval(secondFactor); }.bind(this)).catch(function() { const deepLink = this.formatDeepLink(); this.generateQR(deepLink); }.bind(this)); }, /** * Takes in the JSON response of v1/loginToken and outputs a deeplink to the app * Also removes the second factor from the response */ formatDeepLink: function(response) { // Save the secondFactor locally and remove it from the json var deepLink = `camobile://?serverUrl=${encodeURIComponent(this.getServerURL())}`; if(response) { deepLink = deepLink + `&loginToken=${encodeURIComponent(JSON.stringify(response.loginToken))}` + `&x-ca-affinity=${encodeURIComponent(response.affinityHeader)}`; } return deepLink; }, /** * Displays the second factor and sets a countdown */ onSecondFactorClick: function() { if(!this.secondFactor) { return false; } $('.mobileTwoFactorPin').html(this.secondFactor.value); $('.mobileTwoFactor').removeClass('hidden'); var expirationDate = Date.parse(this.secondFactor.expires); var now = new Date().getTime(); $('.mobileTwoFactorTimer').html(this.formatSecondFactorCountdownTime(now, expirationDate)); this._createCountdownInterval($('.mobileTwoFactorTimer'), expirationDate); }, /** * Call user profile services to retrieve the loginToken */ retrieveLoginToken: function() { var options = { 'url': 'v1/loginToken', 'dataType': 'json', 'type': 'POST' }; return this.glassContext.getCoreSvc('.Ajax').ajax(options) .then(function(response) { const payload = response.data; payload.affinityHeader = response.jqXHR.getResponseHeader('x-ca-affinity'); return Promise.resolve(payload); }.bind(this)).catch(this.handleLoginTokenError.bind(this)); }, handleLoginTokenError: function(err) { this.logger.error(err); return Promise.reject(err); }, getServerURL: function() { return window.location.origin; } }); return QRSlideoutView; });