UNPKG

scriptremote

Version:

Message server providing secure remote access to scripted applications from a browser UI

2 lines 53.2 kB
"use strict";var ApplicationConfiguration=function(){var applicationModuleName="scriptremote",applicationModuleVendorDependencies=["ngResource","ngRoute","ui.bootstrap"],registerModule=function(moduleName,dependencies){angular.module(moduleName,dependencies||[]),angular.module(applicationModuleName).requires.push(moduleName)};return{applicationModuleName:applicationModuleName,applicationModuleVendorDependencies:applicationModuleVendorDependencies,registerModule:registerModule}}();angular.module(ApplicationConfiguration.applicationModuleName,ApplicationConfiguration.applicationModuleVendorDependencies),angular.module(ApplicationConfiguration.applicationModuleName).config(["$locationProvider","$routeProvider",function($locationProvider,$routeProvider){$locationProvider.html5Mode(!1),$routeProvider.otherwise({redirectTo:"/home"})}]),angular.element(document).ready(function(){angular.bootstrap(document,[ApplicationConfiguration.applicationModuleName])}),ApplicationConfiguration.registerModule("adminSvcMod",[]),ApplicationConfiguration.registerModule("alertMod",[]),ApplicationConfiguration.registerModule("ui.bootstrap",["ui.bootstrap.tpls","ui.bootstrap.alert","alertMod"]),ApplicationConfiguration.registerModule("ui.bootstrap.tpls",["template/alert/alert.html"]),ApplicationConfiguration.registerModule("ui.bootstrap.alert",[]),ApplicationConfiguration.registerModule("template/alert/alert.html",[]),ApplicationConfiguration.registerModule("apiMod",[]),ApplicationConfiguration.registerModule("authMod",["alertMod"]),ApplicationConfiguration.registerModule("breadcrumbGlyphsMod",[]),ApplicationConfiguration.registerModule("cryptoMod",[]),ApplicationConfiguration.registerModule("settingsMod",[]),ApplicationConfiguration.registerModule("tmplMod",[]),ApplicationConfiguration.registerModule("adminMod",["ngRoute","ngResource","apiMod","adminSvcMod","authMod","alertMod"]),ApplicationConfiguration.registerModule("contentMod",["ngRoute","ngResource","apiMod","tmplMod","alertMod"]),ApplicationConfiguration.registerModule("footerMod",[]),ApplicationConfiguration.registerModule("headerMod",["authMod"]),ApplicationConfiguration.registerModule("homeMod",[]),ApplicationConfiguration.registerModule("jobSettingsMod",["ngRoute","ngResource","apiMod","authMod","alertMod"]),ApplicationConfiguration.registerModule("jobsMod",["ngRoute","ngResource","apiMod","alertMod"]),ApplicationConfiguration.registerModule("templatesSelectMod",["ngRoute","tmplMod","apiMod","alertMod"]),ApplicationConfiguration.registerModule("locationsMod",["ngRoute","ngResource","apiMod","alertMod"]),ApplicationConfiguration.registerModule("msgsMod",["ngRoute","ngResource","apiMod","alertMod"]),ApplicationConfiguration.registerModule("templatesAddMod",["ngRoute","tmplMod","authMod","alertMod"]),ApplicationConfiguration.registerModule("projectSettingsMod",["ngRoute","ngResource","apiMod","authMod","alertMod"]),ApplicationConfiguration.registerModule("projectsMod",["ngRoute","ngResource","apiMod","alertMod"]),ApplicationConfiguration.registerModule("userSettingsMod",["ngRoute","ngResource","apiMod","authMod","alertMod"]),angular.module("adminSvcMod").factory("AdminSvc",["$resource",function($resource){var service=$resource("admin",{},{userGet:{method:"GET",url:"admin/users/:uid"},userPut:{method:"PUT",url:"admin/users/:uid"},userDelete:{method:"DELETE",url:"admin/users/:uid"},userCreate:{method:"POST",url:"admin/users"},sendMail:{method:"PUT",url:"admin/mail"},optionsPut:{method:"PUT",url:"admin/options"},optionsGet:{method:"GET",url:"admin/options"}});return service}]),angular.module("alertMod").factory("AlertSvc",["$window","$location","$rootScope","$anchorScroll",function($window,$location,$rootScope,$anchorScroll){var service={};return service.alerts=[],service.resAlert=function(response,clearUser){var duplicate,i,obj=null;try{obj=angular.fromJson(response.data)}catch(e){return service.alerts.push({type:"danger",msg:"Server error"}),void $location.path("/#home")}if(obj&&obj.hasOwnProperty("SR_status")){var level="info";for(response.status>=400&&(level="warning"),response.status>=500&&(level="danger"),duplicate=!1,i=0;i<service.alerts.length;i++)if(service.alerts[i].type==level&&service.alerts[i].msg==obj.SR_status){duplicate=!0;break}duplicate||service.alerts.push({type:level,msg:obj.SR_status}),"Not logged in"==obj.SR_status?("undefined"!=typeof clearUser&&clearUser(),$location.path("/#home")):$anchorScroll()}else{for(duplicate=!1,i=0;i<service.alerts.length;i++)if("danger"==service.alerts[i].type&&"Server error"==service.alerts[i].msg){duplicate=!0;break}duplicate||service.alerts.push({type:"danger",msg:"Server error"}),$location.path("/#home")}},service.msgAlert=function(level,msg){for(var duplicate=!1,i=0;i<service.alerts.length;i++)if(service.alerts[i].type==level&&service.alerts[i].msg==msg){duplicate=!0;break}duplicate||service.alerts.push({type:level,msg:msg}),$anchorScroll()},service.confirm=function(msg){var r=$window.confirm(msg);return r},service.remove=function(index){service.alerts.splice(index,1)},service}]),angular.module("ui.bootstrap.alert").controller("AlertController",["$scope","AlertSvc",function($scope,AlertSvc){$scope.closeable=!0,$scope.close=function(index){AlertSvc.remove(index)},$scope.alerts=AlertSvc.alerts}]).directive("alert",["AlertSvc",function(AlertSvc){return{restrict:"EA",controller:"AlertController",templateUrl:"template/alert/alert.html",transclude:!0,replace:!0}}]).directive("dismissOnTimeout",["$timeout",function($timeout){return{require:"alert",link:function(scope,element,attrs,alertCtrl){$timeout(function(){alertCtrl.close()},parseInt(attrs.dismissOnTimeout,10))}}}]),angular.module("template/alert/alert.html").run(["$templateCache",function($templateCache){$templateCache.put("template/alert/alert.html",' <div ng-repeat="item in alerts">\n <div class="alert" ng-class="[\'alert-\' + (item.type || \'warning\'), closeable ? \'alert-dismissable\' : null]" role="alert">\n <button ng-show="closeable" type="button" class="close" ng-click="close($index)">\n <span aria-hidden="true">&times;</span>\n <span class="sr-only">Close</span>\n </button>\n {{item.msg}}\n </div>\n </div>\n')}]),angular.module("apiMod").factory("ApiSvc",["$resource","$http",function($resource,$http){var service={};return service.resource=$resource("brsapi/projects",{},{projectGet:{method:"GET",url:"brsapi/projects/:project"},jobGet:{method:"GET",url:"brsapi/projects/:project/jobs/:job"},locationGet:{method:"GET",url:"brsapi/projects/:project/jobs/:job/locations/:location"},msgGet:{method:"GET",url:"brsapi/projects/:project/jobs/:job/locations/:location/msgs/:msg"},filesGet:{method:"GET",url:"brsapi/projects/:project/jobs/:job/locations/:location/msgs/:msg/files"},locationPut:{method:"PUT",url:"brsapi/projects/:project/jobs/:job/locations/:location/templates"},projectDescPut:{method:"PUT",url:"brsapi/projects/:project/description"},jobDescPut:{method:"PUT",url:"brsapi/projects/:project/jobs/:job/description"},locationDescPut:{method:"PUT",url:"brsapi/projects/:project/jobs/:job/locations/:location/description"},msgPut:{method:"PUT",url:"brsapi/projects/:project/jobs/:job/locations/:location/msgs/:msg/reply"},sharePut:{method:"PUT",url:"brsapi/projects/:project/share"},notifyPut:{method:"PUT",url:"brsapi/projects/:project/notify"},projectDelete:{method:"DELETE",url:"brsapi/projects/:project"},jobDelete:{method:"DELETE",url:"brsapi/projects/:project/jobs/:job"}}),service.fileGet=function(project,job,location,msg,key){var req={method:"GET",url:"brsapi/projects/"+encodeURIComponent(project)+"/jobs/"+job+"/locations/"+encodeURIComponent(location)+"/msgs/"+msg+"/files/"+key};return $http(req)},service}]),angular.module("authMod").factory("AuthSvc",["$q","$location","$http","AlertSvc",function($q,$location,$http,AlertSvc){var service={};return service.data={email:"",loggedIn:!1,admin:!1},service.checkAtStart=function(){return $http.get("/authcheck").then(function(res){return 200==res.status?(service.data.loggedIn=!0,service.data.email=res.data.user,service.data.admin=res.data.admin,{email:service.data.email,admin:service.data.admin}):(service.data.loggedIn=!1,service.data.email="",service.data.admin=!1,null)},function(res){return service.data.loggedIn=!1,service.data.email="",service.data.admin=!1,null})},service.checkAtRoute=function(){var deferred=$q.defer();return service.data.loggedIn?deferred.resolve():service.checkAtStart().then(function(user){user?deferred.resolve():($location.path("/#home"),AlertSvc.msgAlert("info","Please login first"),deferred.reject())}),deferred.promise},service.alertPostRoute=function(res){AlertSvc.resAlert(res,service.reset)},service.email=function(){return service.data.email},service.authenticated=function(){return service.data.loggedIn},service.admin=function(){return service.data.admin},service.reset=function(){service.data.loggedIn=!1,service.data.email="",service.data.admin=!1},service}]),angular.module("breadcrumbGlyphsMod").controller("breadcrumbGlyphsCtrl",["$scope",function($scope){$scope.showHideInfo=function(){$scope.bcinfo.visible=!$scope.bcinfo.visible}}]).directive("breadcrumbGlyphs",function(){return{controller:"breadcrumbGlyphsCtrl",templateUrl:"modules/services/breadcrumbglyphs/src/breadcrumbglyphs.html",restrict:"EA",scope:{bcglyphs:"=",bcinfo:"=",bcfct:"="}}}).directive("breadcrumbInfo",function(){return{controller:"breadcrumbGlyphsCtrl",templateUrl:"modules/services/breadcrumbglyphs/src/breadcrumbinfo.html",restrict:"EA",scope:{bcinfo:"="}}}),angular.module("cryptoMod").factory("CryptoSvc",["$window","AlertSvc",function($window,AlertSvc){var service={keySize:32,ivSize:16,passphrase:"",encrypted:!1,keyGenIters:1e4,opensslPrefix:"Salted__",aesKeys:{}};return service.init=function(){$window.localStorage.getItem("passphrase")&&""!==$window.localStorage.getItem("passphrase")?(service.passphrase=$window.localStorage.getItem("passphrase"),service.encrypted=!0):$window.sessionStorage.getItem("passphrase")&&""!==$window.sessionStorage.getItem("passphrase")?(service.passphrase=$window.sessionStorage.getItem("passphrase"),service.encrypted=!0):(service.passphrase="",service.encrypted=!1,service.aesKeys={})},service.computeAESKey=function(project,salt){if(salt.length>0){var data64=salt.replace(/-/g,"/"),binary=forge.util.decode64(data64),buf=forge.util.createBuffer(binary,"raw");salt=buf.getBytes(8);var key=forge.pkcs5.pbkdf2(service.passphrase,salt,service.keyGenIters,service.keySize,"sha256");service.aesKeys[project]=key}},service.decryptBase=function(project,data,isBinary){if(""===service.passphrase)return AlertSvc.msgAlert("error","No passphrase found"),data;var iv,key,salt,buffer,data64=data.replace(/-/g,"/"),binary=forge.util.decode64(data64),input=forge.util.createBuffer(binary,"raw");if(project&&project in service.aesKeys){salt=input.getBytes(12),buffer=forge.util.createBuffer(salt);for(var i=0;4>i;i++)buffer.putByte(0);iv=buffer.getBytes(service.ivSize),key=service.aesKeys[project]}else{var prefix=input.getBytes(8);if(prefix!=service.opensslPrefix)return AlertSvc.msgAlert("error","Data not in openssl format"),null;salt=input.getBytes(8);var derivedBytes=forge.pbe.opensslDeriveBytes(service.passphrase,salt,service.keySize+service.ivSize);buffer=forge.util.createBuffer(derivedBytes),key=buffer.getBytes(service.keySize),iv=buffer.getBytes(service.ivSize)}var decipher=forge.cipher.createDecipher("AES-CTR",key);decipher.start({iv:iv}),decipher.update(input);var result=decipher.finish(),output="";return result?output=isBinary?decipher.output.getBytes():decipher.output.toString():AlertSvc.msgAlert("error","Decryption failed"),output},service.decrypt=function(project,data,isBinary){if(""===service.passphrase)return AlertSvc.msgAlert("error","No passphrase found"),data;var plain=null;try{plain=service.decryptBase(project,data,isBinary)}catch(e){return null}return plain&&0!==plain.length?plain:null},service.encryptBase=function(project,data){if(""===service.passphrase)return AlertSvc.msgAlert("error","No passphrase found"),data;var key,iv,salt,buffer,openssl;if(project&&project in service.aesKeys){salt=forge.random.getBytesSync(12),buffer=forge.util.createBuffer(salt);for(var i=0;4>i;i++)buffer.putByte(0);iv=buffer.getBytes(service.ivSize),key=service.aesKeys[project],openssl=!1}else{salt=forge.random.getBytesSync(8);var derivedBytes=forge.pbe.opensslDeriveBytes(service.passphrase,salt,service.keySize+service.ivSize);buffer=forge.util.createBuffer(derivedBytes),key=buffer.getBytes(service.keySize),iv=buffer.getBytes(service.ivSize),openssl=!0}var input=forge.util.createBuffer(data,"binary"),cipher=forge.cipher.createCipher("AES-CTR",key);cipher.start({iv:iv}),cipher.update(input),cipher.finish();var ciphertext=cipher.output.getBytes();buffer=forge.util.createBuffer(),openssl&&buffer.putBytes(service.opensslPrefix),buffer.putBytes(salt),buffer.putBytes(ciphertext);var data64=forge.util.encode64(buffer.getBytes()),output=data64.replace(/\//g,"-");return output},service.encrypt=function(project,data){var cipher;if(""===service.passphrase)return AlertSvc.msgAlert("error","No passphrase found"),data;try{cipher=service.encryptBase(project,data)}catch(e){return null}return cipher&&0!==cipher.length?cipher:null},service.hmac=function(data){var hmac1=forge.hmac.create();return hmac1.start("sha256",service.passphrase),hmac1.update(data),hmac1.digest().toHex()},service.isEncrypted=function(){return service.encrypted},service.toBase64=function(data){return forge.util.encode64(data)},service.init(),service}]),angular.module("settingsMod").factory("SettingsSvc",["$resource",function($resource){var service={};return service.credentials=$resource("settings-xhr/:group",{},{get:{method:"GET",params:{group:"apiCredentials"}},save:{method:"POST",params:{group:"apiCredentials"}}}),service.address=$resource("settings-xhr/:group",{},{get:{method:"GET",params:{group:"address"}},save:{method:"POST",params:{group:"address"}}}),service.pw=$resource("settings-xhr/:group",{},{save:{method:"POST",params:{group:"password"}}}),service.fromShares=$resource("settings-xhr/:group",{},{get:{method:"GET",params:{group:"fromShares"}},save:{method:"POST",params:{group:"fromShares"}},remove:{method:"PUT",params:{group:"fromShares"}}}),service.other=$resource("settings-xhr/:group",{},{get:{method:"GET",params:{group:"other"}},save:{method:"POST",params:{group:"other"}}}),service}]),angular.module("tmplMod").service("TmplSvc",["$http","$resource",function($http,$resource){var baseUrl="/templates/",locationUrl=function(project,jobid,location){return baseUrl+"location/"+encodeURIComponent(project)+"/"+jobid+"/"+encodeURIComponent(location)},filesUrl=baseUrl+"files",filesSharedUrl=function(project,jobid,location){return filesUrl+"/share/"+encodeURIComponent(project)+"/"+jobid+"/"+encodeURIComponent(location)},listUrl=baseUrl+"list",listSharedUrl=function(project,jobid,location){return listUrl+"/share/"+encodeURIComponent(project)+"/"+jobid+"/"+encodeURIComponent(location)},defaultsUrl=baseUrl+"defaults",defaultsSharedUrl=function(project,jobid,location){return defaultsUrl+"/share/"+encodeURIComponent(project)+"/"+jobid+"/"+encodeURIComponent(location)},deleteUrl=function(key){return filesUrl+"/"+key};this.isShared=function(project){return project.indexOf("~")>0},this.isEncrypted=function(key,project,jobId,location){var url=filesUrl+"/"+key;return project&&this.isShared(project)&&(url=filesSharedUrl(project,jobId,location)+"/"+key),$http.get(url,{transformResponse:angular.identity})},this.locationTmpl=function(project,jobId,location){var url=locationUrl(project,jobId,location);return $resource(url,{},{get:{method:"GET"},save:{method:"PUT"}})},this.fileUpload=function(key,file,encrypted){var fd=new FormData;return fd.append("file",file),fd.append("encrypted",encrypted),fd.append("file_key",key),$http.post(filesUrl,fd,{transformRequest:angular.identity,headers:{"Content-Type":void 0}})},this.fileDownload=function(key,project,jobId,location){var url=filesUrl+"/"+key+"/contents";return project&&this.isShared(project)&&(url=filesSharedUrl(project,jobId,location)+"/"+key+"/contents"),$http.get(url,{transformResponse:angular.identity})},this.fileDownloadDefault=function(key){var url=filesUrl+"/global/"+key+"/contents";return $http.get(url,{transformResponse:angular.identity})},this.userDefaults=function(project,jobId,location){var url=defaultsUrl;return project&&this.isShared(project)&&(url=defaultsSharedUrl(project,jobId,location)),$resource(url,{},{get:{method:"GET"},save:{method:"PUT"}})},this.listTmpl=function(project,jobId,location){var url=listUrl;return project&&this.isShared(project)&&(url=listSharedUrl(project,jobId,location)),$resource(url,{},{get:{method:"GET"}})},this.deleteTmpl=function(name){return $resource(deleteUrl(name),{},{"delete":{method:"DELETE"}})}}]);var adminApp=angular.module("adminMod"),adminCtrl;adminApp.config(["$routeProvider",function($routeProvider){$routeProvider.when("/admin",{templateUrl:"modules/views/admin/src/admin.client.view.html",controller:"adminCtrl",resolve:{authCheck:adminCtrl.authCheck}})}]);var adminCtrl=adminApp.controller("adminCtrl",["$scope","AdminSvc","AlertSvc","AuthSvc",function($scope,AdminSvc,AlertSvc,AuthSvc){$scope.getUsers=function(){AdminSvc.userGet(function(data){$scope.users=data.users},function(res){AuthSvc.alertPostRoute(res)})},$scope.getUser=function(user){AdminSvc.userGet({uid:user.uid},function(data){$scope.user=data.user},function(res){AuthSvc.alertPostRoute(res)})},$scope.updateUser=function(){var params={confirmed:$scope.user.confirmed,enabled:$scope.user.enabled};$scope.pw.length>0&&(params.password=$scope.pw),AdminSvc.userPut({uid:$scope.user.uid},params,function(data){$scope.user={},$scope.pw=""},function(res){AuthSvc.alertPostRoute(res)})},$scope.regUser=function(){if(0===$scope.newUser.email.length)return void AlertSvc.msgAlert("warning","Missing required email");if(0===$scope.newUser.pw.length)return void AlertSvc.msgAlert("warning","Missing required password");var params={name:$scope.newUser.name,company:$scope.newUser.company,email:$scope.newUser.email,password:$scope.newUser.pw};AdminSvc.userCreate(params,function(data){$scope.newUser={}},function(res){AuthSvc.alertPostRoute(res)})},$scope.deleteUser=function(user){AlertSvc.confirm('Delete user "'+$scope.deleteUid+'"?')&&AdminSvc.userDelete({uid:$scope.deleteUid},function(data){$scope.deleteUid=""},function(res){$scope.deleteUid="",AuthSvc.alertPostRoute(res)})},$scope.sendMail=function(){AdminSvc.sendMail({msg:$scope.msg},function(data){$scope.msg=""},function(res){AuthSvc.alertPostRoute(res)})},$scope.updateOptions=function(){AdminSvc.optionsPut({options:$scope.options},function(data){$scope.options=data.options},function(res){AuthSvc.alertPostRoute(res)})},$scope.getOptions=function(){AdminSvc.optionsGet(function(data){$scope.options=data.options},function(res){AuthSvc.alertPostRoute(res)})},$scope.init=function(){$scope.user={},$scope.pw="",$scope.newUser={},$scope.getUsers(),$scope.getOptions()},$scope.init()}]);adminCtrl.authCheck=["AuthSvc","AlertSvc",function(AuthSvc,AlertSvc){return AuthSvc.checkAtRoute()}],angular.module("contentMod").config(["$routeProvider",function($routeProvider){$routeProvider.when("/content/:projectDisplay/:jobId/:locationDisplay/:msgId/:projectResource?/:locationResource?",{templateUrl:"modules/views/content/src/content.client.view.html",controller:"contentCtrl"})}]).controller("contentCtrl",["$scope","$routeParams","ApiSvc","TmplSvc","AlertSvc","AuthSvc","CryptoSvc","$q",function($scope,$routeParams,ApiSvc,TmplSvc,AlertSvc,AuthSvc,CryptoSvc,$q){$scope.projectDisplay=$routeParams.projectDisplay,$routeParams.projectResource&&$routeParams.projectResource!=$scope.projectDisplay?($scope.projectDecrypt=!0,$scope.projectResource=$routeParams.projectResource,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=encodeURIComponent($routeParams.projectResource),$scope.locationDisplay=$routeParams.locationDisplay,$scope.locationResource=$routeParams.locationResource,$scope.locationDisplayURI=encodeURIComponent($routeParams.locationDisplay),$scope.locationResourceURI=encodeURIComponent($routeParams.locationResource)):($scope.projectDecrypt=!1,$scope.projectResource=$scope.projectDisplay,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=$scope.projectDisplayURI,$scope.locationDisplay=$routeParams.locationDisplay,$scope.locationResource=$scope.locationDisplay,$scope.locationDisplayURI=encodeURIComponent($routeParams.locationDisplay),$scope.locationResourceURI=$scope.locationDisplayURI),$scope.jobId=$routeParams.jobId,$scope.msg=$routeParams.msgId,$scope.error=function(res){AuthSvc.alertPostRoute(res),$scope.clicked=!1},$scope.getTemplate=function(project,jobId,location,key){return TmplSvc.fileDownload(key,project,jobId,location)},$scope.getDefaultTemplate=function(key){return TmplSvc.fileDownloadDefault(key)},$scope.encryptedTemplate=function(project,jobId,location,key){return TmplSvc.isEncrypted(key,project,jobId,location)},$scope.getFiles=function(){ApiSvc.resource.filesGet({project:$scope.projectResource,job:$scope.jobId,location:$scope.locationResource,msg:$scope.msg},function(data){for(var i=0;i<data.file_keys.length;i++)ApiSvc.fileGet($scope.projectResource,$scope.jobId,$scope.locationResource,$scope.msg,encodeURIComponent(data.file_keys[i])).then(function(idx){return function(res){var obj;if(200==res.status)if($scope.projectDecrypt){var key=CryptoSvc.decrypt($scope.projectResource,data.file_keys[idx]),fdata=null,type=data.file_types[idx];if("image/png"==type){var binary=CryptoSvc.decrypt($scope.projectResource,res.data,!0);fdata=CryptoSvc.toBase64(binary)}else fdata=CryptoSvc.decrypt($scope.projectResource,res.data);key&&fdata?(obj={key:key,type:type,data:fdata},$scope.files.push(obj)):AlertSvc.msgAlert("warning","Failed to decrypt file item with current passphrase")}else obj={key:data.file_keys[idx],type:data.file_types[idx],data:res.data},$scope.files.push(obj);else $scope.error(res)}}(i),function(err){$scope.error(err)})},$scope.error)},$scope.load=function(){ApiSvc.resource.msgGet({project:$scope.projectResource,job:$scope.jobId,location:$scope.locationResource,msg:$scope.msg},function(data){var errCount,entry,content=angular.fromJson(data.content);if($scope.projectDecrypt){var contentNew=[];errCount=0;for(var i=0;i<content.length;i++)entry=content[i],entry.name=CryptoSvc.decrypt($scope.projectResource,entry.name),entry.value=CryptoSvc.decrypt($scope.projectResource,entry.value),entry.name&&entry.value?contentNew.push(entry):errCount+=1;errCount>0&&AlertSvc.msgAlert("warning","Failed to decrypt "+errCount+" content items with current passphrase"),content=contentNew}if($scope.content=content,$scope.isReply=data.is_reply,$scope.timestamp=data.timestamp,$scope.isReply){var replyContent=angular.fromJson(data.reply_content);if($scope.projectDecrypt){var replyNew=[],concat="";errCount=0;for(var j=(replyContent.length,0);j<replyContent.length-1;j++)entry=replyContent[j],concat+=entry.name+entry.value,entry.name=CryptoSvc.decrypt($scope.projectResource,entry.name),entry.value=CryptoSvc.decrypt($scope.projectResource,entry.value),entry.name&&entry.value?replyNew.push(entry):errCount+=1;if(errCount>0&&AlertSvc.msgAlert("warning","Failed to decrypt "+errCount+" reply items with current passphrase"),!data.reply_done){var hmac=CryptoSvc.hmac(concat);entry=replyContent[replyContent.length-1],hmac!=entry.value&&AlertSvc.msgAlert("warning","Failed to authenticate message content with current passphrase"),$scope.clicked=!1}replyContent=replyNew}$scope.replyContent=replyContent,$scope.replyContentSave=angular.copy($scope.replyContent),$scope.replyDone=data.reply_done,$scope.replyAck=data.reply_ack}$scope.files=[],$scope.getFiles()},$scope.error)},$scope.reply=function(){if($scope.isEncrypted&&!$scope.projectDecrypt)return void AlertSvc.msgAlert("warning","Project is not decrypted");$scope.clicked=!0;var replyContent=$scope.replyContent;if($scope.projectDecrypt){for(var entry,replyNew=[],errCount=0,concat="",i=0;i<$scope.replyContent.length;i++)entry=$scope.replyContent[i],entry.name=CryptoSvc.encrypt($scope.projectResource,entry.name),entry.value=CryptoSvc.encrypt($scope.projectResource,entry.value),entry.name&&entry.value?(replyNew.push(entry),concat+=entry.name+entry.value):errCount+=1;if(errCount>0)return AlertSvc.msgAlert("warning","Failed to encrypt "+errCount+" reply items with current passphrase"),void($scope.clicked=!1);if(replyNew.length>0){var auth=CryptoSvc.hmac(concat);entry={name:"hmac",value:auth},replyNew.push(entry)}replyContent=replyNew}ApiSvc.resource.msgPut({project:$scope.projectResource,job:$scope.jobId,location:$scope.locationResource,msg:$scope.msg},{reply_content:angular.toJson(replyContent)},$scope.reload,$scope.error)},$scope.restore=function(){$scope.replyContent=angular.copy($scope.replyContentSave),AlertSvc.msgAlert("warning","Reply already sent")},$scope.reload=function(){$scope.replyContentSave=angular.copy($scope.replyContent),$scope.load()},TmplSvc.locationTmpl($scope.projectResource,$scope.jobId,$scope.locationResource).get(function(data){for(var promises1=[],i=0;i<data.templates.length;i++)promises1.push($scope.encryptedTemplate($scope.projectResource,$scope.jobId,$scope.locationResource,data.templates[i]));$q.all(promises1).then(function(resArray1){for(var encrypted=[],promises2=[],j=0;j<resArray1.length;j++)encrypted.push(angular.fromJson(resArray1[j].data).encrypted),encrypted[j]&&!CryptoSvc.isEncrypted()?(0===j?promises2.push($scope.getDefaultTemplate("simplecontent")):promises2.push($scope.getDefaultTemplate("simplereply")),AlertSvc.msgAlert("warning","Template is encrypted but no passphrase is set - using default template")):promises2.push($scope.getTemplate($scope.projectResource,$scope.jobId,$scope.locationResource,data.templates[j]));$q.all(promises2).then(function(resArray2){encrypted[0]&&CryptoSvc.isEncrypted()?($scope.contentTmpl=CryptoSvc.decrypt(null,resArray2[0].data),null===$scope.contentTmpl&&AlertSvc.msgAlert("warning","Failed to decrypt template with current passphrase")):$scope.contentTmpl=resArray2[0].data,encrypted[1]&&CryptoSvc.isEncrypted()?($scope.replyTmpl=CryptoSvc.decrypt(null,resArray2[1].data),null===$scope.replyTmpl&&AlertSvc.msgAlert("warning","Failed to decrypt template with current passphrase")):$scope.replyTmpl=resArray2[1].data,$scope.load(),ApiSvc.resource.projectGet({project:$scope.projectResource},function(data){$scope.isEncrypted=data.encrypted},function(res){AuthSvc.alertPostRoute(res)})},function(err){$scope.error(err)})},function(err){$scope.error(err)})},function(res){AuthSvc.alertPostRoute(res)})}]),angular.module("contentMod").directive("dynamic",function($compile){return{restrict:"A",replace:!0,link:function(scope,elem,attrs){scope.$watch(attrs.dynamic,function(html){elem.html(html),$compile(elem.contents())(scope)})}}}),angular.module("footerMod").controller("footerCtrl",["$scope","$window",function($scope,$window){$scope.version=$window.appVersion}]),angular.module("headerMod").controller("headerCtrl",["$scope","AuthSvc",function($scope,AuthSvc){$scope.currentUser=AuthSvc.data,AuthSvc.checkAtStart()}]),angular.module("homeMod").config(["$routeProvider",function($routeProvider){$routeProvider.when("/home",{templateUrl:"modules/views/home/src/home.client.view.html",controller:"homeCtrl"})}]).controller("homeCtrl",[function(){}]);var jobSettingsApp=angular.module("jobSettingsMod"),jobSettingsCtrl;jobSettingsApp.config(["$routeProvider",function($routeProvider){$routeProvider.when("/job-settings/:projectDisplay/:jobId/:projectResource?",{templateUrl:"modules/views/job-settings/src/job-settings.client.view.html",controller:"jobSettingsCtrl",resolve:{authCheck:jobSettingsCtrl.authCheck}})}]);var jobSettingsCtrl=jobSettingsApp.controller("jobSettingsCtrl",["$scope","$routeParams","AlertSvc","AuthSvc","ApiSvc","CryptoSvc",function($scope,$routeParams,AlertSvc,AuthSvc,ApiSvc,CryptoSvc){$scope.init=function(){$scope.projectDisplay=$routeParams.projectDisplay,$routeParams.projectResource&&$routeParams.projectResource!=$scope.projectDisplay?($scope.projectDecrypt=!0,$scope.projectResource=$routeParams.projectResource,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=encodeURIComponent($routeParams.projectResource)):($scope.projectDecrypt=!1,$scope.projectResource=$scope.projectDisplay,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=$scope.projectDisplayURI),$scope.jobId=$routeParams.jobId,ApiSvc.resource.projectGet({project:$scope.projectResource},function(data){$scope.isEncrypted=data.encrypted},function(res){AuthSvc.alertPostRoute(res)})},$scope.submitDescription=function(){if($scope.isEncrypted&&!$scope.projectDecrypt)return void($scope.description="Project is not decrypted");var description=$scope.description;$scope.projectDecrypt&&(description=CryptoSvc.encrypt($scope.projectResource,$scope.description)),ApiSvc.resource.jobDescPut({project:$scope.projectResource,job:$scope.jobId},{description:description},function(data){$scope.description=null},function(res){AuthSvc.alertPostRoute(res)})},$scope.init()}]);jobSettingsCtrl.authCheck=["AuthSvc","AlertSvc",function(AuthSvc,AlertSvc){return AuthSvc.checkAtRoute()}],angular.module("jobsMod").config(["$routeProvider",function($routeProvider){$routeProvider.when("/jobs/:projectDisplay/:projectResource?",{templateUrl:"modules/views/jobs/src/jobs.client.view.html",controller:"jobsCtrl"})}]).controller("jobsCtrl",["$scope","$location","$routeParams","ApiSvc","AlertSvc","AuthSvc","CryptoSvc",function($scope,$location,$routeParams,ApiSvc,AlertSvc,AuthSvc,CryptoSvc){$scope.init=function(){$scope.projectDisplay=$routeParams.projectDisplay,$routeParams.projectResource&&$routeParams.projectResource!=$scope.projectDisplay?($scope.projectDecrypt=!0,$scope.projectResource=$routeParams.projectResource,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=encodeURIComponent($routeParams.projectResource)):($scope.projectDecrypt=!1,$scope.projectResource=$scope.projectDisplay,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=$scope.projectDisplayURI),ApiSvc.resource.projectGet({project:$scope.projectResource},function(data){var name='"'+$scope.projectDisplay+'"';$scope.projectDisplay!=$scope.projectResource&&(name+=' (Encrypted: "'+$scope.projectResource+'")');var info="Project: "+name+" Created: "+data.timestamp+" Owner: "+data.owner,description=data.description;$scope.projectDecrypt&&""!==description&&(description=CryptoSvc.decrypt($scope.projectResource,data.description)),$scope.bcinfo={visible:!1,"static":info,description:description},$scope.bcfct={configure:$scope.configure,"delete":$scope["delete"]},ApiSvc.resource.jobGet({project:$scope.projectResource},function(data){var jobs=data.jobs;if($scope.projectDecrypt){jobs=[];for(var errCount=0,i=0;i<data.jobs.length;i++){var job=data.jobs[i],plain=CryptoSvc.decrypt($scope.projectResource,job.name);plain?(job.name=plain,jobs.push(job)):errCount+=1}errCount>0&&AlertSvc.msgAlert("warning","Failed to decrypt "+errCount+" jobs with current passphrase")}$scope.jobs=jobs},function(res){AuthSvc.alertPostRoute(res)})},function(res){AuthSvc.alertPostRoute(res)})},$scope.select=function(jobId){$scope.projectDecrypt?$location.path("/locations/"+$scope.projectDisplay+"/"+jobId+"/"+$scope.projectResource):$location.path("/locations/"+$scope.projectDisplay+"/"+jobId)},$scope.configure=function(){$scope.projectDecrypt?$location.path("/project-settings/"+$scope.projectDisplay+"/"+$scope.projectResource):$location.path("/project-settings/"+$scope.projectDisplay)},$scope["delete"]=function($event){$event&&$event.stopPropagation(),AlertSvc.confirm('Delete project "'+$scope.projectDisplay+'"?')&&ApiSvc.resource.projectDelete({ project:$scope.projectResource},function(){$location.path("/projects")},function(res){AuthSvc.alertPostRoute(res)})},$scope.init()}]),angular.module("templatesSelectMod").config(["$routeProvider",function($routeProvider){$routeProvider.when("/templates-select/:projectDisplay/:jobId/:locationDisplay/:projectResource?/:locationResource?",{templateUrl:"modules/views/location-settings/src/location-settings.client.view.html",controller:"templatesSelectCtrl"})}]).controller("templatesSelectCtrl",["$scope","$routeParams","TmplSvc","ApiSvc","AlertSvc","AuthSvc","CryptoSvc",function($scope,$routeParams,TmplSvc,ApiSvc,AlertSvc,AuthSvc,CryptoSvc){$scope.project=$routeParams.project,$scope.jobId=$routeParams.jobId,$scope.location=$routeParams.location,$scope.init=function(){$scope.projectDisplay=$routeParams.projectDisplay,$routeParams.projectResource&&$routeParams.projectResource!=$scope.projectDisplay?($scope.projectDecrypt=!0,$scope.projectResource=$routeParams.projectResource,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=encodeURIComponent($routeParams.projectResource),$scope.locationDisplay=$routeParams.locationDisplay,$scope.locationResource=$routeParams.locationResource,$scope.locationDisplayURI=encodeURIComponent($routeParams.locationDisplay),$scope.locationResourceURI=encodeURIComponent($routeParams.locationResource)):($scope.projectDecrypt=!1,$scope.projectResource=$scope.projectDisplay,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=$scope.projectDisplayURI,$scope.locationDisplay=$routeParams.locationDisplay,$scope.locationResource=$scope.locationDisplay,$scope.locationDisplayURI=encodeURIComponent($routeParams.locationDisplay),$scope.locationResourceURI=$scope.locationDisplayURI),$scope.jobId=$routeParams.jobId,$scope.templates=[],$scope.locationTemplates=[],TmplSvc.listTmpl($scope.projectResource,$scope.jobId,$scope.locationResource).get(function(data){if(data.file_keys){for(var i=0;i<data.file_keys.length;i++)$scope.templates.push({name:data.file_keys[i]});TmplSvc.locationTmpl($scope.projectResource,$scope.jobId,$scope.locationResource).get(function(data1){for(var i=0;2>i;i++)$scope.locationTemplates.push(null);for(i=0;2>i;i++)for(var j=0;j<$scope.templates.length;j++)data1.templates[i]==$scope.templates[j].name&&($scope.locationTemplates[i]=$scope.templates[j]);ApiSvc.resource.projectGet({project:$scope.projectResource},function(data2){$scope.isEncrypted=data2.encrypted},function(res){AuthSvc.alertPostRoute(res)})},function(res){AuthSvc.alertPostRoute(res)})}},function(res){AuthSvc.alertPostRoute(res)})},$scope.submitDescription=function(){if(!$scope.isEncrypted||$scope.projectDecrypt){var description=$scope.description;$scope.projectDecrypt&&(description=CryptoSvc.encrypt($scope.projectResource,$scope.description)),ApiSvc.resource.locationDescPut({project:$scope.projectResource,job:$scope.jobId,location:$scope.locationResource},{description:description},function(data){$scope.description=null},function(res){AuthSvc.alertPostRoute(res)})}},$scope.save=function(){for(var tmplNames=[],i=0;i<$scope.locationTemplates.length;i++)tmplNames.push($scope.locationTemplates[i].name);TmplSvc.locationTmpl($scope.projectResource,$scope.jobId,$scope.locationResource).save({templates:tmplNames},$scope.init,function(res){AuthSvc.alertPostRoute(res)})},$scope.init()}]),angular.module("locationsMod").config(["$routeProvider",function($routeProvider){$routeProvider.when("/locations/:projectDisplay/:jobId/:projectResource?",{templateUrl:"modules/views/locations/src/locations.client.view.html",controller:"locationsCtrl"})}]).controller("locationsCtrl",["$scope","$location","$routeParams","ApiSvc","AlertSvc","AuthSvc","CryptoSvc",function($scope,$location,$routeParams,ApiSvc,AlertSvc,AuthSvc,CryptoSvc){$scope.init=function(){$scope.projectDisplay=$routeParams.projectDisplay,$routeParams.projectResource&&$routeParams.projectResource!=$scope.projectDisplay?($scope.projectDecrypt=!0,$scope.projectResource=$routeParams.projectResource,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=encodeURIComponent($routeParams.projectResource)):($scope.projectDecrypt=!1,$scope.projectResource=$scope.projectDisplay,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=$scope.projectDisplayURI),$scope.jobId=$routeParams.jobId,$scope.locsCrypto={},ApiSvc.resource.jobGet({project:$scope.projectResource,job:$scope.jobId},function(data){var info='Job: "'+$scope.jobId+'"\nCreated: '+data.timestamp;data.ended&&(info+="\nEnded: "+data.timeStampEnd),info+="\nmax-msgs="+data.max_msgs+"\ntoken="+data.token;var description=data.description;$scope.projectDecrypt&&""!==description&&(description=CryptoSvc.decrypt($scope.projectResource,data.description)),$scope.bcinfo={visible:!1,"static":info,description:description},$scope.bcfct={configure:$scope.configure,"delete":$scope["delete"]},ApiSvc.resource.locationGet({project:$scope.projectResource,job:$scope.jobId},function(data){var locs=data.locations;if($scope.projectDecrypt){locs=[];for(var errCount=0,i=0;i<data.locations.length;i++){var plain=data.locations[i].name;if("End"==data.locations[i].name||(plain=CryptoSvc.decrypt($scope.projectResource,data.locations[i].name))){$scope.locsCrypto[plain]=data.locations[i].name;var loc=data.locations[i];loc.name=plain,locs.push(loc)}else errCount+=1}errCount>0&&AlertSvc.msgAlert("warning","Failed to decrypt "+errCount+" locations with current passphrase")}$scope.locations=locs},function(res){AuthSvc.alertPostRoute(res)})},function(res){AuthSvc.alertPostRoute(res)})},$scope.select=function(locDisplay){if($scope.projectDecrypt){var locResource=$scope.locsCrypto[locDisplay];$location.path("/msgs/"+$scope.projectDisplay+"/"+$scope.jobId+"/"+locDisplay+"/"+$scope.projectResource+"/"+locResource)}else $location.path("/msgs/"+$scope.projectDisplay+"/"+$scope.jobId+"/"+locDisplay)},$scope.configure=function(){$scope.projectDecrypt?$location.path("/job-settings/"+$scope.projectDisplay+"/"+$scope.jobId+"/"+$scope.projectResource):$location.path("/job-settings/"+$scope.projectDisplay+"/"+$scope.jobId)},$scope["delete"]=function(){AlertSvc.confirm('Delete job "'+$scope.jobId+'"?')&&ApiSvc.resource.jobDelete({project:$scope.projectResource,job:$scope.jobId},function(){$scope.projectDecrypt?$location.path("/jobs/"+$scope.projectDisplay+"/"+$scope.projectResource):$location.path("/jobs/"+$scope.projectDisplay)},function(res){AuthSvc.alertPostRoute(res)})},$scope.init()}]),angular.module("msgsMod").config(["$routeProvider",function($routeProvider){$routeProvider.when("/msgs/:projectDisplay/:jobId/:locationDisplay/:projectResource?/:locationResource?",{templateUrl:"modules/views/messages/src/messages.client.view.html",controller:"msgsCtrl"})}]).controller("msgsCtrl",["$scope","$location","$routeParams","ApiSvc","AlertSvc","AuthSvc","CryptoSvc",function($scope,$location,$routeParams,ApiSvc,AlertSvc,AuthSvc,CryptoSvc){$scope.init=function(){$scope.projectDisplay=$routeParams.projectDisplay,$routeParams.projectResource&&$routeParams.projectResource!=$scope.projectDisplay?($scope.projectDecrypt=!0,$scope.projectResource=$routeParams.projectResource,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=encodeURIComponent($routeParams.projectResource),$scope.locationDisplay=$routeParams.locationDisplay,$scope.locationResource=$routeParams.locationResource,$scope.locationDisplayURI=encodeURIComponent($routeParams.locationDisplay),$scope.locationResourceURI=encodeURIComponent($routeParams.locationResource)):($scope.projectDecrypt=!1,$scope.projectResource=$scope.projectDisplay,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=$scope.projectDisplayURI,$scope.locationDisplay=$routeParams.locationDisplay,$scope.locationResource=$scope.locationDisplay,$scope.locationDisplayURI=encodeURIComponent($routeParams.locationDisplay),$scope.locationResourceURI=$scope.locationDisplayURI),$scope.jobId=$routeParams.jobId,ApiSvc.resource.locationGet({project:$scope.projectResource,job:$scope.jobId,location:$scope.locationResource},function(data){var info='Location: "'+$scope.locationDisplay+'"\nCreated: '+data.timestamp+"\nmsg-cnt="+data.msgcnt,description=data.description;$scope.projectDecrypt&&(description=CryptoSvc.decrypt($scope.projectResource,data.description)),$scope.bcinfo={visible:!1,"static":info,description:description},$scope.bcfct={configure:$scope.configure},ApiSvc.resource.msgGet({project:$scope.projectResource,job:$scope.jobId,location:$scope.locationResource},function(data){$scope.msgs=data.messages},function(res){AuthSvc.alertPostRoute(res)})},function(res){AuthSvc.alertPostRoute(res)})},$scope.select=function(msgId){$scope.projectDecrypt?$location.path("/content/"+$scope.projectDisplay+"/"+$scope.jobId+"/"+$scope.locationDisplay+"/"+msgId+"/"+$scope.projectResource+"/"+$scope.locationResource):$location.path("/content/"+$scope.projectDisplay+"/"+$scope.jobId+"/"+$scope.locationDisplay+"/"+msgId)},$scope.configure=function(){$scope.projectDecrypt?$location.path("/templates-select/"+$scope.projectDisplay+"/"+$scope.jobId+"/"+$scope.locationDisplay+"/"+$scope.projectResource+"/"+$scope.locationResource):$location.path("/templates-select/"+$scope.projectDisplay+"/"+$scope.jobId+"/"+$scope.locationDisplay)},$scope.init()}]);var templatesAddApp=angular.module("templatesAddMod"),templatesAddCtrl;templatesAddApp.config(["$routeProvider",function($routeProvider){$routeProvider.when("/templates-add",{templateUrl:"modules/views/ng-templates/src/ng-templates.client.view.html",controller:"TemplatesAddCtrl",resolve:{authCheck:templatesAddCtrl.authCheck}})}]);var templatesAddCtrl=templatesAddApp.controller("TemplatesAddCtrl",["$scope","$routeParams","TmplSvc","AlertSvc","AuthSvc","CryptoSvc",function($scope,$routeParams,TmplSvc,AlertSvc,AuthSvc,CryptoSvc){$scope.init=function(){$scope.visible=[],$scope.templates=[],$scope.isEncrypted=[],$scope.defaultTemplates=[],$scope.key="",$scope.file="",TmplSvc.listTmpl().get(function(data){if(data.file_keys){for(var i=0;i<data.file_keys.length;i++)$scope.templates.push({name:data.file_keys[i]}),$scope.visible.push(!1),$scope.isEncrypted.push(data.encrypted[i]);TmplSvc.userDefaults().get(function(data){for(var i=0;2>i;i++)$scope.defaultTemplates.push(null);for(i=0;2>i;i++)for(var j=0;j<$scope.templates.length;j++)data.defaults[i]==$scope.templates[j].name&&($scope.defaultTemplates[i]=$scope.templates[j])},function(res){AuthSvc.alertPostRoute(res)})}},function(res){AuthSvc.alertPostRoute(res)})},$scope.show=function(index){$scope.templates[index].content?$scope.visible[index]=!0:TmplSvc.fileDownload($scope.templates[index].name).then(function(res){if(200==res.status){var contents=res.data;if($scope.isEncrypted[index]){if(!CryptoSvc.isEncrypted())return void AlertSvc.msgAlert("warning","Template is encrypted but no passphrase is set");contents=CryptoSvc.decrypt(null,res.data,!1)}$scope.templates[index].content=contents,$scope.visible[index]=!0}else AuthSvc.alertPostRoute(res)},function(res){AuthSvc.alertPostRoute(res)})},$scope.hide=function(index){$scope.visible[index]=!1},$scope.upload=function(){if($scope.key&&$scope.file){for(var j=0;j<$scope.templates.length;j++)if($scope.key==$scope.templates[j].name)return void AlertSvc.msgAlert("warning","A template with that name already exists");var fileSpec,encryptedFile;if(CryptoSvc.isEncrypted()){var fr=new FileReader;fr.onload=function(event){var cipher=CryptoSvc.encrypt(null,fr.result);fileSpec=new Blob([cipher]),encryptedFile=!0,TmplSvc.fileUpload($scope.key,fileSpec,encryptedFile).then($scope.init,function(res){AuthSvc.alertPostRoute(res)})},fr.onerror=function(event){AlertSvc.msgAlert("warning","Unable to upload file")},fr.readAsText($scope.file)}else fileSpec=$scope.file,encryptedFile=!1,TmplSvc.fileUpload($scope.key,fileSpec,encryptedFile).then($scope.init,function(res){AuthSvc.alertPostRoute(res)})}},$scope["delete"]=function(index){TmplSvc.deleteTmpl($scope.templates[index].name)["delete"]($scope.init,function(res){AuthSvc.alertPostRoute(res)})},$scope.save=function(){for(var defaultNames=[],i=0;i<$scope.defaultTemplates.length;i++)defaultNames.push($scope.defaultTemplates[i].name);TmplSvc.userDefaults().save({defaults:defaultNames},$scope.init,function(res){AuthSvc.alertPostRoute(res)})},$scope.init()}]),templatesAddDirective=templatesAddApp.directive("fileModel",["$parse",function($parse){return{restrict:"A",link:function(scope,element,attrs){var model=$parse(attrs.fileModel),modelSetter=model.assign;element.bind("change",function(){scope.$apply(function(){modelSetter(scope,element[0].files[0])})})}}}]);templatesAddCtrl.authCheck=["AuthSvc","AlertSvc",function(AuthSvc,AlertSvc){return AuthSvc.checkAtRoute()}];var projectSettingsApp=angular.module("projectSettingsMod"),projectSettingsCtrl;projectSettingsApp.config(["$routeProvider",function($routeProvider){$routeProvider.when("/project-settings/:projectDisplay/:projectResource?",{templateUrl:"modules/views/project-settings/src/project-settings.client.view.html",controller:"projectSettingsCtrl",resolve:{authCheck:projectSettingsCtrl.authCheck}})}]);var projectSettingsCtrl=projectSettingsApp.controller("projectSettingsCtrl",["$scope","$routeParams","AlertSvc","AuthSvc","ApiSvc","CryptoSvc",function($scope,$routeParams,AlertSvc,AuthSvc,ApiSvc,CryptoSvc){$scope.submitShare=function(){$scope.email&&ApiSvc.resource.sharePut({project:$scope.projectResource},{email:$scope.email,access:$scope.access,action:"add"},function(data){$scope.email=null,$scope.init()},function(res){AuthSvc.alertPostRoute(res)})},$scope.deleteShare=function(index){ApiSvc.resource.sharePut({project:$scope.projectResource},{email:$scope.authUsers[index].email,action:"remove"},function(data){$scope.email=null,$scope.init()},function(res){AuthSvc.alertPostRoute(res)})},$scope.submitDescription=function(){if($scope.isEncrypted&&!$scope.projectDecrypt)return void($scope.description="Project is not decrypted");var description=$scope.description;$scope.projectDecrypt&&(description=CryptoSvc.encrypt($scope.projectResource,$scope.description)),ApiSvc.resource.projectDescPut({project:$scope.projectResource},{description:description},function(data){$scope.description=null},function(res){AuthSvc.alertPostRoute(res)})},$scope.submitNotify=function(){$scope.nickname;ApiSvc.resource.notifyPut({project:$scope.projectResource},{nickname:$scope.nickname,action:$scope.notify},function(data){$scope.nickname=null,$scope.notify="off",$scope.init()},function(res){AuthSvc.alertPostRoute(res)})},$scope.init=function(){$scope.projectDisplay=$routeParams.projectDisplay,$routeParams.projectResource?($scope.projectDecrypt=!0,$scope.projectResource=$routeParams.projectResource,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=encodeURIComponent($routeParams.projectResource)):($scope.projectDecrypt=!1,$scope.projectResource=$scope.projectDisplay,$scope.projectDisplayURI=encodeURIComponent($routeParams.projectDisplay),$scope.projectResourceURI=$scope.projectDisplayURI),ApiSvc.resource.projectGet({project:$scope.projectResource},function(data){$scope.authUsers=data.authUsers,$scope.access="write",$scope.isEncrypted=data.encrypted,$scope.notify=data.notify,$scope.nickname=data.nickname},function(res){AuthSvc.alertPostRoute(res)})},$scope.init()}]);projectSettingsCtrl.authCheck=["AuthSvc","AlertSvc",function(AuthSvc,AlertSvc){return AuthSvc.checkAtRoute()}];var projectsApp=angular.module("projectsMod"),projectsCtrl;projectsApp.config(["$routeProvider",function($routeProvider){$routeProvider.when("/projects",{templateUrl:"modules/views/projects/src/projects.client.view.html",controller:"projectsCtrl",resolve:{authCheck:projectsCtrl.authCheck}})}]);var projectsCtrl=projectsApp.controller("projectsCtrl",["$scope","$location","SettingsSvc","ApiSvc","AlertSvc","AuthSvc","CryptoSvc",function($scope,$location,SettingsSvc,ApiSvc,AlertSvc,AuthSvc,CryptoSvc){$scope.init=function(){var separator="~";$scope.projectsCrypto={},$scope.projects=[],ApiSvc.resource.projectGet(function(data1){$scope.projects=[];for(var i=0;i<data1.projects.length;i++){var project=data1.projects[i],projName=project[0],projEncrypted=project[1];if(projEncrypted&&CryptoSvc.isEncrypted()){var salt=project[2];salt&&salt.length>0&&CryptoSvc.computeAESKey(projName,salt);var plain=CryptoSvc.decrypt(projName,projName);plain?$scope.projects.push({display:plain,resource:projName,decrypted:!0}):$scope.projects.push({display:projName,resource:projName,decrypted:!1})}else $scope.projects.push({display:projName,resource:projName,decrypted:!1})}SettingsSvc.fromShares.get(function(data2){if(data2.hasOwnProperty("shares"))for(var i=0;i<data2.shares.length;i++){var share=data2.shares[i],projectPlus=share.project+separator+share.email;if(share.encrypted&&CryptoSvc.isEncrypted()){share.salt&&share.salt.length>0&&CryptoSvc.computeAESKey(projectPlus,share.salt);var plain=CryptoSvc.decrypt(projectPlus,share.project);if(plain){var plainPlus=plain+separator+share.email;$scope.projects.push({display:plainPlus,resource:projectPlus,decrypted:!0}),$scope.projectsCrypto[plainPlus]=projectPlus}else $scope.projects.push({display:projectPlus,resource:projectPlus,decrypted:!1})}else $scope.projects.push({display:projectPlus,resource:projectPlus,decrypted:!1})}},function(res){AuthSvc.alertPostRoute(res)})},function(res){AuthSvc.alertPostRoute(res)})},$scope.select=function(project){project.decrypted?$location.path("/jobs/"+project.display+"/"+project.resource):$location.path("/jobs/"+project.display)},$scope.init()}]);projectsCtrl.authCheck=["AuthSvc","AlertSvc",function(AuthSvc,AlertSvc){return AuthSvc.checkAtRoute()}];var userSettingsApp=angular.mod