{"version":3,"sources":["Form/Form.module.js","Toast/Toast.module.js","Nav/Nav.module.js","tfc-sso.min.js","sso/sso.module.js","sso/Auth/Auth.module.js","Form/Autofocus.directive.js","Form/ConfirmInput.directive.js","Toast/Toast.directive.js","Toast/Toast.service.js","Nav/AppVersion.service.js","Nav/CompileHtml.directive.js","Nav/MainNav.directive.js","Nav/Nav.service.js","Nav/Page.directive.js","Nav/TextUtil.service.js","sso/ForgotPassword.ctrl.js","sso/Login.ctrl.js","sso/PasswordReset.ctrl.js","sso/PasswordResetForm.directive.js","sso/RecoverPassword.ctrl.js","sso/Auth/Auth.service.js","sso/Auth/CookieJar.service.js"],"names":["angular","module","config","$stateProvider","$httpProvider","interceptors","push","state","abstract","template","$inject","NavProvider","$provide","addRight","getText","TextUtil","translateOr","parent","data","auth","isPublic","url","templateUrl","controller","resolve","logout","$state","Auth","go","email","$stateParams","getEmailByPasswordToken","t","then","expired","decorator","$delegate","$injector","can","stateName","get","privilege","_","run","$rootScope","$log","Toast","validatePromise","validate","$on","event","toState","toParams","hasValidated","isAuthenticated","name","preventDefault","$broadcast","defaultTo","warn","debug","dest","href","tfcAutofocus","$timeout","restrict","link","$scope","$el","$attrs","autoFocus","$eval","focus","directive","tfcConfirmInput","require","ctrls","ngModel","form","otherNgModel","Error","$watch","$dirty","$isEmpty","$modelValue","hasBeenCleared","$setViewValue","$setPristine","$render","$pristine","valid","$setValidity","ToastCtrl","vm","this","$watchCollection","list","messages","dismiss","translate","tfcToast","scope","ToastProvider","checkType","type","typeDefaults","hasOwnProperty","checkDelay","delay","isNaN","translator","calledUseTranslate","success","info","error","useTranslate","use","console","isFunction","isString","getDefaultDelay","setDefaultDelay","$get","text","fn","has","withAlertType","alertType","defaults","title","arguments","length","current","postMessage","extend","dismissed","quickFade","deleteMessage","message","cancel","pull","dismissMessage","dismissIrrelevant","each","slice","isInState","$current","self","provider","AppVersion","$q","extractMetadata","response","version","headers","appVersion","copyright","appCopyright","getAppVersion","getAppCopyright","responseError","reject","tfcAppVersion","factory","tfcCompileHtml","$compile","childScope","html","destroy","contents","remove","$new","MainNavCtrl","$element","$document","Nav","inject","fnName","item","invoke","mainItems","rightItems","userItems","isExpanded","onClick","canAccess","isActive","some","concat","children","toggle","appTitle","appWelcome","user","on","e","contains","target","$apply","mainMenu","items","rightMenu","userMenu","getUser","document","tfcMainNav","bindToController","fullWidth","welcome","firstName","mainMenuItems","rightMenuItems","userMenuItems","addMain","isPlainObject","addUser","setWelcome","setAppTitle","removeChangePassword","$sce","isInjectable","value","annotate","toInjectable","configureState","params","options","includes","fromFirstChild","keyPath","firstAccessibleChild","find","child","configureText","key","values","translateFilter","configureTemplate","trustAsHtml","forEach","map","x","msg","tfcPage","translationId","fallbackFn","undefined","ForgotPasswordCtrl","sent","submit","forgotPassword","LoginCtrl","usingActiveDirectory","login","PasswordResetCtrl","save","resetPassword","PasswordResetFormCtrl","tfcPasswordResetForm","onSubmit","RecoverPasswordCtrl","recoverPassword","newPass","AuthProvider","basePath","paths","_usingActiveDirectory","setBasePath","bp","setPath","path","$http","$urlRouter","CookieJar","initVars","_authenticatedUser","_isValid","_hasValidated","credentials","post","when","expiration","passwordExpiration","ttlMs","Date","now","ttlDays","Math","floor","toLocaleDateString","location","hash","sync","handleError","status","change","pick","token","newPassword","property","recentPasswordCount","permission","privileges","indexOf","isNonEmptyString","defaultDomain","domain","hostname","parts","split","join","cookiePairs","cookie","pair","set","expires","maxAge","getTime","toUTCString","_remove"],"mappings":"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","file":"tfc-sso.min.js","sourcesContent":["(function () {\n 'use strict';\n\n angular\n .module('tfc.Form', []);\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.Toast',\n [\n 'ui.router',\n 'ui.bootstrap'\n ]);\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.Nav',\n [\n 'ui.router'\n ])\n .config(config);\n\n // @ngInject\n function config($stateProvider, $httpProvider) {\n\n // Interceptor to extract the X-Application-Version header\n $httpProvider.interceptors.push('AppVersion');\n\n $stateProvider\n .state('page', {\n abstract : true,\n template : ''\n })\n .state('widePage', {\n abstract : true,\n template : ''\n })\n ;\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.Form', []);\n\n})();\n\n(function () {\n 'use strict';\n\n angular\n .module('tfc.Toast',\n [\n 'ui.router',\n 'ui.bootstrap'\n ]);\n\n})();\n\n(function () {\n 'use strict';\n\n config.$inject = [\"$stateProvider\", \"$httpProvider\"];\n angular\n .module('tfc.Nav',\n [\n 'ui.router'\n ])\n .config(config);\n\n // @ngInject\n function config($stateProvider, $httpProvider) {\n\n // Interceptor to extract the X-Application-Version header\n $httpProvider.interceptors.push('AppVersion');\n\n $stateProvider\n .state('page', {\n abstract : true,\n template : ''\n })\n .state('widePage', {\n abstract : true,\n template : ''\n })\n ;\n }\n\n})();\n\n(function () {\n 'use strict';\n\n config.$inject = [\"$stateProvider\", \"NavProvider\", \"$provide\"];\n run.$inject = [\"$rootScope\", \"$state\", \"Auth\", \"$log\", \"Toast\", \"TextUtil\"];\n angular\n .module('tfc.sso',\n [\n 'tfc.sso.Auth',\n 'tfc.sso.tmpls',\n 'tfc.Toast',\n 'tfc.Nav',\n 'tfc.Form'\n ])\n .config(config)\n .run(run);\n\n // @ngInject\n function config($stateProvider, NavProvider, $provide) {\n\n NavProvider.addRight({\n state : 'logout',\n // @ngInject\n getText : [\"TextUtil\", function (TextUtil) {\n return TextUtil.translateOr('auth.logout', function () {\n return 'Log Out';\n });\n }]\n });\n\n $stateProvider\n .state('login', {\n parent: 'page',\n data : {\n auth : { isPublic : true }\n },\n url : '/login?dest',\n templateUrl : 'sso/Login.tmpl.html',\n controller : 'LoginCtrl as vm'\n })\n .state('logout', {\n url : '/logout',\n template : '',\n resolve : {\n logout : [\"$state\", \"Auth\", function ($state, Auth) {\n return Auth.logout().finally(function () {\n $state.go('login');\n });\n }]\n }\n })\n .state('passwordReset', {\n parent : 'page',\n url : '/password/reset',\n templateUrl : 'sso/PasswordReset.tmpl.html',\n controller : 'PasswordResetCtrl as vm'\n })\n .state('passwordResetPublic', {\n parent : 'page',\n url : '/password/resetpub?email',\n data : {\n auth : { isPublic : true }\n },\n templateUrl : 'sso/PasswordResetPublic.tmpl.html',\n controller : 'PasswordResetCtrl as vm'\n })\n .state('forgotPassword', {\n parent : 'page',\n url : '/password/forgot?email&{expired:bool}',\n data : {\n auth : { isPublic : true }\n },\n templateUrl : 'sso/ForgotPassword.tmpl.html',\n controller : 'ForgotPasswordCtrl as vm'\n })\n .state('recoverPassword', {\n parent : 'page',\n // IMPORTANT: This MUST match the url in ForgotPasswordEmail.scala\n url : '/password/recover?t',\n data : {\n auth : { isPublic : true }\n },\n resolve : {\n email : [\"$state\", \"$stateParams\", \"Auth\", function ($state, $stateParams, Auth) {\n return Auth.getEmailByPasswordToken($stateParams.t).then(null, function () {\n $state.go('forgotPassword', { expired : true });\n });\n }]\n },\n templateUrl : 'sso/RecoverPassword.tmpl.html',\n controller : 'RecoverPasswordCtrl as vm'\n })\n ;\n\n $provide.decorator('$state', [\"$delegate\", \"$injector\", function ($delegate, $injector) {\n /**\n * @name $state#can\n * Add this function to the $state service so it can be used in the application.\n *\n * To add access to control to a state, add a data.auth property to the state config:\n * $stateProvider.state('foo', {\n * data : {\n * auth : {\n * // privilege required to view the foo state\n * privilege : 'somePrivilege',\n * // redirect to 'some.state' if the user tries to go here w/o the required privilege. defaults to dashboard\n * defaultTo : 'some.state'\n * }\n * },\n * ...\n * @param stateName String The state to check\n * @returns Boolean If the user can access this state.\n */\n $delegate.can = function (stateName) {\n // Avoid circular dependency\n var Auth = $injector.get('Auth');\n var state = $delegate.get(stateName);\n var privilege = _.get(state, 'data.auth.privilege');\n return !privilege || Auth.can(privilege);\n };\n\n return $delegate;\n }]);\n }\n\n // @ngInject\n function run($rootScope, $state, Auth, $log, Toast, TextUtil) {\n // Make sure the current JWT is still valid\n var validatePromise = Auth.validate();\n\n $rootScope.$on('$stateChangeStart', function (event, toState, toParams) {\n if (!Auth.hasValidated()) {\n event.preventDefault();\n if (!validatePromise) {\n // Re-validate after logging out\n validatePromise = Auth.validate();\n }\n validatePromise.finally(function () {\n // This prevents an infinite loop after logging out\n validatePromise = null;\n $state.go(toState.name, toParams);\n });\n } else {\n var isAuthenticated = Auth.isAuthenticated();\n\n // If they hit the login page but are already authenticated, just go to the app's default state\n if (isAuthenticated && toState.name === 'login') {\n event.preventDefault();\n $rootScope.$broadcast('auth.login');\n } else if (_.get(toState, 'data.auth.isPublic')) {\n return;\n }\n\n if (!isAuthenticated) {\n $log.debug('Not authenticated. Redirecting to Login');\n event.preventDefault();\n $state.go('login', { dest : $state.href(toState.name, toParams) });\n } else if (!$state.can(toState.name)) {\n event.preventDefault();\n var defaultTo = _.get(toState, 'data.auth.defaultTo');\n Toast.warn(TextUtil.translateOr('auth.error.lackPrivilege', function () {\n return 'Sorry, you do not have permission to do that.';\n }));\n if (defaultTo) {\n $state.go(defaultTo);\n }\n }\n }\n });\n }\n\n})();\n\n(function () {\n 'use strict';\n\n angular\n .module('tfc.sso.Auth',\n [\n 'ui.router',\n 'tfc.Toast'\n ]);\n\n})();\n\n(function () {\n 'use strict';\n\n tfcAutofocus.$inject = [\"$timeout\"];\n angular\n .module('tfc.Form')\n .directive('tfcAutofocus', tfcAutofocus);\n\n // @ngInject\n function tfcAutofocus($timeout) {\n return {\n restrict : 'A',\n link : function ($scope, $el, $attrs) {\n var autoFocus = $attrs.tfcAutofocus || 'true';\n $timeout(function () {\n if ($scope.$eval(autoFocus)) {\n $el[0].focus();\n }\n });\n }\n };\n }\n\n})();\n\n(function () {\n 'use strict';\n\n angular\n .module('tfc.Form')\n .directive('tfcConfirmInput', tfcConfirmInput);\n\n // @ngInject\n function tfcConfirmInput() {\n return {\n restrict : 'A',\n require : ['ngModel', '^form'],\n link : function ($scope, $el, $attrs, ctrls) {\n var ngModel = ctrls[0],\n form = ctrls[1];\n var name = $attrs.tfcConfirmInput,\n otherNgModel = form[name];\n\n if (!otherNgModel) {\n throw new Error('Cannot find field:' + name);\n }\n\n $scope.$watch(\n function () {\n return ngModel.$dirty && otherNgModel.$isEmpty(otherNgModel.$modelValue);\n },\n function (hasBeenCleared) {\n if (hasBeenCleared) {\n // reset this field when the other field is cleared\n ngModel.$setViewValue('');\n ngModel.$setPristine();\n ngModel.$render();\n }\n }\n );\n\n $scope.$watch(\n function () {\n // don't validate until this field has been touched\n return ngModel.$pristine\n || form[name].$modelValue === ngModel.$modelValue;\n },\n function (valid) {\n ngModel.$setValidity('confirm', valid);\n }\n );\n }\n };\n }\n\n})();\n\n(function () {\n 'use strict';\n\n ToastCtrl.$inject = [\"$scope\", \"Toast\"];\n angular\n .module('tfc.Toast')\n .controller('ToastCtrl', ToastCtrl)\n .directive('tfcToast', tfcToast);\n\n // @ngInject\n function ToastCtrl($scope, Toast) {\n var vm = this;\n $scope.$watchCollection(Toast.list, function (messages) {\n vm.messages = messages;\n });\n vm.dismiss = Toast.dismiss;\n vm.translate = Toast.translate;\n }\n\n // @ngInject\n function tfcToast() {\n return {\n controller : 'ToastCtrl as vm',\n scope : {},\n templateUrl : 'Toast/Toast.tmpl.html'\n };\n }\n\n})();\n\n(function () {\n 'use strict';\n\n angular\n .module('tfc.Toast')\n .provider('Toast', ToastProvider);\n\n // @ngInject\n function ToastProvider() {\n // true is a special value that means to use 'translateFilter' if it exists\n var translator = true;\n // Whether the developer has called ToastProvider.useTranslate.\n // If it's called more than once, it's probably a bug.\n var calledUseTranslate = false;\n var typeDefaults = {\n success : {\n delay : 2000\n },\n info : {\n delay : 5000\n },\n warn : {\n delay : 10000\n },\n error : {\n delay : false // never hide automatically\n }\n };\n\n function checkType(type) {\n if (!typeDefaults.hasOwnProperty(type)) {\n throw new Error('Invalid toast level [' + type + ']');\n }\n }\n\n function checkDelay(delay) {\n if (typeof delay !== 'Boolean' && isNaN(delay)) {\n throw new Error('Invalid delay [' + delay + ']');\n }\n }\n\n /**\n * Sets how or whether to translate toast message texts and titles.\n * @param use How or whether to use a translator. Defaults to using 'translateFilter' if it exists. Can be:\n * false - Don't use any translation mechanism. Will just return the text or title as is.\n * String - The name of a service whose value is a function taking text and data.\n * Function - A custom translation function taking text and data.\n */\n this.useTranslate = function (use) {\n if (calledUseTranslate) {\n console.warn('ToastProvider.useTranslate has already been called with [' + translator + '].',\n 'This is probably a bug.');\n }\n calledUseTranslate = true;\n if (use === false || _.isFunction(use) || _.isString(use)) {\n translator = use;\n } else {\n throw new Error('Illegal useTranslate value');\n }\n };\n\n this.getDefaultDelay = function (type) {\n checkType(type);\n return typeDefaults[type].delay;\n };\n\n this.setDefaultDelay = function (type, delay) {\n checkType(type);\n checkDelay(delay);\n typeDefaults[type].delay = delay;\n return this;\n };\n\n this.$get = [\"$rootScope\", \"$injector\", \"$timeout\", \"$state\", \"$log\", function ($rootScope, $injector, $timeout, $state, $log) {\n var messages = [];\n\n $rootScope.$on('$stateChangeSuccess', dismissIrrelevant);\n\n if (translator === true) {\n // auto-detect translateFilter, or turn it off\n if ($injector.has('translateFilter')) {\n translator = $injector.get('translateFilter');\n } else {\n $log.debug('translateFilter not present -- turning off Toast translations');\n translator = false;\n }\n }\n\n return {\n // Called when the user clicks the X button\n dismiss : dismiss,\n translate : translate,\n list : function () { return messages.slice(); },\n success : withAlertType('success', typeDefaults.success),\n info : withAlertType('info', typeDefaults.info),\n warn : withAlertType('warning', typeDefaults.warn),\n error : withAlertType('danger', typeDefaults.error)\n };\n\n function translate(text, data) {\n var fn;\n if (!translator) {\n return text;\n }\n if (_.isFunction(translator)) {\n fn = translator;\n } else if (_.isString(translator)) {\n if (!$injector.has(translator)) {\n throw new Error('Toast set to use [' + translator + '] for translation, but it does not exist. ' +\n \"If you aren't using translations, you need to call ToastProvider.useTranslate(false).\");\n }\n fn = $injector.get(translator);\n if (!_.isFunction(fn)) {\n throw new Error('Toast useTranslate service [' + translator + '] is not a function');\n }\n } else {\n // This should never happen unless we add a feature and forget to implement it here\n throw new Error('Unsupported useTranslate value [' + translator + ']');\n }\n return fn(text, data);\n }\n\n function withAlertType(alertType, defaults) {\n return function (title, text, config) {\n if (arguments.length === 1) {\n text = title;\n title = null;\n config = null;\n } else if (!_.isString(text)) {\n config = text;\n text = title;\n title = null;\n }\n\n config = _.defaults({}, config, defaults, {\n state : false\n });\n\n if (config.state === true) {\n config.state = $state.current.name;\n }\n\n checkDelay(config.delay);\n\n return postMessage(_.extend(config, {\n alertType : alertType,\n title : title,\n text : text,\n dismissed : false,\n quickFade : false\n }));\n };\n }\n\n function deleteMessage(message) {\n $timeout.cancel(message.$timeout);\n _.pull(messages, message);\n }\n\n function postMessage(message) {\n messages.push(message);\n\n if (message.delay !== false) {\n message.$timeout = $timeout(function () {\n deleteMessage(message);\n }, message.delay);\n }\n var dismissMessage = function () {\n deleteMessage(message);\n };\n return dismissMessage\n }\n\n function dismiss(message) {\n // quickFade makes it fade out quickly when the user dismisses the toast\n // TODO: There's probably a better way\n message.quickFade = true;\n // TODO: This is done asynchronously in the original -- make sure that's unnecessary\n $timeout(function () {\n deleteMessage(message);\n });\n }\n\n function dismissIrrelevant() {\n // slice because `dismiss` will mutate `messages`\n _.each(messages.slice(), function (message) {\n // dismiss every state-bound message whose state we've left\n if (message.state && !isInState(message.state)) {\n dismiss(message);\n }\n });\n }\n\n // returns whether we're in the given state or one of its children\n function isInState(stateName) {\n var state = $state.$current;\n do {\n if (state.self.name === stateName) {\n return true;\n }\n state = state.parent;\n } while (state);\n return false;\n }\n }];\n }\n\n})();\n\n(function () {\n 'use strict';\n\n AppVersion.$inject = [\"$q\"];\n tfcAppVersion.$inject = [\"AppVersion\"];\n angular\n .module('tfc.Nav')\n .factory('AppVersion', AppVersion)\n .directive('tfcAppVersion', tfcAppVersion);\n\n // @ngInject\n function AppVersion($q) {\n\n var appVersion = '';\n var appCopyright = '';\n\n function extractMetadata(response) {\n var version = response.headers('X-Application-Version');\n if (version) {\n appVersion = version;\n }\n var copyright = response.headers('X-Application-Copyright');\n if (copyright) {\n appCopyright = copyright;\n }\n }\n\n return {\n getAppVersion : function () { return appVersion; },\n getAppCopyright : function () { return appCopyright; },\n // response interceptor\n response : function (response) {\n extractMetadata(response);\n return response;\n },\n responseError : function (response) {\n extractMetadata(response);\n return $q.reject(response);\n }\n };\n }\n\n // @ngInject\n function tfcAppVersion(AppVersion) {\n return {\n scope : {},\n templateUrl : 'Nav/AppVersion.tmpl.html',\n link : function ($scope) {\n $scope.getAppVersion = AppVersion.getAppVersion;\n $scope.getAppCopyright = AppVersion.getAppCopyright;\n }\n };\n }\n\n})();\n\n(function () {\n 'use strict';\n\n tfcCompileHtml.$inject = [\"$compile\"];\n angular\n .module('tfc.Nav')\n .directive('tfcCompileHtml', tfcCompileHtml);\n\n // @ngInject\n function tfcCompileHtml($compile) {\n return {\n restrict : 'A',\n link : function ($scope, $el, $attrs) {\n var childScope;\n $scope.$watch($attrs.tfcCompileHtml, function (html) {\n if (childScope) {\n childScope.destroy();\n }\n $el.contents().remove();\n $el.html(html);\n childScope = $scope.$new();\n $compile($el.contents())(childScope);\n });\n }\n };\n }\n \n})();\n(function () {\n 'use strict';\n\n MainNavCtrl.$inject = [\"$injector\", \"$scope\", \"$element\", \"$document\", \"Nav\", \"Auth\"];\n angular\n .module('tfc.Nav')\n .controller('MainNavCtrl', MainNavCtrl)\n .directive('tfcMainNav', tfcMainNav);\n\n // @ngInject\n function MainNavCtrl($injector, $scope, $element, $document, Nav, Auth) {\n var vm = this,\n isExpanded = false,\n mainItems,\n rightItems,\n userItems;\n\n function inject(fnName) {\n return function (item) {\n return $injector.invoke(item[fnName]);\n };\n }\n\n vm.getText = inject('getText');\n vm.onClick = inject('onClick');\n vm.canAccess = inject('canAccess');\n\n vm.isActive = function (item) {\n return _.some([item].concat(item.children || []), inject('isActive'));\n };\n\n vm.isExpanded = function () {\n return isExpanded;\n };\n\n vm.toggle = function () {\n isExpanded = !isExpanded;\n };\n\n vm.appTitle = function () {\n return vm.getText(Nav.appTitle());\n };\n\n vm.appWelcome = function () {\n return vm.getText(Nav.appWelcome());\n };\n\n vm.mainItems = function () {\n return vm.user ? mainItems : [];\n };\n\n vm.rightItems = function () {\n return vm.user ? rightItems : [];\n };\n\n vm.userItems = function () {\n return vm.user ? userItems : [];\n };\n\n $scope.$on('$stateChangeSuccess', function () {\n isExpanded = false;\n });\n\n $document.on('click', function (e) {\n if (!$element[0].contains(e.target)) {\n isExpanded = false;\n $scope.$apply();\n }\n });\n\n $scope.$watch(Nav.mainMenu, function (items) {\n mainItems = items;\n });\n $scope.$watch(Nav.rightMenu, function (items) {\n rightItems = items;\n });\n $scope.$watch(Nav.userMenu, function (items) {\n userItems = items;\n });\n // we don't want to watch getUser because it returns a new one each time,\n // so we'd have to\n $scope.$watch(Auth.isAuthenticated, function () {\n vm.user = Auth.getUser();\n });\n\n $scope.$watch(vm.appTitle, function (title) {\n if (title) {\n document.title = title + ' | True Fit';\n }\n });\n }\n\n // @ngInject\n function tfcMainNav() {\n return {\n restrict : 'E',\n controller : 'MainNavCtrl as vm',\n bindToController : true,\n templateUrl : 'Nav/MainNav.tmpl.html',\n scope : {\n fullWidth : '='\n }\n };\n }\n\n})();\n\n(function () {\n 'use strict';\n\n angular\n .module('tfc.Nav')\n .provider('Nav', NavProvider);\n\n // @ngInject\n function NavProvider() {\n\n var title = { text : '' };\n var welcome = {\n // @ngInject\n getText : [\"TextUtil\", \"Auth\", function (TextUtil, Auth) {\n return TextUtil.translateOr('app.welcome', Auth.getUser(), function (user) {\n return 'Welcome, ' + user.firstName;\n });\n }]\n };\n\n var mainMenuItems = [],\n rightMenuItems = [],\n userMenuItems = [\n {\n text : 'Change Password',\n state : 'passwordReset'\n }\n ];\n\n /**\n * @name NavProvider#addMain\n * Add a nav button that will be left-justified in the navbar.\n *\n * The 'Injectable' type is something that `$injector` understands:\n * @see https://code.angularjs.org/1.4.10/docs/api/auto/service/$injector#annotate\n * Note: The 'Argument names' syntax from the above link is not allowed.\n *\n * The configuration's main methods are:\n * - getText {Injectable} Returns the nav button's text\n * - onClick {Injectable} Function called when the user clicks the nav button\n * - isActive {Injectable} Returns whether the nav button should be highlighted as 'active'\n *\n * The configuration also supports a few short-hand properties, which obviate the need to define\n * the main methods listed above. These short-hand properties are:\n * - text {String} For when the nav button has static text. `getText` is ignored if this is set.\n * - translate {String|Object} For use with angular-translate. This is ignored if `text` is set.\n * `getText` is ignored if this is set. Setting to a string is the same as { key: `translate` }.\n * This defines what's passed to the translate filter. If `translate` is an object, it can have:\n * - key {String|Injectable} Defines the translation key.\n * - values {Object|Injectable} Defines the translation params.\n * @see https://angular-translate.github.io/docs/#/api/pascalprecht.translate.filter:translate\n * - state {String|Object} Defines the ui-router state to navigate to onClick.\n * `onClick` is ignored if this is set. Setting to a string is the same as { name: `state` }.\n * This defines what's passed to `$state.go`. This will create default `onClick` and `isActive` options,\n * which you can still overwrite. If `state` is an object, it can have:\n * - name {String|Injectable} Defines the state to go to.\n * - params {Object|Injectable} Defines the state params.\n * - options {Object|Injectable} Defines the `$state.go` options.\n * @see http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state#methods_go\n *\n * @param config {Object} The item's configuration. See above for details\n * @returns {NavProvider} Returns `this`, so as to be chainable\n */\n this.addMain = function (config) {\n require(_.isPlainObject(config), 'You must supply a config object to NavProvider#addMain');\n mainMenuItems.push(config);\n return this;\n };\n\n /**\n * @name NavProvider#addRight\n * Add a nav button that will be right-justified in the navbar. This has an identical API to NavProvider#addMain\n * @param config {Object} The item's configuration.\n * @returns {NavProvider} Returns `this`, so as to be chainable\n * @see NavProvider#addMain\n */\n this.addRight = function (config) {\n require(_.isPlainObject(config), 'You must supply a config object to NavProvider#addRight');\n rightMenuItems.push(config);\n return this;\n };\n\n this.addUser = function (config) {\n require(_.isPlainObject(config), 'You must supply a config object to NavProvider#addRight');\n userMenuItems.push(config);\n return this;\n };\n\n this.setWelcome = function (config) {\n welcome = config;\n return this;\n };\n\n this.setAppTitle = function (config) {\n title = config;\n return this;\n };\n\n this.removeChangePassword = function() {\n _.remove(userMenuItems, {state: 'passwordReset'});\n return this;\n };\n\n this.$get = [\"$injector\", \"$sce\", function ($injector, $sce) {\n var invoke = $injector.invoke;\n /**\n * Returns whether something is injectable.\n * @see https://code.angularjs.org/1.4.10/docs/api/auto/service/$injector#annotate\n * Note: The 'Argument names' syntax from the above link is not allowed.\n */\n function isInjectable(value) {\n try {\n $injector.annotate(value, /*strictDi=*/true);\n return true;\n } catch (e) {\n return false;\n }\n }\n\n /**\n * Returns a value that can be passed to $injector.invoke. This means\n * if `value` is injectable, `value` is returned. Otherwise, this returns\n * an injectable function that will return `value`.\n */\n function toInjectable(value) {\n return isInjectable(value) ? value : function () {\n return value;\n };\n }\n\n function configureState(config) {\n if (config.state) {\n // support simple `state: 'foo'` syntax\n if (_.isString(config.state)) {\n config.state = {\n name : config.state\n };\n }\n // if the values aren't injectable functions, wrap them in one\n config.state.name = toInjectable(config.state.name);\n config.state.params = toInjectable(config.state.params);\n config.state.options = toInjectable(config.state.options);\n // _.defaults to allow overriding\n _.defaults(config, {\n // @ngInject\n onClick : [\"$state\", function ($state) {\n $state.go(\n invoke(config.state.name),\n invoke(config.state.params),\n invoke(config.state.options)\n );\n }],\n // @ngInject\n isActive : [\"$state\", function ($state) {\n return $state.includes(invoke(config.state.name));\n }],\n // Whether the user can access this item\n // @ngInject\n canAccess : [\"$state\", function ($state) {\n return $state.can(invoke(config.state.name));\n }]\n });\n } else if (!config.onClick && !config.isActive) {\n if (!_.get(config, 'children.length')) {\n console.warn('Nav item configured with no \"state\" property and no children. ' +\n 'Did you forget to add a \"state\" to this nav item?', config);\n } else {\n // With no state defined, make the parent act as the first child the user has access to\n var fromFirstChild = function(keyPath) {\n return function () {\n var firstAccessibleChild = _.find(config.children, function (child) {\n return invoke(child.canAccess);\n });\n var fn = _.get(firstAccessibleChild, keyPath);\n return fn && invoke(fn);\n };\n };\n config.state = {\n name : fromFirstChild('state.name'),\n params : fromFirstChild('state.params'),\n options : fromFirstChild('state.options')\n };\n config.onClick = fromFirstChild('onClick');\n config.isActive = fromFirstChild('isActive');\n config.canAccess = fromFirstChild('canAccess');\n }\n }\n }\n\n function configureText(config) {\n if (_.isString(config.text)) {\n config.getText = function () {\n return config.text;\n };\n } else if (config.translate) {\n // support simple `translate: 'app.welcome'` syntax\n if (_.isString(config.translate)) {\n config.translate = {\n key : config.translate\n };\n }\n config.translate.key = toInjectable(config.translate.key);\n config.translate.values = toInjectable(config.translate.values);\n // @ngInject\n config.getText = function () {\n var translateFilter;\n if (!$injector.has('translateFilter')) {\n throw new Error('Nav: menu item set \"translate\" property without angular-translate present');\n }\n translateFilter = $injector.get('translateFilter');\n return translateFilter(\n invoke(config.translate.key),\n invoke(config.translate.values)\n );\n };\n }\n }\n\n function configureTemplate(config) {\n if (!_.isString(config.template)) {\n return;\n }\n config.template = $sce.trustAsHtml(config.template);\n }\n\n configureText(title);\n configureText(welcome);\n\n // massage config items so they're usable\n mainMenuItems\n .concat(rightMenuItems)\n .concat(userMenuItems)\n .forEach(function (config) {\n configureState(config);\n configureText(config);\n // TODO: implement the UI for child nav items\n config.children = _.map(config.children, function (child) {\n configureState(child);\n configureText(child);\n // only children get the ability to template for now\n configureTemplate(child);\n return child;\n });\n });\n\n return {\n appTitle : appTitle,\n appWelcome : appWelcome,\n mainMenu : mainMenu,\n rightMenu : rightMenu,\n userMenu : userMenu\n };\n\n function appTitle() {\n return title;\n }\n\n function appWelcome() {\n return welcome;\n }\n\n function mainMenu() {\n return mainMenuItems\n }\n\n function rightMenu() {\n return rightMenuItems;\n }\n\n function userMenu() {\n return userMenuItems;\n }\n }];\n }\n\n function require(x, msg) {\n if (!x) {\n throw new Error(msg);\n }\n }\n\n})();\n\n(function () {\n 'use strict';\n\n angular\n .module('tfc.Nav')\n .directive('tfcPage', tfcPage);\n\n // @ngInject\n function tfcPage() {\n return {\n templateUrl : 'Nav/Page.tmpl.html',\n scope : {\n fullWidth : '='\n }\n };\n }\n\n})();\n\n(function () {\n 'use strict';\n\n TextUtil.$inject = [\"$injector\"];\n angular\n .module('tfc.Nav')\n .factory('TextUtil', TextUtil);\n\n // @ngInject\n function TextUtil($injector) {\n\n var translateFilter;\n if ($injector.has('translateFilter')) {\n translateFilter = $injector.get('translateFilter');\n }\n\n return {\n translateOr : translateOr\n };\n\n /**\n * @name TextUtil#translateOr\n *\n * Uses angular-translate to translate the `translationId` or calls the `fallbackFn`\n * with `values`.\n *\n * @param translationId\n * @param [values]\n * @param fallbackFn\n * @returns String The result of the translation, or the return value of `fallbackFn`\n * if angular-translate is not present\n */\n function translateOr(translationId, values, fallbackFn) {\n if (arguments.length < 2) {\n throw new Error('translateOr requires at least a translationId and fallback function,' +\n 'with optional values in between.');\n }\n if (arguments.length === 2) {\n fallbackFn = values;\n values = undefined;\n }\n if (translateFilter) {\n return translateFilter(translationId, values);\n } else {\n return fallbackFn(values);\n }\n }\n }\n\n})();\n\n(function () {\n 'use strict';\n\n ForgotPasswordCtrl.$inject = [\"$stateParams\", \"Auth\"];\n angular\n .module('tfc.sso')\n .controller('ForgotPasswordCtrl', ForgotPasswordCtrl);\n\n // @ngInject\n function ForgotPasswordCtrl($stateParams, Auth) {\n var vm = this;\n\n vm.sent = false;\n vm.expired = $stateParams.expired;\n vm.email = $stateParams.email;\n\n vm.submit = function () {\n Auth.forgotPassword(vm.email).then(function () {\n vm.sent = true;\n });\n };\n }\n\n})();\n\n(function () {\n 'use strict';\n\n LoginCtrl.$inject = [\"Auth\"];\n angular\n .module('tfc.sso')\n .controller('LoginCtrl', LoginCtrl);\n\n // @ngInject\n function LoginCtrl(Auth) {\n var vm = this;\n vm.usingActiveDirectory = Auth.usingActiveDirectory;\n\n vm.user = {};\n\n vm.login = function () {\n Auth.login(vm.user);\n };\n }\n\n})();\n\n(function () {\n 'use strict';\n\n PasswordResetCtrl.$inject = [\"$state\", \"Auth\", \"Toast\"];\n angular\n .module('tfc.sso')\n .controller('PasswordResetCtrl', PasswordResetCtrl);\n\n // @ngInject\n function PasswordResetCtrl($state, Auth, Toast) {\n var vm = this;\n\n var user = Auth.getUser();\n\n vm.isAuthenticated = function () {\n return !!user;\n };\n\n vm.user = {\n user : $state.params.email || (user && user.email)\n };\n\n vm.error = null;\n\n vm.save = function () {\n vm.error = null;\n Auth.resetPassword(vm.user).then(function () {\n Toast.success('Password successfully changed');\n $state.go('login');\n });\n };\n }\n\n})();\n\n(function () {\n 'use strict';\n\n PasswordResetFormCtrl.$inject = [\"Auth\"];\n angular\n .module('tfc.sso')\n .controller('PasswordResetFormCtrl', PasswordResetFormCtrl)\n .directive('tfcPasswordResetForm', tfcPasswordResetForm);\n\n // @ngInject\n function PasswordResetFormCtrl(Auth) {\n var vm = this;\n\n vm.isAuthenticated = function () {\n return !!Auth.getUser();\n };\n }\n\n // @ngInject\n function tfcPasswordResetForm() {\n return {\n bindToController : true,\n controller : 'PasswordResetFormCtrl as vm',\n templateUrl : 'sso/PasswordResetForm.tmpl.html',\n scope : {\n user : '=',\n onSubmit : '&'\n }\n };\n }\n\n})();\n\n(function () {\n 'use strict';\n\n RecoverPasswordCtrl.$inject = [\"$state\", \"$stateParams\", \"email\", \"Auth\", \"Toast\", \"TextUtil\"];\n angular\n .module('tfc.sso')\n .controller('RecoverPasswordCtrl', RecoverPasswordCtrl);\n\n // @ngInject\n function RecoverPasswordCtrl($state, $stateParams, email, Auth, Toast, TextUtil) {\n var vm = this;\n\n vm.email = email;\n\n vm.submit = function () {\n Auth.recoverPassword($stateParams.t, vm.user.newPass).then(function () {\n Toast.success(TextUtil.translateOr('auth.password.reset.success', function () {\n return 'Your password has been reset.';\n }));\n $state.go('login');\n });\n };\n }\n\n})();\n\n(function () {\n 'use strict';\n\n // tfc.sso's run block calls Auth.validate() (see sso.module.js).\n // This is a separate module so tfc.sso's run doesn't have to be mocked for every test\n config.$inject = [\"$httpProvider\", \"AuthProvider\"];\n angular\n .module('tfc.sso.Auth')\n .provider('Auth', Auth)\n .config(config);\n\n // @ngInject\n function config($httpProvider, AuthProvider) {\n\n\n }\n\n // @ngInject\n function Auth() {\n var basePath = 'ui';\n var paths = {\n login : '/auth/login',\n logout : '/auth/logout',\n validate : '/auth/validate',\n resetPassword: '/auth/password/reset',\n forgotPassword: '/auth/password/forgot',\n recoverPassword: '/auth/password/recover',\n getEmailByPasswordToken : '/auth/password/token'\n };\n\n var _usingActiveDirectory = false;\n\n this.setBasePath = function (bp) {\n basePath = bp;\n };\n\n this.setPath = function (name, path) {\n paths[name] = path;\n };\n\n this.usingActiveDirectory = function () {\n _usingActiveDirectory = true\n };\n\n this.$get = [\"$rootScope\", \"$http\", \"$log\", \"$q\", \"$state\", \"$urlRouter\", \"CookieJar\", \"Toast\", function ($rootScope, $http, $log, $q, $state, $urlRouter, CookieJar, Toast) {\n var _authenticatedUser;\n var _isValid,\n _hasValidated;\n\n function initVars() {\n _authenticatedUser = null;\n _isValid = false;\n _hasValidated = false;\n }\n\n initVars();\n\n return {\n getUser : getUser,\n login : login,\n logout : logout,\n validate : validate,\n resetPassword : resetPassword,\n forgotPassword : forgotPassword,\n recoverPassword : recoverPassword,\n getEmailByPasswordToken : getEmailByPasswordToken,\n isAuthenticated : isAuthenticated,\n hasValidated : function () { return _hasValidated; },\n can : can,\n usingActiveDirectory : function () { return _usingActiveDirectory}\n };\n\n function getUser() {\n if (isAuthenticated()) {\n return _authenticatedUser;\n } else {\n return null;\n }\n }\n\n function login(credentials) {\n return $http.post(basePath + paths.login, credentials).then(function (response) {\n _authenticatedUser = response.data;\n _isValid = true;\n var expiration = getUser().passwordExpiration;\n var ttlMs = expiration - Date.now();\n var ttlDays = Math.floor(ttlMs / 1000 / 60 / 60 / 24);\n var when;\n // Give them 7 days of warning before it expires\n if (ttlDays <= 7) {\n when = new Date(expiration).toLocaleDateString(); // 'mm/dd/yyyy'\n Toast.warn('Your password will expire on ' + when + '. Please reset it');\n }\n if ($state.params.dest) {\n document.location.hash = $state.params.dest;\n $urlRouter.sync();\n } else {\n $rootScope.$broadcast('auth.login');\n }\n }, handleError);\n }\n\n function logout() {\n return $http.post(basePath + paths.logout).then(function () {\n initVars();\n $rootScope.$broadcast('auth.logout');\n });\n }\n\n function validate() {\n return $http.get(basePath + paths.validate).then(function (response) {\n _authenticatedUser = response.data;\n _isValid = true;\n }, function(response) {\n _isValid = false;\n if (response.status === 403) {\n // They're already logged in from somewhere else, but they can't access this app.\n Toast.error('You do not have permission to use this application');\n } else if (response.status === 401) {\n _authenticatedUser = null;\n } else if (response.status >= 500) {\n Toast.error('Something is wrong with the server. Please contact operations.');\n } else {\n Toast.error('Unexpected error. (code = ' + response.status + ')');\n }\n }).finally(function () {\n _hasValidated = true;\n });\n }\n\n function resetPassword(change) {\n change = _.pick(change, ['user', 'pass', 'newPass']);\n return $http.post(basePath + paths.resetPassword, change)\n .then(null, handleError);\n }\n\n function forgotPassword(email) {\n return $http.post(basePath + paths.forgotPassword, { email : email });\n }\n\n function recoverPassword(token, newPassword) {\n return $http.post(basePath + paths.recoverPassword, {\n token : token,\n newPassword : newPassword\n }).then(null, handleError);\n }\n\n function getEmailByPasswordToken(token) {\n return $http.get(basePath + paths.getEmailByPasswordToken, {\n params : { token : token }\n }).then(_.property('data'));\n }\n\n function handleError(response) {\n if (response.status === 400) {\n switch (_.get(response.data, '_type')) {\n case 'PasswordInsecure':\n Toast.error(response.data.message, { state : true });\n break;\n case 'PasswordUnchanged':\n Toast.error('You cannot use your current or ' +\n response.data.recentPasswordCount + ' most recent passwords.', { state : true });\n break;\n default:\n Toast.error('Oops! Something went wrong.');\n break;\n }\n } else if (response.status === 401) {\n switch (_.get(response.data, '_type')) {\n case 'TooManyFailedLoginAttempts':\n Toast.error(\"You've failed to login too many times. Please try again later.\");\n break;\n case 'MustResetPassword':\n var user = response.data.user;\n if (user.passwordExpiration < Date.now()) {\n Toast.warn('Your password has expired. Please change it.');\n }\n $state.go('passwordResetPublic', { email : user.email });\n break;\n default:\n Toast.warn('Invalid email or password', { state : true });\n }\n } else if (response.status >= 500) {\n // TODO: move to an interceptor\n Toast.error('Unexpected error', { state : true });\n }\n return $q.reject(response);\n }\n\n function isAuthenticated() {\n return _isValid && !!_authenticatedUser;\n }\n\n function can(permission) {\n var user = getUser();\n return !!user && -1 !== user.privileges.indexOf(permission);\n }\n }];\n }\n\n})();\n\n(function () {\n 'use strict';\n\n CookieJar.$inject = [\"$log\"];\n angular\n .module('tfc.sso.Auth')\n .factory('CookieJar', CookieJar);\n\n // @ngInject\n function CookieJar($log) {\n\n return {\n /**\n * @name CookieJar#get\n * @param name {string} The name of the cookie\n * @returns {string} The value of the cookie, or undefined if it does not exist.\n */\n get : get,\n /**\n * @name CookieJar#set\n * @param {object} data The cookie configuration, which has the following fields:\n * - {string} name The name of the cookie.\n * - {string} value The value of the cookie.\n * - {string} [domain] The domain for the cookie. Setting to true will use the current domain's parent domain.\n * Omitting the domain sets a session cookie.\n * - {string} [path] The path to which this cookie applies. Defaults to '/'.\n * - {number} [maxAge] Integer representing # seconds for the cookie to last. Anything <= 0 will delete the cookie.\n */\n set : set,\n /**\n * @name CookieJar#remove\n * @param {object|string} data The name of the cookie, or an object containing:\n * - {string} name The name of the cookie.\n * - {string} [domain] The domain of the cookie. Defaults to the current domain's parent domain.\n * - {string} [path] The path of the cookie to delete. Defaults to '/'.\n */\n remove : remove\n };\n\n function isNonEmptyString(x) {\n return _.isString(x) && x.length > 0;\n }\n\n function defaultDomain() {\n var domain = location.hostname;\n if (domain === 'localhost') {\n $log.warn(\"Cookies don't really work on localhost. Using a session cookie\");\n return;\n }\n var parts = domain.split('.');\n if (parts.length > 2) {\n return parts.slice(1).join('.');\n } else {\n return domain;\n }\n }\n\n function get(name) {\n var cookiePairs = document.cookie.split('; ');\n var value;\n _.each(cookiePairs, function (pair) {\n var split = pair.split('=');\n if (split[0] === name) {\n value = split[1];\n return false;\n }\n });\n return value;\n }\n\n function set(data) {\n var cookie, expires;\n if (_.isPlainObject(data) && _.isString(data.name) && _.isString(data.value)) {\n\n cookie = data.name + '=' + data.value;\n\n if (data.domain === true) {\n data.domain = defaultDomain();\n }\n\n if (isNonEmptyString(data.domain)) {\n cookie += ';domain=' + data.domain;\n }\n\n data.path = isNonEmptyString(data.path) ? data.path : '/';\n cookie += ';path=' + data.path;\n\n if (!isNaN(data.maxAge)) {\n if (data.maxAge <= 0) {\n data.maxAge = expires = 0;\n } else {\n expires = new Date().getTime() + data.maxAge * 1000;\n }\n cookie += ';max-age=' + data.maxAge;\n cookie += ';expires=' + new Date(expires).toUTCString();\n }\n\n document.cookie = cookie;\n }\n }\n\n function _remove(data) {\n set({\n name: data.name,\n value: '',\n domain: data.domain,\n path: data.path,\n maxAge: 0\n });\n }\n\n function remove(data) {\n if (_.isString(data)) {\n data = {\n name : data,\n domain : true\n };\n }\n\n _remove(data);\n\n if (get(data.name) != null && data.domain) {\n $log.debug('Cookie [' + data.name + '] still present after remove. ' +\n 'Trying again as a session cookie');\n delete data.domain;\n _remove(data);\n }\n }\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.sso',\n [\n 'tfc.sso.Auth',\n 'tfc.sso.tmpls',\n 'tfc.Toast',\n 'tfc.Nav',\n 'tfc.Form'\n ])\n .config(config)\n .run(run);\n\n // @ngInject\n function config($stateProvider, NavProvider, $provide) {\n\n NavProvider.addRight({\n state : 'logout',\n // @ngInject\n getText : function (TextUtil) {\n return TextUtil.translateOr('auth.logout', function () {\n return 'Log Out';\n });\n }\n });\n\n $stateProvider\n .state('login', {\n parent: 'page',\n data : {\n auth : { isPublic : true }\n },\n url : '/login?dest',\n templateUrl : 'sso/Login.tmpl.html',\n controller : 'LoginCtrl as vm'\n })\n .state('logout', {\n url : '/logout',\n template : '',\n resolve : {\n logout : function ($state, Auth) {\n return Auth.logout().finally(function () {\n $state.go('login');\n });\n }\n }\n })\n .state('passwordReset', {\n parent : 'page',\n url : '/password/reset',\n templateUrl : 'sso/PasswordReset.tmpl.html',\n controller : 'PasswordResetCtrl as vm'\n })\n .state('passwordResetPublic', {\n parent : 'page',\n url : '/password/resetpub?email',\n data : {\n auth : { isPublic : true }\n },\n templateUrl : 'sso/PasswordResetPublic.tmpl.html',\n controller : 'PasswordResetCtrl as vm'\n })\n .state('forgotPassword', {\n parent : 'page',\n url : '/password/forgot?email&{expired:bool}',\n data : {\n auth : { isPublic : true }\n },\n templateUrl : 'sso/ForgotPassword.tmpl.html',\n controller : 'ForgotPasswordCtrl as vm'\n })\n .state('recoverPassword', {\n parent : 'page',\n // IMPORTANT: This MUST match the url in ForgotPasswordEmail.scala\n url : '/password/recover?t',\n data : {\n auth : { isPublic : true }\n },\n resolve : {\n email : function ($state, $stateParams, Auth) {\n return Auth.getEmailByPasswordToken($stateParams.t).then(null, function () {\n $state.go('forgotPassword', { expired : true });\n });\n }\n },\n templateUrl : 'sso/RecoverPassword.tmpl.html',\n controller : 'RecoverPasswordCtrl as vm'\n })\n ;\n\n $provide.decorator('$state', function ($delegate, $injector) {\n /**\n * @name $state#can\n * Add this function to the $state service so it can be used in the application.\n *\n * To add access to control to a state, add a data.auth property to the state config:\n * $stateProvider.state('foo', {\n * data : {\n * auth : {\n * // privilege required to view the foo state\n * privilege : 'somePrivilege',\n * // redirect to 'some.state' if the user tries to go here w/o the required privilege. defaults to dashboard\n * defaultTo : 'some.state'\n * }\n * },\n * ...\n * @param stateName String The state to check\n * @returns Boolean If the user can access this state.\n */\n $delegate.can = function (stateName) {\n // Avoid circular dependency\n var Auth = $injector.get('Auth');\n var state = $delegate.get(stateName);\n var privilege = _.get(state, 'data.auth.privilege');\n return !privilege || Auth.can(privilege);\n };\n\n return $delegate;\n });\n }\n\n // @ngInject\n function run($rootScope, $state, Auth, $log, Toast, TextUtil) {\n // Make sure the current JWT is still valid\n var validatePromise = Auth.validate();\n\n $rootScope.$on('$stateChangeStart', function (event, toState, toParams) {\n if (!Auth.hasValidated()) {\n event.preventDefault();\n if (!validatePromise) {\n // Re-validate after logging out\n validatePromise = Auth.validate();\n }\n validatePromise.finally(function () {\n // This prevents an infinite loop after logging out\n validatePromise = null;\n $state.go(toState.name, toParams);\n });\n } else {\n var isAuthenticated = Auth.isAuthenticated();\n\n // If they hit the login page but are already authenticated, just go to the app's default state\n if (isAuthenticated && toState.name === 'login') {\n event.preventDefault();\n $rootScope.$broadcast('auth.login');\n } else if (_.get(toState, 'data.auth.isPublic')) {\n return;\n }\n\n if (!isAuthenticated) {\n $log.debug('Not authenticated. Redirecting to Login');\n event.preventDefault();\n $state.go('login', { dest : $state.href(toState.name, toParams) });\n } else if (!$state.can(toState.name)) {\n event.preventDefault();\n var defaultTo = _.get(toState, 'data.auth.defaultTo');\n Toast.warn(TextUtil.translateOr('auth.error.lackPrivilege', function () {\n return 'Sorry, you do not have permission to do that.';\n }));\n if (defaultTo) {\n $state.go(defaultTo);\n }\n }\n }\n });\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.sso.Auth',\n [\n 'ui.router',\n 'tfc.Toast'\n ]);\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.Form')\n .directive('tfcAutofocus', tfcAutofocus);\n\n // @ngInject\n function tfcAutofocus($timeout) {\n return {\n restrict : 'A',\n link : function ($scope, $el, $attrs) {\n var autoFocus = $attrs.tfcAutofocus || 'true';\n $timeout(function () {\n if ($scope.$eval(autoFocus)) {\n $el[0].focus();\n }\n });\n }\n };\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.Form')\n .directive('tfcConfirmInput', tfcConfirmInput);\n\n // @ngInject\n function tfcConfirmInput() {\n return {\n restrict : 'A',\n require : ['ngModel', '^form'],\n link : function ($scope, $el, $attrs, ctrls) {\n var ngModel = ctrls[0],\n form = ctrls[1];\n var name = $attrs.tfcConfirmInput,\n otherNgModel = form[name];\n\n if (!otherNgModel) {\n throw new Error('Cannot find field:' + name);\n }\n\n $scope.$watch(\n function () {\n return ngModel.$dirty && otherNgModel.$isEmpty(otherNgModel.$modelValue);\n },\n function (hasBeenCleared) {\n if (hasBeenCleared) {\n // reset this field when the other field is cleared\n ngModel.$setViewValue('');\n ngModel.$setPristine();\n ngModel.$render();\n }\n }\n );\n\n $scope.$watch(\n function () {\n // don't validate until this field has been touched\n return ngModel.$pristine\n || form[name].$modelValue === ngModel.$modelValue;\n },\n function (valid) {\n ngModel.$setValidity('confirm', valid);\n }\n );\n }\n };\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.Toast')\n .controller('ToastCtrl', ToastCtrl)\n .directive('tfcToast', tfcToast);\n\n // @ngInject\n function ToastCtrl($scope, Toast) {\n var vm = this;\n $scope.$watchCollection(Toast.list, function (messages) {\n vm.messages = messages;\n });\n vm.dismiss = Toast.dismiss;\n vm.translate = Toast.translate;\n }\n\n // @ngInject\n function tfcToast() {\n return {\n controller : 'ToastCtrl as vm',\n scope : {},\n templateUrl : 'Toast/Toast.tmpl.html'\n };\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.Toast')\n .provider('Toast', ToastProvider);\n\n // @ngInject\n function ToastProvider() {\n // true is a special value that means to use 'translateFilter' if it exists\n var translator = true;\n // Whether the developer has called ToastProvider.useTranslate.\n // If it's called more than once, it's probably a bug.\n var calledUseTranslate = false;\n var typeDefaults = {\n success : {\n delay : 2000\n },\n info : {\n delay : 5000\n },\n warn : {\n delay : 10000\n },\n error : {\n delay : false // never hide automatically\n }\n };\n\n function checkType(type) {\n if (!typeDefaults.hasOwnProperty(type)) {\n throw new Error('Invalid toast level [' + type + ']');\n }\n }\n\n function checkDelay(delay) {\n if (typeof delay !== 'Boolean' && isNaN(delay)) {\n throw new Error('Invalid delay [' + delay + ']');\n }\n }\n\n /**\n * Sets how or whether to translate toast message texts and titles.\n * @param use How or whether to use a translator. Defaults to using 'translateFilter' if it exists. Can be:\n * false - Don't use any translation mechanism. Will just return the text or title as is.\n * String - The name of a service whose value is a function taking text and data.\n * Function - A custom translation function taking text and data.\n */\n this.useTranslate = function (use) {\n if (calledUseTranslate) {\n console.warn('ToastProvider.useTranslate has already been called with [' + translator + '].',\n 'This is probably a bug.');\n }\n calledUseTranslate = true;\n if (use === false || _.isFunction(use) || _.isString(use)) {\n translator = use;\n } else {\n throw new Error('Illegal useTranslate value');\n }\n };\n\n this.getDefaultDelay = function (type) {\n checkType(type);\n return typeDefaults[type].delay;\n };\n\n this.setDefaultDelay = function (type, delay) {\n checkType(type);\n checkDelay(delay);\n typeDefaults[type].delay = delay;\n return this;\n };\n\n this.$get = function ($rootScope, $injector, $timeout, $state, $log) {\n var messages = [];\n\n $rootScope.$on('$stateChangeSuccess', dismissIrrelevant);\n\n if (translator === true) {\n // auto-detect translateFilter, or turn it off\n if ($injector.has('translateFilter')) {\n translator = $injector.get('translateFilter');\n } else {\n $log.debug('translateFilter not present -- turning off Toast translations');\n translator = false;\n }\n }\n\n return {\n // Called when the user clicks the X button\n dismiss : dismiss,\n translate : translate,\n list : function () { return messages.slice(); },\n success : withAlertType('success', typeDefaults.success),\n info : withAlertType('info', typeDefaults.info),\n warn : withAlertType('warning', typeDefaults.warn),\n error : withAlertType('danger', typeDefaults.error)\n };\n\n function translate(text, data) {\n var fn;\n if (!translator) {\n return text;\n }\n if (_.isFunction(translator)) {\n fn = translator;\n } else if (_.isString(translator)) {\n if (!$injector.has(translator)) {\n throw new Error('Toast set to use [' + translator + '] for translation, but it does not exist. ' +\n \"If you aren't using translations, you need to call ToastProvider.useTranslate(false).\");\n }\n fn = $injector.get(translator);\n if (!_.isFunction(fn)) {\n throw new Error('Toast useTranslate service [' + translator + '] is not a function');\n }\n } else {\n // This should never happen unless we add a feature and forget to implement it here\n throw new Error('Unsupported useTranslate value [' + translator + ']');\n }\n return fn(text, data);\n }\n\n function withAlertType(alertType, defaults) {\n return function (title, text, config) {\n if (arguments.length === 1) {\n text = title;\n title = null;\n config = null;\n } else if (!_.isString(text)) {\n config = text;\n text = title;\n title = null;\n }\n\n config = _.defaults({}, config, defaults, {\n state : false\n });\n\n if (config.state === true) {\n config.state = $state.current.name;\n }\n\n checkDelay(config.delay);\n\n return postMessage(_.extend(config, {\n alertType : alertType,\n title : title,\n text : text,\n dismissed : false,\n quickFade : false\n }));\n };\n }\n\n function deleteMessage(message) {\n $timeout.cancel(message.$timeout);\n _.pull(messages, message);\n }\n\n function postMessage(message) {\n messages.push(message);\n\n if (message.delay !== false) {\n message.$timeout = $timeout(function () {\n deleteMessage(message);\n }, message.delay);\n }\n var dismissMessage = function () {\n deleteMessage(message);\n };\n return dismissMessage\n }\n\n function dismiss(message) {\n // quickFade makes it fade out quickly when the user dismisses the toast\n // TODO: There's probably a better way\n message.quickFade = true;\n // TODO: This is done asynchronously in the original -- make sure that's unnecessary\n $timeout(function () {\n deleteMessage(message);\n });\n }\n\n function dismissIrrelevant() {\n // slice because `dismiss` will mutate `messages`\n _.each(messages.slice(), function (message) {\n // dismiss every state-bound message whose state we've left\n if (message.state && !isInState(message.state)) {\n dismiss(message);\n }\n });\n }\n\n // returns whether we're in the given state or one of its children\n function isInState(stateName) {\n var state = $state.$current;\n do {\n if (state.self.name === stateName) {\n return true;\n }\n state = state.parent;\n } while (state);\n return false;\n }\n };\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.Nav')\n .factory('AppVersion', AppVersion)\n .directive('tfcAppVersion', tfcAppVersion);\n\n // @ngInject\n function AppVersion($q) {\n\n var appVersion = '';\n var appCopyright = '';\n\n function extractMetadata(response) {\n var version = response.headers('X-Application-Version');\n if (version) {\n appVersion = version;\n }\n var copyright = response.headers('X-Application-Copyright');\n if (copyright) {\n appCopyright = copyright;\n }\n }\n\n return {\n getAppVersion : function () { return appVersion; },\n getAppCopyright : function () { return appCopyright; },\n // response interceptor\n response : function (response) {\n extractMetadata(response);\n return response;\n },\n responseError : function (response) {\n extractMetadata(response);\n return $q.reject(response);\n }\n };\n }\n\n // @ngInject\n function tfcAppVersion(AppVersion) {\n return {\n scope : {},\n templateUrl : 'Nav/AppVersion.tmpl.html',\n link : function ($scope) {\n $scope.getAppVersion = AppVersion.getAppVersion;\n $scope.getAppCopyright = AppVersion.getAppCopyright;\n }\n };\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.Nav')\n .directive('tfcCompileHtml', tfcCompileHtml);\n\n // @ngInject\n function tfcCompileHtml($compile) {\n return {\n restrict : 'A',\n link : function ($scope, $el, $attrs) {\n var childScope;\n $scope.$watch($attrs.tfcCompileHtml, function (html) {\n if (childScope) {\n childScope.destroy();\n }\n $el.contents().remove();\n $el.html(html);\n childScope = $scope.$new();\n $compile($el.contents())(childScope);\n });\n }\n };\n }\n \n})();","(function () {\n 'use strict';\n\n angular\n .module('tfc.Nav')\n .controller('MainNavCtrl', MainNavCtrl)\n .directive('tfcMainNav', tfcMainNav);\n\n // @ngInject\n function MainNavCtrl($injector, $scope, $element, $document, Nav, Auth) {\n var vm = this,\n isExpanded = false,\n mainItems,\n rightItems,\n userItems;\n\n function inject(fnName) {\n return function (item) {\n return $injector.invoke(item[fnName]);\n };\n }\n\n vm.getText = inject('getText');\n vm.onClick = inject('onClick');\n vm.canAccess = inject('canAccess');\n\n vm.isActive = function (item) {\n return _.some([item].concat(item.children || []), inject('isActive'));\n };\n\n vm.isExpanded = function () {\n return isExpanded;\n };\n\n vm.toggle = function () {\n isExpanded = !isExpanded;\n };\n\n vm.appTitle = function () {\n return vm.getText(Nav.appTitle());\n };\n\n vm.appWelcome = function () {\n return vm.getText(Nav.appWelcome());\n };\n\n vm.mainItems = function () {\n return vm.user ? mainItems : [];\n };\n\n vm.rightItems = function () {\n return vm.user ? rightItems : [];\n };\n\n vm.userItems = function () {\n return vm.user ? userItems : [];\n };\n\n $scope.$on('$stateChangeSuccess', function () {\n isExpanded = false;\n });\n\n $document.on('click', function (e) {\n if (!$element[0].contains(e.target)) {\n isExpanded = false;\n $scope.$apply();\n }\n });\n\n $scope.$watch(Nav.mainMenu, function (items) {\n mainItems = items;\n });\n $scope.$watch(Nav.rightMenu, function (items) {\n rightItems = items;\n });\n $scope.$watch(Nav.userMenu, function (items) {\n userItems = items;\n });\n // we don't want to watch getUser because it returns a new one each time,\n // so we'd have to\n $scope.$watch(Auth.isAuthenticated, function () {\n vm.user = Auth.getUser();\n });\n\n $scope.$watch(vm.appTitle, function (title) {\n if (title) {\n document.title = title + ' | True Fit';\n }\n });\n }\n\n // @ngInject\n function tfcMainNav() {\n return {\n restrict : 'E',\n controller : 'MainNavCtrl as vm',\n bindToController : true,\n templateUrl : 'Nav/MainNav.tmpl.html',\n scope : {\n fullWidth : '='\n }\n };\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.Nav')\n .provider('Nav', NavProvider);\n\n // @ngInject\n function NavProvider() {\n\n var title = { text : '' };\n var welcome = {\n // @ngInject\n getText : function (TextUtil, Auth) {\n return TextUtil.translateOr('app.welcome', Auth.getUser(), function (user) {\n return 'Welcome, ' + user.firstName;\n });\n }\n };\n\n var mainMenuItems = [],\n rightMenuItems = [],\n userMenuItems = [\n {\n text : 'Change Password',\n state : 'passwordReset'\n }\n ];\n\n /**\n * @name NavProvider#addMain\n * Add a nav button that will be left-justified in the navbar.\n *\n * The 'Injectable' type is something that `$injector` understands:\n * @see https://code.angularjs.org/1.4.10/docs/api/auto/service/$injector#annotate\n * Note: The 'Argument names' syntax from the above link is not allowed.\n *\n * The configuration's main methods are:\n * - getText {Injectable} Returns the nav button's text\n * - onClick {Injectable} Function called when the user clicks the nav button\n * - isActive {Injectable} Returns whether the nav button should be highlighted as 'active'\n *\n * The configuration also supports a few short-hand properties, which obviate the need to define\n * the main methods listed above. These short-hand properties are:\n * - text {String} For when the nav button has static text. `getText` is ignored if this is set.\n * - translate {String|Object} For use with angular-translate. This is ignored if `text` is set.\n * `getText` is ignored if this is set. Setting to a string is the same as { key: `translate` }.\n * This defines what's passed to the translate filter. If `translate` is an object, it can have:\n * - key {String|Injectable} Defines the translation key.\n * - values {Object|Injectable} Defines the translation params.\n * @see https://angular-translate.github.io/docs/#/api/pascalprecht.translate.filter:translate\n * - state {String|Object} Defines the ui-router state to navigate to onClick.\n * `onClick` is ignored if this is set. Setting to a string is the same as { name: `state` }.\n * This defines what's passed to `$state.go`. This will create default `onClick` and `isActive` options,\n * which you can still overwrite. If `state` is an object, it can have:\n * - name {String|Injectable} Defines the state to go to.\n * - params {Object|Injectable} Defines the state params.\n * - options {Object|Injectable} Defines the `$state.go` options.\n * @see http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state#methods_go\n *\n * @param config {Object} The item's configuration. See above for details\n * @returns {NavProvider} Returns `this`, so as to be chainable\n */\n this.addMain = function (config) {\n require(_.isPlainObject(config), 'You must supply a config object to NavProvider#addMain');\n mainMenuItems.push(config);\n return this;\n };\n\n /**\n * @name NavProvider#addRight\n * Add a nav button that will be right-justified in the navbar. This has an identical API to NavProvider#addMain\n * @param config {Object} The item's configuration.\n * @returns {NavProvider} Returns `this`, so as to be chainable\n * @see NavProvider#addMain\n */\n this.addRight = function (config) {\n require(_.isPlainObject(config), 'You must supply a config object to NavProvider#addRight');\n rightMenuItems.push(config);\n return this;\n };\n\n this.addUser = function (config) {\n require(_.isPlainObject(config), 'You must supply a config object to NavProvider#addRight');\n userMenuItems.push(config);\n return this;\n };\n\n this.setWelcome = function (config) {\n welcome = config;\n return this;\n };\n\n this.setAppTitle = function (config) {\n title = config;\n return this;\n };\n\n this.removeChangePassword = function() {\n _.remove(userMenuItems, {state: 'passwordReset'});\n return this;\n };\n\n this.$get = function ($injector, $sce) {\n var invoke = $injector.invoke;\n /**\n * Returns whether something is injectable.\n * @see https://code.angularjs.org/1.4.10/docs/api/auto/service/$injector#annotate\n * Note: The 'Argument names' syntax from the above link is not allowed.\n */\n function isInjectable(value) {\n try {\n $injector.annotate(value, /*strictDi=*/true);\n return true;\n } catch (e) {\n return false;\n }\n }\n\n /**\n * Returns a value that can be passed to $injector.invoke. This means\n * if `value` is injectable, `value` is returned. Otherwise, this returns\n * an injectable function that will return `value`.\n */\n function toInjectable(value) {\n return isInjectable(value) ? value : function () {\n return value;\n };\n }\n\n function configureState(config) {\n if (config.state) {\n // support simple `state: 'foo'` syntax\n if (_.isString(config.state)) {\n config.state = {\n name : config.state\n };\n }\n // if the values aren't injectable functions, wrap them in one\n config.state.name = toInjectable(config.state.name);\n config.state.params = toInjectable(config.state.params);\n config.state.options = toInjectable(config.state.options);\n // _.defaults to allow overriding\n _.defaults(config, {\n // @ngInject\n onClick : function ($state) {\n $state.go(\n invoke(config.state.name),\n invoke(config.state.params),\n invoke(config.state.options)\n );\n },\n // @ngInject\n isActive : function ($state) {\n return $state.includes(invoke(config.state.name));\n },\n // Whether the user can access this item\n // @ngInject\n canAccess : function ($state) {\n return $state.can(invoke(config.state.name));\n }\n });\n } else if (!config.onClick && !config.isActive) {\n if (!_.get(config, 'children.length')) {\n console.warn('Nav item configured with no \"state\" property and no children. ' +\n 'Did you forget to add a \"state\" to this nav item?', config);\n } else {\n // With no state defined, make the parent act as the first child the user has access to\n var fromFirstChild = function(keyPath) {\n return function () {\n var firstAccessibleChild = _.find(config.children, function (child) {\n return invoke(child.canAccess);\n });\n var fn = _.get(firstAccessibleChild, keyPath);\n return fn && invoke(fn);\n };\n };\n config.state = {\n name : fromFirstChild('state.name'),\n params : fromFirstChild('state.params'),\n options : fromFirstChild('state.options')\n };\n config.onClick = fromFirstChild('onClick');\n config.isActive = fromFirstChild('isActive');\n config.canAccess = fromFirstChild('canAccess');\n }\n }\n }\n\n function configureText(config) {\n if (_.isString(config.text)) {\n config.getText = function () {\n return config.text;\n };\n } else if (config.translate) {\n // support simple `translate: 'app.welcome'` syntax\n if (_.isString(config.translate)) {\n config.translate = {\n key : config.translate\n };\n }\n config.translate.key = toInjectable(config.translate.key);\n config.translate.values = toInjectable(config.translate.values);\n // @ngInject\n config.getText = function () {\n var translateFilter;\n if (!$injector.has('translateFilter')) {\n throw new Error('Nav: menu item set \"translate\" property without angular-translate present');\n }\n translateFilter = $injector.get('translateFilter');\n return translateFilter(\n invoke(config.translate.key),\n invoke(config.translate.values)\n );\n };\n }\n }\n\n function configureTemplate(config) {\n if (!_.isString(config.template)) {\n return;\n }\n config.template = $sce.trustAsHtml(config.template);\n }\n\n configureText(title);\n configureText(welcome);\n\n // massage config items so they're usable\n mainMenuItems\n .concat(rightMenuItems)\n .concat(userMenuItems)\n .forEach(function (config) {\n configureState(config);\n configureText(config);\n // TODO: implement the UI for child nav items\n config.children = _.map(config.children, function (child) {\n configureState(child);\n configureText(child);\n // only children get the ability to template for now\n configureTemplate(child);\n return child;\n });\n });\n\n return {\n appTitle : appTitle,\n appWelcome : appWelcome,\n mainMenu : mainMenu,\n rightMenu : rightMenu,\n userMenu : userMenu\n };\n\n function appTitle() {\n return title;\n }\n\n function appWelcome() {\n return welcome;\n }\n\n function mainMenu() {\n return mainMenuItems\n }\n\n function rightMenu() {\n return rightMenuItems;\n }\n\n function userMenu() {\n return userMenuItems;\n }\n };\n }\n\n function require(x, msg) {\n if (!x) {\n throw new Error(msg);\n }\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.Nav')\n .directive('tfcPage', tfcPage);\n\n // @ngInject\n function tfcPage() {\n return {\n templateUrl : 'Nav/Page.tmpl.html',\n scope : {\n fullWidth : '='\n }\n };\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.Nav')\n .factory('TextUtil', TextUtil);\n\n // @ngInject\n function TextUtil($injector) {\n\n var translateFilter;\n if ($injector.has('translateFilter')) {\n translateFilter = $injector.get('translateFilter');\n }\n\n return {\n translateOr : translateOr\n };\n\n /**\n * @name TextUtil#translateOr\n *\n * Uses angular-translate to translate the `translationId` or calls the `fallbackFn`\n * with `values`.\n *\n * @param translationId\n * @param [values]\n * @param fallbackFn\n * @returns String The result of the translation, or the return value of `fallbackFn`\n * if angular-translate is not present\n */\n function translateOr(translationId, values, fallbackFn) {\n if (arguments.length < 2) {\n throw new Error('translateOr requires at least a translationId and fallback function,' +\n 'with optional values in between.');\n }\n if (arguments.length === 2) {\n fallbackFn = values;\n values = undefined;\n }\n if (translateFilter) {\n return translateFilter(translationId, values);\n } else {\n return fallbackFn(values);\n }\n }\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.sso')\n .controller('ForgotPasswordCtrl', ForgotPasswordCtrl);\n\n // @ngInject\n function ForgotPasswordCtrl($stateParams, Auth) {\n var vm = this;\n\n vm.sent = false;\n vm.expired = $stateParams.expired;\n vm.email = $stateParams.email;\n\n vm.submit = function () {\n Auth.forgotPassword(vm.email).then(function () {\n vm.sent = true;\n });\n };\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.sso')\n .controller('LoginCtrl', LoginCtrl);\n\n // @ngInject\n function LoginCtrl(Auth) {\n var vm = this;\n vm.usingActiveDirectory = Auth.usingActiveDirectory;\n\n vm.user = {};\n\n vm.login = function () {\n Auth.login(vm.user);\n };\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.sso')\n .controller('PasswordResetCtrl', PasswordResetCtrl);\n\n // @ngInject\n function PasswordResetCtrl($state, Auth, Toast) {\n var vm = this;\n\n var user = Auth.getUser();\n\n vm.isAuthenticated = function () {\n return !!user;\n };\n\n vm.user = {\n user : $state.params.email || (user && user.email)\n };\n\n vm.error = null;\n\n vm.save = function () {\n vm.error = null;\n Auth.resetPassword(vm.user).then(function () {\n Toast.success('Password successfully changed');\n $state.go('login');\n });\n };\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.sso')\n .controller('PasswordResetFormCtrl', PasswordResetFormCtrl)\n .directive('tfcPasswordResetForm', tfcPasswordResetForm);\n\n // @ngInject\n function PasswordResetFormCtrl(Auth) {\n var vm = this;\n\n vm.isAuthenticated = function () {\n return !!Auth.getUser();\n };\n }\n\n // @ngInject\n function tfcPasswordResetForm() {\n return {\n bindToController : true,\n controller : 'PasswordResetFormCtrl as vm',\n templateUrl : 'sso/PasswordResetForm.tmpl.html',\n scope : {\n user : '=',\n onSubmit : '&'\n }\n };\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.sso')\n .controller('RecoverPasswordCtrl', RecoverPasswordCtrl);\n\n // @ngInject\n function RecoverPasswordCtrl($state, $stateParams, email, Auth, Toast, TextUtil) {\n var vm = this;\n\n vm.email = email;\n\n vm.submit = function () {\n Auth.recoverPassword($stateParams.t, vm.user.newPass).then(function () {\n Toast.success(TextUtil.translateOr('auth.password.reset.success', function () {\n return 'Your password has been reset.';\n }));\n $state.go('login');\n });\n };\n }\n\n})();\n","(function () {\n 'use strict';\n\n // tfc.sso's run block calls Auth.validate() (see sso.module.js).\n // This is a separate module so tfc.sso's run doesn't have to be mocked for every test\n angular\n .module('tfc.sso.Auth')\n .provider('Auth', Auth)\n .config(config);\n\n // @ngInject\n function config($httpProvider, AuthProvider) {\n\n\n }\n\n // @ngInject\n function Auth() {\n var basePath = 'ui';\n var paths = {\n login : '/auth/login',\n logout : '/auth/logout',\n validate : '/auth/validate',\n resetPassword: '/auth/password/reset',\n forgotPassword: '/auth/password/forgot',\n recoverPassword: '/auth/password/recover',\n getEmailByPasswordToken : '/auth/password/token'\n };\n\n var _usingActiveDirectory = false;\n\n this.setBasePath = function (bp) {\n basePath = bp;\n };\n\n this.setPath = function (name, path) {\n paths[name] = path;\n };\n\n this.usingActiveDirectory = function () {\n _usingActiveDirectory = true\n };\n\n this.$get = function ($rootScope, $http, $log, $q, $state, $urlRouter, CookieJar, Toast) {\n var _authenticatedUser;\n var _isValid,\n _hasValidated;\n\n function initVars() {\n _authenticatedUser = null;\n _isValid = false;\n _hasValidated = false;\n }\n\n initVars();\n\n return {\n getUser : getUser,\n login : login,\n logout : logout,\n validate : validate,\n resetPassword : resetPassword,\n forgotPassword : forgotPassword,\n recoverPassword : recoverPassword,\n getEmailByPasswordToken : getEmailByPasswordToken,\n isAuthenticated : isAuthenticated,\n hasValidated : function () { return _hasValidated; },\n can : can,\n usingActiveDirectory : function () { return _usingActiveDirectory}\n };\n\n function getUser() {\n if (isAuthenticated()) {\n return _authenticatedUser;\n } else {\n return null;\n }\n }\n\n function login(credentials) {\n return $http.post(basePath + paths.login, credentials).then(function (response) {\n _authenticatedUser = response.data;\n _isValid = true;\n var expiration = getUser().passwordExpiration;\n var ttlMs = expiration - Date.now();\n var ttlDays = Math.floor(ttlMs / 1000 / 60 / 60 / 24);\n var when;\n // Give them 7 days of warning before it expires\n if (ttlDays <= 7) {\n when = new Date(expiration).toLocaleDateString(); // 'mm/dd/yyyy'\n Toast.warn('Your password will expire on ' + when + '. Please reset it');\n }\n if ($state.params.dest) {\n document.location.hash = $state.params.dest;\n $urlRouter.sync();\n } else {\n $rootScope.$broadcast('auth.login');\n }\n }, handleError);\n }\n\n function logout() {\n return $http.post(basePath + paths.logout).then(function () {\n initVars();\n $rootScope.$broadcast('auth.logout');\n });\n }\n\n function validate() {\n return $http.get(basePath + paths.validate).then(function (response) {\n _authenticatedUser = response.data;\n _isValid = true;\n }, function(response) {\n _isValid = false;\n if (response.status === 403) {\n // They're already logged in from somewhere else, but they can't access this app.\n Toast.error('You do not have permission to use this application');\n } else if (response.status === 401) {\n _authenticatedUser = null;\n } else if (response.status >= 500) {\n Toast.error('Something is wrong with the server. Please contact operations.');\n } else {\n Toast.error('Unexpected error. (code = ' + response.status + ')');\n }\n }).finally(function () {\n _hasValidated = true;\n });\n }\n\n function resetPassword(change) {\n change = _.pick(change, ['user', 'pass', 'newPass']);\n return $http.post(basePath + paths.resetPassword, change)\n .then(null, handleError);\n }\n\n function forgotPassword(email) {\n return $http.post(basePath + paths.forgotPassword, { email : email });\n }\n\n function recoverPassword(token, newPassword) {\n return $http.post(basePath + paths.recoverPassword, {\n token : token,\n newPassword : newPassword\n }).then(null, handleError);\n }\n\n function getEmailByPasswordToken(token) {\n return $http.get(basePath + paths.getEmailByPasswordToken, {\n params : { token : token }\n }).then(_.property('data'));\n }\n\n function handleError(response) {\n if (response.status === 400) {\n switch (_.get(response.data, '_type')) {\n case 'PasswordInsecure':\n Toast.error(response.data.message, { state : true });\n break;\n case 'PasswordUnchanged':\n Toast.error('You cannot use your current or ' +\n response.data.recentPasswordCount + ' most recent passwords.', { state : true });\n break;\n default:\n Toast.error('Oops! Something went wrong.');\n break;\n }\n } else if (response.status === 401) {\n switch (_.get(response.data, '_type')) {\n case 'TooManyFailedLoginAttempts':\n Toast.error(\"You've failed to login too many times. Please try again later.\");\n break;\n case 'MustResetPassword':\n var user = response.data.user;\n if (user.passwordExpiration < Date.now()) {\n Toast.warn('Your password has expired. Please change it.');\n }\n $state.go('passwordResetPublic', { email : user.email });\n break;\n default:\n Toast.warn('Invalid email or password', { state : true });\n }\n } else if (response.status >= 500) {\n // TODO: move to an interceptor\n Toast.error('Unexpected error', { state : true });\n }\n return $q.reject(response);\n }\n\n function isAuthenticated() {\n return _isValid && !!_authenticatedUser;\n }\n\n function can(permission) {\n var user = getUser();\n return !!user && -1 !== user.privileges.indexOf(permission);\n }\n };\n }\n\n})();\n","(function () {\n 'use strict';\n\n angular\n .module('tfc.sso.Auth')\n .factory('CookieJar', CookieJar);\n\n // @ngInject\n function CookieJar($log) {\n\n return {\n /**\n * @name CookieJar#get\n * @param name {string} The name of the cookie\n * @returns {string} The value of the cookie, or undefined if it does not exist.\n */\n get : get,\n /**\n * @name CookieJar#set\n * @param {object} data The cookie configuration, which has the following fields:\n * - {string} name The name of the cookie.\n * - {string} value The value of the cookie.\n * - {string} [domain] The domain for the cookie. Setting to true will use the current domain's parent domain.\n * Omitting the domain sets a session cookie.\n * - {string} [path] The path to which this cookie applies. Defaults to '/'.\n * - {number} [maxAge] Integer representing # seconds for the cookie to last. Anything <= 0 will delete the cookie.\n */\n set : set,\n /**\n * @name CookieJar#remove\n * @param {object|string} data The name of the cookie, or an object containing:\n * - {string} name The name of the cookie.\n * - {string} [domain] The domain of the cookie. Defaults to the current domain's parent domain.\n * - {string} [path] The path of the cookie to delete. Defaults to '/'.\n */\n remove : remove\n };\n\n function isNonEmptyString(x) {\n return _.isString(x) && x.length > 0;\n }\n\n function defaultDomain() {\n var domain = location.hostname;\n if (domain === 'localhost') {\n $log.warn(\"Cookies don't really work on localhost. Using a session cookie\");\n return;\n }\n var parts = domain.split('.');\n if (parts.length > 2) {\n return parts.slice(1).join('.');\n } else {\n return domain;\n }\n }\n\n function get(name) {\n var cookiePairs = document.cookie.split('; ');\n var value;\n _.each(cookiePairs, function (pair) {\n var split = pair.split('=');\n if (split[0] === name) {\n value = split[1];\n return false;\n }\n });\n return value;\n }\n\n function set(data) {\n var cookie, expires;\n if (_.isPlainObject(data) && _.isString(data.name) && _.isString(data.value)) {\n\n cookie = data.name + '=' + data.value;\n\n if (data.domain === true) {\n data.domain = defaultDomain();\n }\n\n if (isNonEmptyString(data.domain)) {\n cookie += ';domain=' + data.domain;\n }\n\n data.path = isNonEmptyString(data.path) ? data.path : '/';\n cookie += ';path=' + data.path;\n\n if (!isNaN(data.maxAge)) {\n if (data.maxAge <= 0) {\n data.maxAge = expires = 0;\n } else {\n expires = new Date().getTime() + data.maxAge * 1000;\n }\n cookie += ';max-age=' + data.maxAge;\n cookie += ';expires=' + new Date(expires).toUTCString();\n }\n\n document.cookie = cookie;\n }\n }\n\n function _remove(data) {\n set({\n name: data.name,\n value: '',\n domain: data.domain,\n path: data.path,\n maxAge: 0\n });\n }\n\n function remove(data) {\n if (_.isString(data)) {\n data = {\n name : data,\n domain : true\n };\n }\n\n _remove(data);\n\n if (get(data.name) != null && data.domain) {\n $log.debug('Cookie [' + data.name + '] still present after remove. ' +\n 'Trying again as a session cookie');\n delete data.domain;\n _remove(data);\n }\n }\n }\n\n})();\n"]}