angular.module("bit",["ui.router","ngMessages","angular-jwt","angular-md5","ui.bootstrap.showErrors","toastr","angulartics","angulartics.google.analytics","bit.directives","bit.services","bit.global","bit.accounts","bit.vault","bit.settings","bit.tools"]),angular.module("bit").constant("appSettings",{rememberedEmailCookieName:"bit.rememberedEmail",version:"1.0.0",environment:"Production",apiUri:"https://api.bitwarden.com"}),angular.module("bit.accounts",["ui.bootstrap","ngCookies"]),angular.module("bit.directives",[]),angular.module("bit.global",[]),angular.module("bit.services",["ngResource","ngStorage","angular-jwt"]),angular.module("bit.settings",["ui.bootstrap","toastr"]),angular.module("bit.tools",["ui.bootstrap","toastr"]),angular.module("bit.vault",["ui.bootstrap","ngclipboard"]),angular.module("bit").factory("apiInterceptor",["$injector","$q","toastr",function(e,t,r){return{request:function(e){return e},response:function(o){return 401!==o.status&&403!==o.status||(e.get("authService").logOut(),e.get("$state").go("frontend.login.info").then(function(){r.warning("Your login session has expired.","Logged out")})),o||t.when(o)},responseError:function(o){return 401!==o.status&&403!==o.status||(e.get("authService").logOut(),e.get("$state").go("frontend.login.info").then(function(){r.warning("Your login session has expired.","Logged out")})),t.reject(o)}}}]),angular.module("bit").config(["$stateProvider","$urlRouterProvider","$httpProvider","jwtInterceptorProvider","$uibTooltipProvider","toastrConfig",function(e,t,r,o,a,n){o.urlParam="access_token",o.tokenGetter=["config","appSettings","tokenService",function(e,t,r){return 0===e.url.indexOf(t.apiUri)?r.getToken():void 0}],angular.extend(n,{closeButton:!0,progressBar:!0,showMethod:"slideDown",target:".toast-target"}),a.options({popupDelay:600}),r.defaults.headers.post&&(r.defaults.headers.post={}),r.defaults.headers.post["Content-Type"]="text/plain; charset=utf-8",r.interceptors.push("apiInterceptor"),r.interceptors.push("jwtInterceptor"),t.otherwise("/"),e.state("backend",{templateUrl:"app/views/backendLayout.html","abstract":!0,data:{authorize:!0}}).state("backend.vault",{url:"^/",templateUrl:"app/vault/views/vault.html",controller:"vaultController",data:{pageTitle:"My Vault"}}).state("backend.settings",{url:"^/settings",templateUrl:"app/settings/views/settings.html",controller:"settingsController",data:{pageTitle:"Settings"}}).state("backend.tools",{url:"^/tools",templateUrl:"app/tools/views/tools.html",controller:"toolsController",data:{pageTitle:"Tools"}}).state("frontend",{templateUrl:"app/views/frontendLayout.html","abstract":!0,data:{authorize:!1}}).state("frontend.login",{templateUrl:"app/accounts/views/accountsLogin.html",controller:"accountsLoginController",data:{bodyClass:"login-page"}}).state("frontend.login.info",{url:"^/login",templateUrl:"app/accounts/views/accountsLoginInfo.html",data:{pageTitle:"Log In"}}).state("frontend.login.twoFactor",{url:"^/login/two-factor",templateUrl:"app/accounts/views/accountsLoginTwoFactor.html",data:{pageTitle:"Log In (Two Factor)",authorizeTwoFactor:!0}}).state("frontend.logout",{url:"^/logout",controller:"accountsLogoutController",data:{authorize:!0}}).state("frontend.passwordHint",{url:"^/password-hint",templateUrl:"app/accounts/views/accountsPasswordHint.html",controller:"accountsPasswordHintController",data:{pageTitle:"Master Password Hint",bodyClass:"login-page"}}).state("frontend.register",{url:"^/register",templateUrl:"app/accounts/views/accountsRegister.html",controller:"accountsRegisterController",data:{pageTitle:"Register",bodyClass:"register-page"}})}]).run(["$rootScope","authService","jwtHelper","tokenService","$state",function(e,t,r,o,a){e.$on("$stateChangeStart",function(e,n,s){return n.data&&n.data.authorize?void(t.isAuthenticated()&&!r.isTokenExpired(o.getToken())||(e.preventDefault(),t.logOut(),a.go("frontend.login.info"))):void(t.isAuthenticated()&&!r.isTokenExpired(o.getToken())&&(e.preventDefault(),a.go("backend.vault")))})}]),angular.module("bit.accounts").controller("accountsLoginController",["$scope","$rootScope","$cookies","apiService","cryptoService","authService","$state","appSettings","$analytics",function(e,t,r,o,a,n,s,i,l){var c=r.get(i.rememberedEmailCookieName);c&&(e.model={email:c,rememberEmail:!0}),e.login=function(t){e.loginPromise=n.logIn(t.email,t.masterPassword),e.loginPromise.then(function(){if(t.rememberEmail){var e=new Date;e.setFullYear(e.getFullYear()+10),r.put(i.rememberedEmailCookieName,t.email,{expires:e})}else r.remove(i.rememberedEmailCookieName);var o=n.getUserProfile();o.twoFactor?(l.eventTrack("Logged In To Two-step"),s.go("frontend.login.twoFactor")):(l.eventTrack("Logged In"),s.go("backend.vault"))})},e.twoFactor=function(t){e.twoFactorPromise=n.logInTwoFactor(t.code,"Authenticator"),e.twoFactorPromise.then(function(){l.eventTrack("Logged In From Two-step"),s.go("backend.vault")})}}]),angular.module("bit.accounts").controller("accountsLogoutController",["$scope","authService","$state","$analytics",function(e,t,r,o){t.logOut(),o.eventTrack("Logged Out"),r.go("frontend.login.info")}]),angular.module("bit.accounts").controller("accountsPasswordHintController",["$scope","$rootScope","apiService",function(e,t,r){e.success=!1,e.submit=function(t){e.submitPromise=r.accounts.postPasswordHint({email:t.email},function(){e.success=!0}).$promise}}]),angular.module("bit.accounts").controller("accountsRegisterController",["$scope","$location","apiService","cryptoService","validationService","$analytics",function(e,t,r,o,a,n){var s=t.search();e.success=!1,e.model={email:s.email},e.registerPromise=null,e.register=function(t){var s=!1;if((e.model.masterPassword.length<8||!/[a-z]/i.test(e.model.masterPassword)||/^[a-zA-Z]*$/.test(e.model.masterPassword))&&(a.addError(t,"MasterPassword","Master password must be at least 8 characters long and contain at least 1 letter and 1 number or special character.",!0),s=!0),e.model.masterPassword!==e.model.confirmMasterPassword&&(a.addError(t,"ConfirmMasterPassword","Master password confirmation does not match.",!0),s=!0),!s){var i=o.makeKey(e.model.masterPassword,e.model.email),l={name:e.model.name,email:e.model.email,masterPasswordHash:o.hashPassword(e.model.masterPassword,i),masterPasswordHint:e.model.masterPasswordHint};e.registerPromise=r.accounts.register(l,function(){e.success=!0,n.eventTrack("Registered")}).$promise}}}]),angular.module("bit.directives").directive("apiField",function(){var e=function(e,t,r,o){function a(){return o.$setValidity("api",!0),!0}function n(){o.$setValidity("api",!1)}o.$registerApiError=n,o.$validators.apiValidate=a};return{require:"ngModel",restrict:"A",compile:function(t,r){if(!r.name||""===r.name)throw"api-field element does not have a valid name attribute";return e}}}),angular.module("bit.directives").directive("apiForm",["$rootScope","validationService",function(e,t){function r(e,r,o){o&&o.then&&(e.$errors=null,e.$loading=!0,o.then(function(t){e.$loading=!1},function(o){e.$loading=!1,t.addErrors(e,o),r.$broadcast("show-errors-check-validity")}))}return{require:"form",restrict:"A",link:function(e,t,o,a){var n=o.apiForm||null;void 0!==n&&e.$watch(n,r.bind(null,a,e))}}}]),angular.module("bit.directives").directive("masterPassword",["cryptoService","authService",function(e,t){return{require:"ngModel",restrict:"A",link:function(r,o,a,n){var s=t.getUserProfile();s&&(n.$parsers.unshift(function(t){if(t){var r=e.makeKey(t,s.email,!0),o=r===e.getKey(!0);return n.$setValidity("masterPassword",o),o?t:void 0}}),n.$formatters.unshift(function(t){if(t){var r=e.makeKey(t,s.email,!0),o=r===e.getKey(!0);return n.$setValidity("masterPassword",o),t}}))}}}]),angular.module("bit.directives").directive("pageTitle",["$rootScope","$timeout","appSettings",function(e,t,r){return{link:function(r,o){var a=function(e,r,a,n,s){var i="bitwarden Password Manager";r.data&&r.data.pageTitle&&(i=r.data.pageTitle+" - bitwarden Password Manager"),t(function(){o.text(i)})};e.$on("$stateChangeStart",a)}}}]),angular.module("bit.directives").directive("passwordMeter",function(){return{template:'
{{value}}%
',restrict:"A",scope:{password:"=passwordMeter",username:"=passwordMeterUsername",outerClass:"@?"},link:function(e){var t=function(e,t){if(!t||t===e)return 0;var r=t.length;return e&&""!==e&&(-1!==e.indexOf(t)&&(r-=15),-1!==t.indexOf(e)&&(r-=e.length)),t.length>0&&t.length<=4?r+=t.length:t.length>=5&&t.length<=7?r+=6:t.length>=8&&t.length<=15?r+=12:t.length>=16&&(r+=18),t.match(/[a-z]/)&&(r+=1),t.match(/[A-Z]/)&&(r+=5),t.match(/\d/)&&(r+=5),t.match(/.*\d.*\d.*\d/)&&(r+=5),t.match(/[!,@,#,$,%,^,&,*,?,_,~]/)&&(r+=5),t.match(/.*[!,@,#,$,%,^,&,*,?,_,~].*[!,@,#,$,%,^,&,*,?,_,~]/)&&(r+=5),t.match(/(?=.*[a-z])(?=.*[A-Z])/)&&(r+=2),t.match(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/)&&(r+=2),t.match(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!,@,#,$,%,^,&,*,?,_,~])/)&&(r+=2),r=Math.round(2*r),Math.max(0,Math.min(100,r))},r=function(e){switch(Math.round(e/33)){case 0:case 1:return"danger";case 2:return"warning";case 3:return"success"}},o=function(e){e.value=t(e.username,e.password),e.valueClass=r(e.value)};e.$watch("password",function(){o(e)}),e.$watch("username",function(){o(e)})}}}),angular.module("bit.directives").directive("passwordViewer",function(){return{restrict:"A",link:function(e,t,r){var o=r.passwordViewer;o&&(t.onclick=function(e){},t.on("click",function(e){var r=$(o);r&&"password"===r.attr("type")?(t.removeClass("fa-eye").addClass("fa-eye-slash"),r.attr("type","text")):r&&"text"===r.attr("type")&&(t.removeClass("fa-eye-slash").addClass("fa-eye"),r.attr("type","password"))}))}}}),angular.module("bit.global").controller("mainController",["$scope","$state","authService","appSettings","toastr",function(e,t,r,o,a){var n=this;n.bodyClass="",n.userProfile=null,n.searchVaultText=null,n.version=o.version,e.currentYear=(new Date).getFullYear(),e.$on("$viewContentLoaded",function(){$.AdminLTE&&($.AdminLTE.layout&&($.AdminLTE.layout.fix(),$.AdminLTE.layout.fixSidebar()),$.AdminLTE.pushMenu&&$.AdminLTE.pushMenu.expandOnHover())}),e.$on("$stateChangeSuccess",function(e,t,o,a,s){return n.searchVaultText=null,n.userProfile=r.getUserProfile(),t.data.bodyClass?void(n.bodyClass=t.data.bodyClass):void(n.bodyClass="")}),e.searchVault=function(){t.go("backend.vault")},e.addSite=function(){e.$broadcast("vaultAddSite")},e.addFolder=function(){e.$broadcast("vaultAddFolder")},e.changeEmail=function(){e.$broadcast("settingsChangeEmail")},e.changePassword=function(){e.$broadcast("settingsChangePassword")},e.sessions=function(){e.$broadcast("settingsSessions")},e["delete"]=function(){e.$broadcast("settingsDelete")},e.twoFactor=function(){e.$broadcast("settingsTwoFactor")},e["import"]=function(){e.$broadcast("toolsImport")},e["export"]=function(){e.$broadcast("toolsExport")},e.audits=function(){e.$broadcast("toolsAudits")}}]),angular.module("bit.global").controller("sideNavController",["$scope","$state",function(e,t){e.$state=t}]),angular.module("bit.global").controller("topNavController",["$scope",function(e){}]),angular.module("bit.services").factory("apiService",["$resource","tokenService","appSettings",function(e,t,r){var o={},a=r.apiUri;return o.sites=e(a+"/sites/:id",{},{get:{method:"GET",params:{id:"@id"}},list:{method:"GET",params:{}},post:{method:"POST",params:{}},put:{method:"POST",params:{id:"@id"}},del:{url:a+"/sites/:id/delete",method:"POST",params:{id:"@id"}}}),o.folders=e(a+"/folders/:id",{},{get:{method:"GET",params:{id:"@id"}},list:{method:"GET",params:{}},post:{method:"POST",params:{}},put:{method:"POST",params:{id:"@id"}},del:{url:a+"/folders/:id/delete",method:"POST",params:{id:"@id"}}}),o.ciphers=e(a+"/ciphers/:id",{},{get:{method:"GET",params:{id:"@id"}},list:{method:"GET",params:{}},"import":{url:a+"/ciphers/import",method:"POST",params:{}},favorite:{url:a+"/ciphers/:id/favorite",method:"POST",params:{id:"@id"}},del:{url:a+"/ciphers/:id/delete",method:"POST",params:{id:"@id"}}}),o.accounts=e(a+"/accounts",{},{register:{url:a+"/accounts/register",method:"POST",params:{}},emailToken:{url:a+"/accounts/email-token",method:"POST",params:{}},email:{url:a+"/accounts/email",method:"POST",params:{}},putPassword:{url:a+"/accounts/password",method:"POST",params:{}},getProfile:{url:a+"/accounts/profile",method:"GET",params:{}},putProfile:{url:a+"/accounts/profile",method:"POST",params:{}},getTwoFactor:{url:a+"/accounts/two-factor",method:"GET",params:{}},putTwoFactor:{url:a+"/accounts/two-factor",method:"POST",params:{}},postPasswordHint:{url:a+"/accounts/password-hint",method:"POST",params:{}},putSecurityStamp:{url:a+"/accounts/security-stamp",method:"POST",params:{}},"import":{url:a+"/accounts/import",method:"POST",params:{}},postDelete:{url:a+"/accounts/delete",method:"POST",params:{}}}),o.auth=e(a+"/auth",{},{token:{url:a+"/auth/token",method:"POST",params:{}},tokenTwoFactor:{url:a+"/auth/token/two-factor",method:"POST",params:{}}}),o}]),angular.module("bit.services").factory("authService",["cryptoService","apiService","tokenService","$q","jwtHelper",function(e,t,r,o,a){function n(e){i.extended={name:e.Name,twoFactorEnabled:e.TwoFactorEnabled,culture:e.Culture}}var s={},i=null;return s.logIn=function(a,n){var i=e.makeKey(n,a),l={email:a,masterPasswordHash:e.hashPassword(n,i)},c=o.defer();return t.auth.token(l,function(t){t&&t.Token&&(r.setToken(t.Token),e.setKey(i),s.setUserProfile(t.Profile),c.resolve(t))},function(e){c.reject(e)}),c.promise},s.logInTwoFactor=function(e,a){var n={code:e,provider:a},i=o.defer();return t.auth.tokenTwoFactor(n,function(e){e&&e.Token&&(r.setToken(e.Token),s.setUserProfile(e.Profile),i.resolve(e))},function(e){i.reject(e)}),i.promise},s.logOut=function(){r.clearToken(),e.clearKey(),i=null},s.getUserProfile=function(){return i||s.setUserProfile(),i},s.setUserProfile=function(e){var o=r.getToken();if(o){var s=a.decodeToken(o),l="TwoFactor"===s.authmethod;i={id:s.nameid,email:s.email,twoFactor:l},!l&&e?n(e):l||e||t.accounts.getProfile({},n)}},s.isAuthenticated=function(){return null!==s.getUserProfile()&&!s.getUserProfile().twoFactor},s.isTwoFactorAuthenticated=function(){return null!==s.getUserProfile()&&s.getUserProfile().twoFactor},s}]),angular.module("bit.services").factory("cipherService",["cryptoService","apiService",function(e,t){var r={};return r.decryptSites=function(e){if(!e)throw"encryptedSites is undefined or null";for(var t=[],o=0;o0)for(var s=0;s0)for(var i=0;i0)for(var l=0;l0)for(var c=0;c=t?e:new Array(t-e.length+1).join(r)+e}l.eventTrack("toolsExportController",{category:"Modal"}),e["export"]=function(r){e.startedExport=!0,t.sites.list({expand:["folder"]},function(t){try{for(var r=n.decryptSites(t.Data),o=[],a=0;a0&&(r[0].folderId=t.folderId,r[0].name=t.name,r[0].username=t.username,r[0].favorite=t.favorite)})},e.$on("vaultAddSite",function(t,r){e.addSite()}),e.addSite=function(r){var o=t.open({animation:!0,templateUrl:"app/vault/views/vaultAddSite.html",controller:"vaultAddSiteController",resolve:{folders:function(){return e.folders},selectedFolder:function(){return r}}});o.result.then(function(t){e.sites.push(t)})},e.deleteSite=function(t){confirm("Are you sure you want to delete this site ("+t.name+")?")&&r.sites.del({id:t.id},function(){var r=e.sites.indexOf(t);e.sites.splice(r,1)})},e.editFolder=function(r){var a=t.open({animation:!0,templateUrl:"app/vault/views/vaultEditFolder.html",controller:"vaultEditFolderController",size:"sm",resolve:{folderId:function(){return r.id}}});a.result.then(function(t){var r=o("filter")(e.folders,{id:t.id},!0);r&&r.length>0&&(r[0].name=t.name)})},e.$on("vaultAddFolder",function(t,r){e.addFolder()}),e.addFolder=function(){var r=t.open({animation:!0,templateUrl:"app/vault/views/vaultAddFolder.html",controller:"vaultAddFolderController",size:"sm"});r.result.then(function(t){e.folders.push(t)})},e.deleteFolder=function(t){confirm("Are you sure you want to delete this folder ("+t.name+")?")&&r.folders.del({id:t.id},function(){var r=e.folders.indexOf(t);e.folders.splice(r,1)})},e.canDeleteFolder=function(t){if(!t||!t.id)return!1;var r=o("filter")(e.sites,{folderId:t.id});return 0===r.length}}]),angular.module("bit.vault").controller("vaultEditFolderController",["$scope","apiService","$uibModalInstance","cryptoService","cipherService","folderId","$analytics",function(e,t,r,o,a,n,s){s.eventTrack("vaultEditFolderController",{category:"Modal"}),e.folder={},t.folders.get({id:n},function(t){e.folder=a.decryptFolder(t)}),e.savePromise=null,e.save=function(o){var i=a.encryptFolder(o);e.savePromise=t.folders.put({id:n},i,function(e){s.eventTrack("Edited Folder");var t=a.decryptFolder(e);r.close(t)}).$promise},e.close=function(){r.dismiss("cancel")}}]),angular.module("bit.vault").controller("vaultEditSiteController",["$scope","apiService","$uibModalInstance","cryptoService","cipherService","passwordService","siteId","folders","$analytics",function(e,t,r,o,a,n,s,i,l){function c(e){var t=$(e.trigger).parent().prev();"text"===t.attr("type")&&t.select()}l.eventTrack("vaultEditSiteController",{category:"Modal"}),e.folders=i,e.site={},t.sites.get({id:s},function(t){e.site=a.decryptSite(t)}),e.save=function(o){var n=a.encryptSite(o);e.savePromise=t.sites.put({id:s},n,function(e){l.eventTrack("Edited Site");var t=a.decryptSite(e);r.close(t)}).$promise},e.generatePassword=function(){e.site.password&&!confirm("Are you sure you want to overwrite the current password?")||(l.eventTrack("Generated Password From Edit"),e.site.password=n.generatePassword({length:10,special:!0}))},e.clipboardSuccess=function(e){e.clearSelection(),c(e)},e.clipboardError=function(e,t){t&&c(e),alert("Your web browser does not support easy clipboard copying. Copy it manually instead.")},e.close=function(){r.dismiss("cancel")}}]);