diff options
| -rw-r--r-- | package.json | 28 | ||||
| -rw-r--r-- | www/external/js/lz-string.min.js | 1 | ||||
| -rw-r--r-- | www/index.html | 1 | ||||
| -rw-r--r-- | www/js/DevOptionsCtrl.js | 28 | ||||
| -rw-r--r-- | www/js/LoginCtrl.js | 3 | ||||
| -rw-r--r-- | www/js/MonitorCtrl.js | 1 | ||||
| -rw-r--r-- | www/js/NVR.js | 72 | ||||
| -rwxr-xr-x | www/js/app.js | 3 | ||||
| -rw-r--r-- | www/lang/locale-en.json | 2 | ||||
| -rw-r--r-- | www/templates/devoptions.html | 10 |
10 files changed, 121 insertions, 28 deletions
diff --git a/package.json b/package.json index 330b9038..a14c47a4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "zmninjapro", "description": "Home security mobile app for ZoneMinder", - "version":"1.3.086", + "version": "1.3.086", "displayName": "zmNinja", "author": "Pliable Pixels", "license": "custom see LICENSE.md", @@ -67,17 +67,6 @@ "dependencies": { "app-builder-lib": "^22.1.0", "clivas": "^0.2.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.2", - "is-regex": "^1.0.5", - "object-is": "^1.0.2", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.3.0", "cordova-android": "8.0.0", "cordova-custom-config": "^5.1.0", "cordova-ios": "^5.0.1", @@ -112,16 +101,27 @@ "cordova-sqlite-storage": "^1.5.3", "cordova-support-google-services": "^1.1.0", "deep-equal": "^1.0.1", + "define-properties": "^1.1.3", "dialog": "^0.3.1", "electron-window-state": "^4.1.1", + "es-abstract": "^1.17.0", "es6-promise-plugin": "^4.2.2", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.2", + "is-regex": "^1.0.5", "jsonfile": "^4.0.0", "keypress": "^0.2.1", "menu": "^0.2.5", "minimist": "^1.2.0", "mkdirp": "^0.5.1", + "object-is": "^1.0.2", + "object-keys": "^1.1.1", "phonegap-plugin-multidex": "^1.0.0", - "phonegap-plugin-push": "^2.2.3" + "phonegap-plugin-push": "^2.2.3", + "regexp.prototype.flags": "^1.3.0" }, "devDependencies": { "@ionic/v1-toolkit": "^1.0.14", @@ -214,4 +214,4 @@ ] } } -} +}
\ No newline at end of file diff --git a/www/external/js/lz-string.min.js b/www/external/js/lz-string.min.js new file mode 100644 index 00000000..2d1900a0 --- /dev/null +++ b/www/external/js/lz-string.min.js @@ -0,0 +1 @@ +var LZString=function(){function o(o,r){if(!t[o]){t[o]={};for(var n=0;n<o.length;n++)t[o][o.charAt(n)]=n}return t[o][r]}var r=String.fromCharCode,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$",t={},i={compressToBase64:function(o){if(null==o)return"";var r=i._compress(o,6,function(o){return n.charAt(o)});switch(r.length%4){default:case 0:return r;case 1:return r+"===";case 2:return r+"==";case 3:return r+"="}},decompressFromBase64:function(r){return null==r?"":""==r?null:i._decompress(r.length,32,function(e){return o(n,r.charAt(e))})},compressToUTF16:function(o){return null==o?"":i._compress(o,15,function(o){return r(o+32)})+" "},decompressFromUTF16:function(o){return null==o?"":""==o?null:i._decompress(o.length,16384,function(r){return o.charCodeAt(r)-32})},compressToUint8Array:function(o){for(var r=i.compress(o),n=new Uint8Array(2*r.length),e=0,t=r.length;t>e;e++){var s=r.charCodeAt(e);n[2*e]=s>>>8,n[2*e+1]=s%256}return n},decompressFromUint8Array:function(o){if(null===o||void 0===o)return i.decompress(o);for(var n=new Array(o.length/2),e=0,t=n.length;t>e;e++)n[e]=256*o[2*e]+o[2*e+1];var s=[];return n.forEach(function(o){s.push(r(o))}),i.decompress(s.join(""))},compressToEncodedURIComponent:function(o){return null==o?"":i._compress(o,6,function(o){return e.charAt(o)})},decompressFromEncodedURIComponent:function(r){return null==r?"":""==r?null:(r=r.replace(/ /g,"+"),i._decompress(r.length,32,function(n){return o(e,r.charAt(n))}))},compress:function(o){return i._compress(o,16,function(o){return r(o)})},_compress:function(o,r,n){if(null==o)return"";var e,t,i,s={},p={},u="",c="",a="",l=2,f=3,h=2,d=[],m=0,v=0;for(i=0;i<o.length;i+=1)if(u=o.charAt(i),Object.prototype.hasOwnProperty.call(s,u)||(s[u]=f++,p[u]=!0),c=a+u,Object.prototype.hasOwnProperty.call(s,c))a=c;else{if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++),s[c]=f++,a=String(u)}if(""!==a){if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++)}for(t=2,e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;for(;;){if(m<<=1,v==r-1){d.push(n(m));break}v++}return d.join("")},decompress:function(o){return null==o?"":""==o?null:i._decompress(o.length,32768,function(r){return o.charCodeAt(r)})},_decompress:function(o,n,e){var t,i,s,p,u,c,a,l,f=[],h=4,d=4,m=3,v="",w=[],A={val:e(0),position:n,index:1};for(i=0;3>i;i+=1)f[i]=i;for(p=0,c=Math.pow(2,2),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(t=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 2:return""}for(f[3]=l,s=l,w.push(l);;){if(A.index>o)return"";for(p=0,c=Math.pow(2,m),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(l=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 2:return w.join("")}if(0==h&&(h=Math.pow(2,m),m++),f[l])v=f[l];else{if(l!==d)return null;v=s+s.charAt(0)}w.push(v),f[d++]=s+v.charAt(0),h--,s=v,0==h&&(h=Math.pow(2,m),m++)}}};return i}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module&&(module.exports=LZString); diff --git a/www/index.html b/www/index.html index 06829c77..89075b37 100644 --- a/www/index.html +++ b/www/index.html @@ -83,6 +83,7 @@ <script src="external/js/angular-touch.min.js"></script> <script src="external/js/holder.min.js"></script> <script src="external/js/angular-cookies.min.js"></script> + <script src="external/js/lz-string.min.js"></script> <!-- app related JS --> <script src="js/app.js"></script> diff --git a/www/js/DevOptionsCtrl.js b/www/js/DevOptionsCtrl.js index 5fa349cc..1f5a920a 100644 --- a/www/js/DevOptionsCtrl.js +++ b/www/js/DevOptionsCtrl.js @@ -2,7 +2,7 @@ /* jslint browser: true*/ /* global cordova,StatusBar,angular,console */ -angular.module('zmApp.controllers').controller('zmApp.DevOptionsCtrl', ['$scope', '$rootScope', '$ionicModal', 'zm', 'NVR', '$ionicSideMenuDelegate', '$ionicPopup', '$http', '$q', '$ionicLoading', '$ionicHistory', '$state', 'SecuredPopups', '$translate', function ($scope, $rootScope, $ionicModal, zm, NVR, $ionicSideMenuDelegate, $ionicPopup, $http, $q, $ionicLoading, $ionicHistory, $state, SecuredPopups, $translate) { +angular.module('zmApp.controllers').controller('zmApp.DevOptionsCtrl', ['$scope', '$rootScope', '$ionicModal', 'zm', 'NVR', '$ionicSideMenuDelegate', '$ionicPopup', '$http', '$q', '$ionicLoading', '$ionicHistory', '$state', 'SecuredPopups', '$translate','$ionicActionSheet', function ($scope, $rootScope, $ionicModal, zm, NVR, $ionicSideMenuDelegate, $ionicPopup, $http, $q, $ionicLoading, $ionicHistory, $state, SecuredPopups, $translate, $ionicActionSheet) { $scope.openMenu = function () { $ionicSideMenuDelegate.toggleLeft(); @@ -155,6 +155,32 @@ angular.module('zmApp.controllers').controller('zmApp.DevOptionsCtrl', ['$scope' }; + $scope.selectObfuscationScheme = function() { + + var buttons = [ + { text: $translate.instant('kObfuscationLZS'), value:'lzs' }, + { text: $translate.instant('kObfuscationAES'), value:'aes' }, + + ] + + $ionicActionSheet.show({ + titleText: $translate.instant('kSelect'), + buttons: buttons, + + cancelText: $translate.instant('kButtonCancel'), + cancel: function() { + NVR.debug ('obfuscation actionsheet cancelled'); + }, + buttonClicked: function(index) { + + $scope.loginData.obfuscationScheme = buttons[index].value; + NVR.debug ('changed obfuscation scheme to:'+$scope.loginData.obfuscationScheme ); + return true; + }, + + }); + }; + $scope.saveDevOptions = function () { saveDevOptions(); diff --git a/www/js/LoginCtrl.js b/www/js/LoginCtrl.js index 11474f2d..ffde6ffa 100644 --- a/www/js/LoginCtrl.js +++ b/www/js/LoginCtrl.js @@ -766,8 +766,7 @@ function mobilePinConfig () { var serverGroupList = NVR.getServerGroups(); serverGroupList[$scope.loginData.serverName] = angular.copy($scope.loginData); - var ct = CryptoJS.AES.encrypt(JSON.stringify(serverGroupList), zm.cipherKey).toString(); - + var ct = NVR.encrypt(serverGroupList); window.cordova.plugin.cloudsettings.save({ 'serverGroupList': ct, 'defaultServerName': $scope.loginData.serverName diff --git a/www/js/MonitorCtrl.js b/www/js/MonitorCtrl.js index b396f5ee..1cd695b7 100644 --- a/www/js/MonitorCtrl.js +++ b/www/js/MonitorCtrl.js @@ -423,6 +423,7 @@ angular.module('zmApp.controllers') else { NVR.debug ("reporting status of monitors from multi-server API"); processMonitorStatus(); + } }, diff --git a/www/js/NVR.js b/www/js/NVR.js index 8d9681c8..5b6eb0fd 100644 --- a/www/js/NVR.js +++ b/www/js/NVR.js @@ -1,7 +1,7 @@ /* jshint -W041 */ /* jslint browser: true*/ -/* global cordova,StatusBar,angular,console, URI, moment, localforage, CryptoJS, Connection */ +/* global cordova,StatusBar,angular,console, URI, moment, localforage, CryptoJS, Connection, LZString */ // This is my central data respository and common functions // that many other controllers use @@ -211,6 +211,7 @@ angular.module('zmApp.controllers') 'pauseStreams': false, 'liveStreamBuffer': 10, 'zmNinjaCustomId':undefined, // filled in init. custom header + 'obfuscationScheme': 'lzs' // or 'aes' }; @@ -404,8 +405,7 @@ angular.module('zmApp.controllers') //data = JSON.parse(data); if (doCrypt) { debug ('CACHE: decryption requested'); - var bytes = CryptoJS.AES.decrypt(data.toString(), zm.cipherKey); - data = JSON.parse(bytes.toString(CryptoJS.enc.Utf8)); + data = decrypt(data); } else data = JSON.parse(data); @@ -424,7 +424,7 @@ angular.module('zmApp.controllers') debug ('CACHE: storing key data in cache now, with expiry of '+expiry); if (doCrypt) { debug ('CACHE: encrypting request'); - var ct = CryptoJS.AES.encrypt(JSON.stringify(data), zm.cipherKey).toString(); + var ct = encrypt(data); cache_entry.data = ct; } else { @@ -1031,6 +1031,7 @@ angular.module('zmApp.controllers') } + } function setLogin(newLogin) { @@ -1045,8 +1046,8 @@ angular.module('zmApp.controllers') serverGroupList[loginData.serverName] = angular.copy(loginData); - var ct = CryptoJS.AES.encrypt(JSON.stringify(serverGroupList), zm.cipherKey).toString(); - + var ct = encrypt(serverGroupList); + //debug ("Crypto is: " + ct); return localforage.setItem("serverGroupList", ct) @@ -1611,6 +1612,10 @@ angular.module('zmApp.controllers') loginData.zmNinjaCustomId = 'zmNinja_'+zmAppVersion; } + if (typeof loginData.obfuscationScheme == 'undefined') { + loginData.obfuscationScheme = 'lzs'; + } + loginData.canSwipeMonitors = true; loginData.forceImageModePath = false; loginData.enableBlog = true; @@ -1676,9 +1681,57 @@ angular.module('zmApp.controllers') debug("Setting server version to:" + val); } + function encrypt(data) { + + var jsdata = JSON.stringify(data); + var compress; + + if (loginData.obfuscationScheme == 'lzs') { + compress = '--Z--'+LZString.compressToUTF16(jsdata); + + } + else if (loginData.obfuscationScheme == 'aes') { + compress = CryptoJS.AES.encrypt(jsdata, zm.cipherKey).toString(); + } else { + log ('ERROR: obfuscation scheme:'+loginData.obfuscationScheme+' not recognized'); + return undefined; + } + + debug ('obfuscate: original:'+jsdata.length+' obfuscated:'+compress.length+' scheme:'+loginData.obfuscationScheme); + return compress; + } + + function decrypt(data) { + //debug ('-->deobfuscating '+data.length+' bytes using scheme:'+loginData.obfuscationScheme); + var decodedVal; + var scheme; + if (data.substr(0,5) == '--Z--') { + //debug ('unpacking'); + scheme = 'lzs'; + decodedVal = LZString.decompressFromUTF16(data.substr(5)); + } else { + var bytes = CryptoJS.AES.decrypt(data.toString(), zm.cipherKey); + decodedVal = bytes.toString(CryptoJS.enc.Utf8); + scheme = 'aes'; + } + + //console.log ('-->decrypted ' + decodedVal); + debug ('deobfuscate: before:'+data.length+' after:'+decodedVal.length+' scheme:'+scheme); + var decodedJSON = JSON.parse(decodedVal); + + return (decodedJSON); + } + return { + encrypt: function(data) { + return encrypt(data); + }, + + decrypt: function(data) { + return decrypt(data); + }, insertSpecialTokens: function () { @@ -2009,8 +2062,8 @@ angular.module('zmApp.controllers') if (typeof sgl == 'string') { log("user profile encrypted, decoding..."); - var bytes = CryptoJS.AES.decrypt(sgl.toString(), zm.cipherKey); - decodedSgl = JSON.parse(bytes.toString(CryptoJS.enc.Utf8)); + decodedSgl = decrypt(sgl); + } else { decodedSgl = sgl; @@ -2128,8 +2181,7 @@ angular.module('zmApp.controllers') if (typeof val == 'string') { log("user profile encrypted, decoding..."); - var bytes = CryptoJS.AES.decrypt(val.toString(), zm.cipherKey); - decodedVal = JSON.parse(bytes.toString(CryptoJS.enc.Utf8)); + decodedVal = decrypt(val); } else { log("user profile not encrypted"); diff --git a/www/js/app.js b/www/js/app.js index 3eb7210f..9221d456 100755 --- a/www/js/app.js +++ b/www/js/app.js @@ -1698,7 +1698,8 @@ angular.module('zmApp', [ NVR.log(">>>>migrated latestBlogPostChecked..."); // lets encrypt serverGroupList NVR.log("server group list is " + JSON.stringify(sgl)); - var ct = CryptoJS.AES.encrypt(JSON.stringify(sgl), zm.cipherKey); + var ct = NVR.encrypt(sgl); + NVR.log("encrypted server group list is " + ct); ct = sgl; return localforage.setItem('serverGroupList', ct); diff --git a/www/lang/locale-en.json b/www/lang/locale-en.json index e7eed7ec..f3922c03 100644 --- a/www/lang/locale-en.json +++ b/www/lang/locale-en.json @@ -271,6 +271,8 @@ "kNormalPlay" :"normal play", "kNote" :"Note", "kNow" :"now", + "kObfuscationAES" :"AES (encrypt)", + "kObfuscationLZS" :"LZS (compress)", "kOff" :"off", "kOn" :"on", "kOnTapNavigate" :"on tap, navigate to", diff --git a/www/templates/devoptions.html b/www/templates/devoptions.html index 26485910..a56e77f3 100644 --- a/www/templates/devoptions.html +++ b/www/templates/devoptions.html @@ -243,6 +243,16 @@ </label> <label> + <div class="item item-button-right"> + Data obfuscation: {{loginData.obfuscationScheme}}<button class="button button-calm" ng-click="selectObfuscationScheme()"> + <i class="icon ion-gear-b"></i> + </button> + </div> + </label> + + + + <label> <ion-toggle ng-model="loginData.enableLogs" toggle-class="toggle-calm"> <span class="item-text-wrap">{{'kEnableLogs' | translate}}</span> </ion-toggle> |
