diff --git a/app/admin_components/adf-admins/dreamfactory-admins.js b/app/admin_components/adf-admins/dreamfactory-admins.js index 003a2e17..4f5a2599 100644 --- a/app/admin_components/adf-admins/dreamfactory-admins.js +++ b/app/admin_components/adf-admins/dreamfactory-admins.js @@ -1174,7 +1174,7 @@ angular.module('dfAdmins', ['ngRoute', 'dfUtility', 'dfApplication', 'dfHelp']) }; }]) - .directive('dfExportAdmins', ['MOD_ADMIN_ASSET_PATH', 'INSTANCE_URL', 'UserDataService', '$http', '$window', 'APP_API_KEY', function (MOD_ADMIN_ASSET_PATH, INSTANCE_URL, UserDataService, $http, $window, APP_API_KEY) { + .directive('dfExportAdmins', ['MOD_ADMIN_ASSET_PATH', 'INSTANCE_URL', 'UserDataService', '$http', '$window', 'SystemConfigDataService', function (MOD_ADMIN_ASSET_PATH, INSTANCE_URL, UserDataService, $http, $window, SystemConfigDataService) { return { @@ -1203,7 +1203,7 @@ angular.module('dfAdmins', ['ngRoute', 'dfUtility', 'dfApplication', 'dfHelp']) scope.fileFormatStr = fileFormatStr; - var params = 'file=admin.' + scope.fileFormatStr + '&api_key=' + APP_API_KEY; + var params = 'file=admin.' + scope.fileFormatStr + '&api_key=' + SystemConfigDataService.getApiKey(); var currentUser = UserDataService.getCurrentUser(); if (currentUser && currentUser.session_token) { params += '&session_token=' + currentUser.session_token; diff --git a/app/admin_components/adf-package-manager/dreamfactory-package-manager.js b/app/admin_components/adf-package-manager/dreamfactory-package-manager.js index 46211052..f64248c0 100644 --- a/app/admin_components/adf-package-manager/dreamfactory-package-manager.js +++ b/app/admin_components/adf-package-manager/dreamfactory-package-manager.js @@ -749,7 +749,7 @@ angular.module('dfPackageManager', ['ngRoute', 'dfUtility', 'ngclipboard']) } }; }]) - .directive('dfExportPackage', ['INSTANCE_URL', 'INSTANCE_API_PREFIX', 'APP_API_KEY', 'dfNotify', '$http', '$window', '$timeout', 'UserDataService', function (INSTANCE_URL, INSTANCE_API_PREFIX, APP_API_KEY, dfNotify, $http, $window, $timeout, UserDataService) { + .directive('dfExportPackage', ['INSTANCE_URL', 'INSTANCE_API_PREFIX', 'SystemConfigDataService', 'dfNotify', '$http', '$window', '$timeout', 'UserDataService', function (INSTANCE_URL, INSTANCE_API_PREFIX, SystemConfigDataService, dfNotify, $http, $window, $timeout, UserDataService) { return { @@ -912,7 +912,7 @@ angular.module('dfPackageManager', ['ngRoute', 'dfUtility', 'ngclipboard']) scope.exportDownload = function() { if (exportPath !== '') { - var params = "?api_key=" + APP_API_KEY; + var params = "?api_key=" + SystemConfigDataService.getApiKey(); var currentUser = UserDataService.getCurrentUser(); if (currentUser && currentUser.session_token) { params += "&session_token=" + currentUser.session_token; diff --git a/app/admin_components/adf-system-config/dreamfactory-system-config.js b/app/admin_components/adf-system-config/dreamfactory-system-config.js index ac74dc8f..cebd88ec 100644 --- a/app/admin_components/adf-system-config/dreamfactory-system-config.js +++ b/app/admin_components/adf-system-config/dreamfactory-system-config.js @@ -1329,6 +1329,10 @@ angular.module('dfSystemConfig', ['ngRoute', 'dfUtility', 'dfApplication']) getSystemConfig: function () { return dfApplicationData.getApiDataSync('environment'); + }, + getApiKey: function () { + + return this.getSystemConfig().platform.api_key } }; } diff --git a/app/admin_components/adf-user-management/dreamfactory-user-management.js b/app/admin_components/adf-user-management/dreamfactory-user-management.js index 0625f0ec..e67fe5eb 100644 --- a/app/admin_components/adf-user-management/dreamfactory-user-management.js +++ b/app/admin_components/adf-user-management/dreamfactory-user-management.js @@ -1766,7 +1766,7 @@ angular.module('dfUserManagement', ['ngRoute', 'ngCookies', 'dfUtility']) } }; }]) - .service('dfXHRHelper', ['INSTANCE_URL', 'APP_API_KEY', 'UserDataService', function (INSTANCE_URL, APP_API_KEY, UserDataService) { + .service('dfXHRHelper', ['INSTANCE_URL', 'SystemConfigDataService', 'UserDataService', function (INSTANCE_URL, SystemConfigDataService, UserDataService) { function _isEmpty(obj) { @@ -1792,7 +1792,7 @@ angular.module('dfUserManagement', ['ngRoute', 'ngCookies', 'dfUtility']) function _setHeaders(_xhrObj, _headersDataObj) { // Setting Dreamfactory Headers - _xhrObj.setRequestHeader("X-DreamFactory-API-Key", APP_API_KEY); + _xhrObj.setRequestHeader("X-DreamFactory-API-Key", SystemConfigDataService.getApiKey()); var currentUser = UserDataService.getCurrentUser(); if (currentUser && currentUser.session_tpken) { xhrObj.setRequestHeader("X-DreamFactory-Session-Token", currentUser.session_token); diff --git a/app/admin_components/adf-users/dreamfactory-users.js b/app/admin_components/adf-users/dreamfactory-users.js index ceb9d875..0afb6e76 100644 --- a/app/admin_components/adf-users/dreamfactory-users.js +++ b/app/admin_components/adf-users/dreamfactory-users.js @@ -1124,7 +1124,7 @@ angular.module('dfUsers', ['ngRoute', 'dfUtility', 'dfApplication', 'dfHelp']) }; }]) - .directive('dfExportUsers', ['MOD_USER_ASSET_PATH', 'INSTANCE_URL', 'UserDataService', '$http', '$window', 'APP_API_KEY', function (MOD_USER_ASSET_PATH, INSTANCE_URL, UserDataService, $http, $window, APP_API_KEY) { + .directive('dfExportUsers', ['MOD_USER_ASSET_PATH', 'INSTANCE_URL', 'UserDataService', '$http', '$window', 'SystemConfigDataService', function (MOD_USER_ASSET_PATH, INSTANCE_URL, UserDataService, $http, $window, SystemConfigDataService) { return { @@ -1153,7 +1153,7 @@ angular.module('dfUsers', ['ngRoute', 'dfUtility', 'dfApplication', 'dfHelp']) scope.fileFormatStr = fileFormatStr; - var params = 'file=user.' + scope.fileFormatStr + '&api_key=' + APP_API_KEY; + var params = 'file=user.' + scope.fileFormatStr + '&api_key=' + SystemConfigDataService.getApiKey() ; var currentUser = UserDataService.getCurrentUser(); if (currentUser && currentUser.session_token) { params += '&session_token=' + currentUser.session_token; diff --git a/app/admin_components/adf-utility/dreamfactory-utility.js b/app/admin_components/adf-utility/dreamfactory-utility.js index 83d88f81..1a740f85 100644 --- a/app/admin_components/adf-utility/dreamfactory-utility.js +++ b/app/admin_components/adf-utility/dreamfactory-utility.js @@ -2827,170 +2827,6 @@ angular.module('dfUtility', ['dfApplication']) } ]) - // allows us to make synchronous ajax calls. Not extensive enough in its - // functionality to replace $http but helps with loading/bootstrapping data - .service('XHRHelper', ['INSTANCE_URL', 'APP_API_KEY', '$cookies', function (INSTANCE_URL, APP_API_KEY, $cookies) { - - function _isEmpty(obj) { - - // null and undefined are "empty" - if (obj == null) return true; - - // Assume if it has a length property with a non-zero value - // that that property is correct. - if (obj.length > 0) return false; - if (obj.length === 0) return true; - - // Otherwise, does it have any properties of its own? - // Note that this doesn't handle - // toString and valueOf enumeration bugs in IE < 9 - for (var key in obj) { - if (hasOwnProperty.call(obj, key)) return false; - } - - return true; - } - - // Set DreamFactory Headers as well as additional passed in headers - function _setHeaders(_xhrObj, _headersDataObj) { - - // Setting Dreamfactory Headers - _xhrObj.setRequestHeader("X-DreamFactory-API-Key", APP_API_KEY); - var currentUser = UserDataService.getCurrentUser(); - if (currentUser && currentUser.session_tpken) { - xhrObj.setRequestHeader("X-DreamFactory-Session-Token", currentUser.session_token); - } - - // Set additional headers - for (var _key in _headersDataObj) { - - _xhrObj.setRequestHeader(_key, _headersDataObj[_key]); - } - } - - // Create url params - function _setParams(_paramsDataObj) { - - // Set a return var - var params = ''; - - // Check if we have any params - if (!_isEmpty(_paramsDataObj)) { - - // We do. - // begin query string - params = '?'; - - // Loop through object - for (var _key in _paramsDataObj) { - - // Create URL params out of object properties/values - params += _key + '=' + _paramsDataObj[_key] + '&'; - } - } - - // Check if params is empty string - // Did we have any params - if (params !== '') { - - // We did so trim of the trailing '&' from building the string - params = params.substring(0, params.length -1); - - // Encode the params - encodeURI(params); - } - - // Return our final params value - return params; - } - - - function _makeRequest(_method, _url, _async, _params, _headers, _mimeType) { - - - var xhr; - - // Create XHR object - if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari - xhr = new XMLHttpRequest(); - } - else {// code for IE6, IE5 - xhr = new ActiveXObject("Microsoft.XMLHTTP"); - } - - // set and encode params - var params = _setParams(_params); - - - // Do XHR - xhr.open(_method, INSTANCE_URL.url + '/' + _url + params, _async); - - // Set headers - _setHeaders(xhr, _headers); - - // Set mime type override - xhr.overrideMimeType(_mimeType); - - // Send our request - xhr.send(); - - - if (xhr.readyState === 4) { - return xhr; - } - } - - - function _ajax(optionsDataObj) { - - // We need a valid URL - // Do we have one? - if (!optionsDataObj.url || optionsDataObj.url === '') { - - // No. Throw an error - throw { - module: 'DreamFactory Utility Module', - type: 'error', - provider: 'dreamfactory', - exception: 'XHRHelper Request Failure: No URL provided' - } - } - - // Default xhr options - var defaults = { - method: "GET", - url: '', - async: false, - params: {}, - headers:{}, - mimeType: "application/json" - }; - - - // Merge user xhr options object with default xhr options object - for (var _key in defaults) { - - if (optionsDataObj.hasOwnProperty(_key)) { - defaults[_key] = optionsDataObj[_key]; - } - } - - // Make the request with the merged object - return _makeRequest(defaults.method, defaults.url, defaults.async, defaults.params, defaults.headers, defaults.mimeType); - - } - - - return { - - ajax: function(requestOptions) { - - return _ajax(requestOptions); - } - } - - }]) - // Notification service .service('dfNotify', ['dfApplicationData', function(dfApplicationData) { diff --git a/app/index.html b/app/index.html index 44fef8cf..497a44a2 100644 --- a/app/index.html +++ b/app/index.html @@ -127,6 +127,10 @@ + + + + diff --git a/app/interceptors/globalHeaders.interceptor.js b/app/interceptors/globalHeaders.interceptor.js new file mode 100644 index 00000000..8ea93f23 --- /dev/null +++ b/app/interceptors/globalHeaders.interceptor.js @@ -0,0 +1,21 @@ +'use strict'; +angular.module('dfApplication') + .factory('globalHeaders', ['$injector', function ($injector) { + + var isHTMLRequested = function (url) { + return url.indexOf('.html') > -1; + }; + return { + request: function (config) { + + if (!isHTMLRequested(config.url)) { + var SystemConfigDataService = $injector.get('SystemConfigDataService'); + var systemConfig = SystemConfigDataService.getSystemConfig(); + if (systemConfig && systemConfig.platform) { + config.headers['X-Dreamfactory-API-Key'] = systemConfig.platform.api_key + } + } + return config; + } + }; + }]); diff --git a/app/interceptors/httpValidSession.interceptor.js b/app/interceptors/httpValidSession.interceptor.js new file mode 100644 index 00000000..d01cd4eb --- /dev/null +++ b/app/interceptors/httpValidSession.interceptor.js @@ -0,0 +1,122 @@ +'use strict'; +angular.module('dfApplication') +// Intercepts outgoing http calls. Checks for valid session. If 401 will trigger a pop up login screen. + .factory('httpValidSession', ['$q', '$rootScope', '$location', 'INSTANCE_URL', '$injector', function ($q, $rootScope, $location, INSTANCE_URL, $injector) { + + var refreshSession = function (reject) { + + var $http = $injector.get('$http'); + var UserDataService = $injector.get('UserDataService'); + var user = UserDataService.getCurrentUser(); + var deferred = $injector.get('$q').defer(); + + var url = user.is_sys_admin ? '/system/admin/session' : '/user/session'; + + $http({ + method: 'PUT', + url: INSTANCE_URL.url + url + }).then(function (result) { + UserDataService.setCurrentUser(result.data); + retry(reject.config, deferred); + }, function () { + newSession(reject, deferred); + }); + + return deferred.promise; + }; + + var retry = function (config, deferred) { + + var request = { + method: config.method, + url: config.url + }; + if (config.params) { + request.params = config.params; + } + if (config.data) { + request.data = config.data; + } + if (config.transformRequest) { + request.transformRequest = config.transformRequest; + } + var $http = $injector.get('$http'); + $http(request).then(deferred.resolve, deferred.reject); + return deferred.promise; + }; + + var newSession = function (reject, deferred) { + + var UserDataService = $injector.get('UserDataService'); + UserDataService.unsetCurrentUser(); + + var UserEventsService = $injector.get('UserEventsService'); + var deferred = deferred || $injector.get('$q').defer(); + + $rootScope.$$childHead.openLoginWindow(reject); + $rootScope.$on('user:login:success', function () { + retry(reject.config, deferred); + }); + + return deferred.promise; + }; + + return { + + request: function (config) { + + return config; + }, + + requestError: function (reject) { + + return $q.reject(reject); + }, + + response: function (response) { + + return response; + }, + + responseError: function (reject) { + + switch ($location.path()) { + + // If we get an error from any of the + // login / register pages, ignore it. + // No need to pop up a login. + case '/login': + case '/user-invite': + case '/register-confirm': + case '/register': + case '/register-complete': + // apidocs has its own login + case '/apidocs': + break; + + default: + if (!reject.config.ignore401 && reject.config.url.indexOf('/session') === -1) { + var UserDataService = $injector.get('UserDataService'); + var currentUser = UserDataService.getCurrentUser(); + if (currentUser) { + if (reject.status === 401 || (reject.data && reject.data.error && reject.data.error.code === 401) || + ((reject.status === 403 || (reject.data && reject.data.error && reject.data.error.code === 403)) && reject.data.error.message.indexOf('The token has been blacklisted') >= 0)) { + + if (reject.data.error.message.indexOf('Token has expired') >= 0 || reject.config.url.indexOf('/profile') !== -1) { + // refresh session + return refreshSession(reject); + } + else { + // new session + return newSession(reject); + } + } + } + } + break; + } + + return $q.reject(reject); + } + }; + }]); diff --git a/app/interceptors/interceptor.config.js b/app/interceptors/interceptor.config.js new file mode 100644 index 00000000..97762b07 --- /dev/null +++ b/app/interceptors/interceptor.config.js @@ -0,0 +1,11 @@ +'use strict'; + +angular + .module('dreamfactoryApp') + .config(['$httpProvider', function ($httpProvider) { + + $httpProvider.defaults.headers.delete = {'Content-Type': 'application/json;charset=utf-8'}; + + $httpProvider.interceptors.push('httpValidSession'); + $httpProvider.interceptors.push('globalHeaders'); + }]); \ No newline at end of file diff --git a/app/scripts/app.js b/app/scripts/app.js index 3b92bc89..8ef9c2f7 100644 --- a/app/scripts/app.js +++ b/app/scripts/app.js @@ -131,18 +131,8 @@ angular // App should use this service when making calls to the API .service('INSTANCE_URL', ['INSTANCE_BASE_URL', 'INSTANCE_API_PREFIX', function (INSTANCE_BASE_URL, INSTANCE_API_PREFIX) { this.url = INSTANCE_BASE_URL + INSTANCE_API_PREFIX;}]) - // Set API key for this application - .constant('APP_API_KEY', '6498a8ad1beb9d84d63035c5d1120c007fad6de706734db9689f8996707e0f7d') - - // Set global header for calls made to DreamFactory instance - .config(['$httpProvider', 'APP_API_KEY', function($httpProvider, APP_API_KEY) { - - $httpProvider.defaults.headers.common['X-Dreamfactory-API-Key'] = APP_API_KEY; - $httpProvider.defaults.headers.delete = {'Content-Type': 'application/json;charset=utf-8'}; - }]) - // Configure main app routing rules - .config(['$routeProvider', '$locationProvider', '$httpProvider', '$qProvider', function ($routeProvider, $locationProvider, $httpProvider, $qProvider) { + .config(['$routeProvider', '$locationProvider', '$qProvider', function ($routeProvider, $locationProvider, $qProvider) { $locationProvider.hashPrefix(""); @@ -357,7 +347,6 @@ angular } }); - $httpProvider.interceptors.push('httpValidSession'); }]) // Configure Error handling diff --git a/dist/index.html b/dist/index.html index c8d9657c..124eccb5 100644 --- a/dist/index.html +++ b/dist/index.html @@ -2,7 +2,7 @@

You are using an outdated browser. Please upgrade your browser to improve your experience.