diff --git a/.travis.yml b/.travis.yml index ff6ea90ce..51762742b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - '0.12' + - '4.0' before_install: - npm install -g bower - npm install -g grunt-cli diff --git a/Gruntfile.js b/Gruntfile.js index 811946557..188cb81b8 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -235,12 +235,12 @@ module.exports = function(grunt) { singleRun: true } }, - nodewebkit: { + nwjs: { options: { appName: 'Copay', platforms: ['win64', 'osx64', 'linux64'], buildDir: './webkitbuilds', - version: '0.12.2', + version: '0.16.0', macIcns: './public/img/icons/icon.icns', exeIco: './public/img/icons/icon.ico' }, @@ -271,7 +271,7 @@ module.exports = function(grunt) { grunt.registerTask('translate', ['nggettext_extract']); grunt.registerTask('test', ['karma:unit']); grunt.registerTask('test-coveralls', ['browserify', 'karma:prod', 'exec:coveralls']); - grunt.registerTask('desktop', ['prod', 'nodewebkit', 'copy:linux', 'compress:linux']); - grunt.registerTask('osx', ['prod', 'nodewebkit', 'exec:osx']); + grunt.registerTask('desktop', ['prod', 'nwjs', 'copy:linux', 'compress:linux']); + grunt.registerTask('osx', ['prod', 'nwjs', 'exec:osx']); grunt.registerTask('release', ['string-replace:dist']); }; diff --git a/package.json b/package.json index 98bc73bb1..54c4a81a4 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "window": { "title": "Copay - A multisignature bitcoin wallet", "icon": "./public/img/icons/icon-256.png", - "toolbar": false, "show": true, "visible": true, "resizable": true, @@ -30,7 +29,7 @@ "java": false, "plugin": false }, - "dom_storage_quota": 100, + "dom_storage_quota": 200, "id": "jid1-x7bV5evAaI1P9Q", "homepage": "https://github.com/bitpay/copay", "license": "MIT", @@ -42,20 +41,10 @@ "url": "https://github.com/bitpay/copay/issues" }, "dependencies": { - "bitcore-wallet-client": "2.9.0", + "bitcore-wallet-client": "2.11.0", "coveralls": "^2.11.9", "express": "^4.11.2", "fs": "0.0.2", - "grunt": "^0.4.5", - "grunt-angular-gettext": "^0.2.15", - "grunt-browserify": "^4.0.1", - "grunt-cli": "^0.1.13", - "grunt-contrib-compress": "^0.13.0", - "grunt-contrib-concat": "^0.5.1", - "grunt-contrib-copy": "^0.8.1", - "grunt-contrib-uglify": "^0.9.2", - "grunt-contrib-watch": "^0.6.1", - "grunt-exec": "^0.4.6", "shelljs": "^0.3.0" }, "scripts": { @@ -75,9 +64,17 @@ "chai": "^3.5.0", "cordova": "5.4.1", "cordova-android": "5.1.1", - "grunt-karma": "^1.0.0", + "grunt": "^1.0.1", + "grunt-angular-gettext": "^2.2.3", + "grunt-browserify": "^5.0.0", + "grunt-contrib-compress": "^1.3.0", + "grunt-contrib-concat": "^1.0.1", + "grunt-contrib-copy": "^1.0.0", + "grunt-contrib-uglify": "^2.0.0", + "grunt-exec": "^1.0.0", + "grunt-karma": "^2.0.0", "grunt-karma-coveralls": "^2.5.4", - "grunt-node-webkit-builder": "^1.0.2", + "grunt-nw-builder": "^2.0.3", "grunt-sass": "^1.2.0", "grunt-string-replace": "^1.2.1", "karma": "^0.13.22", diff --git a/src/js/controllers/disclaimer.js b/src/js/controllers/disclaimer.js index 261032579..177c82a41 100644 --- a/src/js/controllers/disclaimer.js +++ b/src/js/controllers/disclaimer.js @@ -11,6 +11,7 @@ angular.module('copayApp.controllers').controller('disclaimerController', var create = function(opts) { opts = opts || {}; $log.debug('Creating profile'); + profileService.create(opts, function(err) { if (err) { $log.warn(err); @@ -30,7 +31,6 @@ angular.module('copayApp.controllers').controller('disclaimerController', } }, 3000); }; - $scope.error = ""; ongoingProcess.set('creatingWallet', false); }); diff --git a/src/js/controllers/import.js b/src/js/controllers/import.js index b86d06b59..f0337a7de 100644 --- a/src/js/controllers/import.js +++ b/src/js/controllers/import.js @@ -348,9 +348,9 @@ angular.module('copayApp.controllers').controller('importController', }; $scope.setSeedSource = function() { + if (!$scope.seedSource) return; $scope.seedSourceId = $scope.seedSource.id; - $timeout(function() { $rootScope.$apply(); }); diff --git a/src/js/controllers/index.js b/src/js/controllers/index.js index 2a070cfc1..72de95860 100644 --- a/src/js/controllers/index.js +++ b/src/js/controllers/index.js @@ -20,6 +20,9 @@ angular.module('copayApp.controllers').controller('indexController', function($r ret.prevState = 'walletHome'; ret.physicalScreenWidth = ((window.innerWidth > 0) ? window.innerWidth : screen.width); + // Only for testing + //storageService.checkQuota(); + ret.menu = [{ 'title': gettext('Receive'), 'icon': { diff --git a/src/js/services/localStorage.js b/src/js/services/localStorage.js index 17ab3a27d..8a0cc1610 100644 --- a/src/js/services/localStorage.js +++ b/src/js/services/localStorage.js @@ -1,21 +1,23 @@ 'use strict'; angular.module('copayApp.services') - .factory('localStorageService', function(platformInfo, $timeout) { + .factory('localStorageService', function(platformInfo, $timeout, $log) { var isNW = platformInfo.isNW; var isChromeApp = platformInfo.isChromeApp; var root = {}; var ls = ((typeof window.localStorage !== "undefined") ? window.localStorage : null); if (isChromeApp && !isNW && !ls) { + $log.info('Using CHROME storage'); ls = chrome.storage.local; } + if (!ls) throw new Error('localstorage not available'); root.get = function(k, cb) { - if (isChromeApp && !isNW) { + if (isChromeApp || isNW) { chrome.storage.local.get(k, function(data) { //TODO check for errors @@ -41,7 +43,7 @@ angular.module('copayApp.services') }; root.set = function(k, v, cb) { - if (isChromeApp && !isNW) { + if (isChromeApp || isNW) { var obj = {}; obj[k] = v; @@ -54,7 +56,7 @@ angular.module('copayApp.services') }; root.remove = function(k, cb) { - if (isChromeApp && !isNW) { + if (isChromeApp || isNW) { chrome.storage.local.remove(k, cb); } else { ls.removeItem(k); @@ -63,5 +65,37 @@ angular.module('copayApp.services') }; + + if (isNW) { + $log.info('Overwritting localstorage with chrome storage for NW.JS'); + + var ts = ls.getItem('migrationToChromeStorage'); + var p = ls.getItem('profile'); + + // Need migration? + if (!ts && p) { + $log.info('### MIGRATING DATA! TO CHROME STORAGE'); + + var j = 0; + for (var i = 0; i < localStorage.length; i++) { + var k = ls.key(i); + var v = ls.getItem(k); + + $log.debug(' Key: ' + k); + root.set(k, v, function() { + j++; + if (j == localStorage.length) { + $log.info('### MIGRATION DONE'); + ls.setItem('migrationToChromeStorage', Date.now()) + ls = chrome.storage.local; + } + }) + } + } else if (p) { + $log.info('# Data already migrated to Chrome storage on ' + ts); + } + } + + return root; }); diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index 1da3e07b2..46a0eb14a 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -123,6 +123,7 @@ angular.module('copayApp.services') var validationLock = false; root.runValidation = function(client, delay, retryDelay) { + delay = delay || 500; retryDelay = retryDelay || 50; @@ -152,6 +153,7 @@ angular.module('copayApp.services') $log.warn('Key Derivation failed for wallet:' + walletId); storageService.clearLastAddress(walletId, function() {}); } + root.storeProfileIfDirty(); $rootScope.$emit('Local/ValidatingWalletEnded', walletId, isOK); }); @@ -663,9 +665,11 @@ angular.module('copayApp.services') root.createDefaultProfile(opts, function(err, p) { if (err) return cb(err); - root.bindProfile(p, function(err) { - // ignore NONAGREEDDISCLAIMER - storageService.storeNewProfile(p, function(err) { + storageService.storeNewProfile(p, function(err) { + if (err) return cb(err); + root.bindProfile(p, function(err) { + // ignore NONAGREEDDISCLAIMER + if (err && err.toString().match('NONAGREEDDISCLAIMER')) return cb(); return cb(err); }); }); diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js index 1de5ec21e..33eaa819c 100644 --- a/src/js/services/storageService.js +++ b/src/js/services/storageService.js @@ -264,8 +264,26 @@ angular.module('copayApp.services') storage.remove('addressbook-' + network, cb); }; + + root.checkQuota = function() { + var block = ''; + // 50MB + for (var i = 0; i < 1024*1024; ++ i){ + block += '12345678901234567890123456789012345678901234567890'; + } + storage.set('test', block, function(err) { + $log.error('CheckQuota Return:'+ err); + }); + }; + root.setTxHistory = function(txs, walletId, cb) { - storage.set('txsHistory-' + walletId, txs, cb); + try { + storage.set('txsHistory-' + walletId, txs, cb); + } catch (e) { + $log.error('Error saving tx History. Size:' + txs.length); + $log.error(e); + return cb(e); + } } root.getTxHistory = function(walletId, cb) { diff --git a/test/controllers/disclaimer.test.js b/test/controllers/disclaimer.test.js index c508d35a8..9a8709582 100644 --- a/test/controllers/disclaimer.test.js +++ b/test/controllers/disclaimer.test.js @@ -48,14 +48,14 @@ describe('disclaimerController', function() { }, "scanStatus": null } - } - + }, }; // TODO: Read from file beforeEach(function(done) { + mocks.init(fixtures, 'disclaimerController', { initController: true, - noDisclaimer: true, + noProfile: true, }, done); }); diff --git a/test/controllers/import.test.js b/test/controllers/import.test.js index 7d7b8dc2f..b5c21b456 100644 --- a/test/controllers/import.test.js +++ b/test/controllers/import.test.js @@ -90,9 +90,10 @@ describe('importController', function() { scope.bwsurl = null; scope._walletPrivKey = 'Kz4CFSTgLzoYfMkt97BTBotUbZYXjMts6Ej9HbVfCf5oLmun1BXy'; - ctrl.setSeedSource(); - ctrl.importMnemonic(fakeForm); - should.not.exist(ctrl.error); + scope.setSeedSource(); + + scope.importMnemonic(fakeForm); + should.not.exist(scope.error); mocks.notification.success.calledOnce.should.equal(true); diff --git a/test/helpers.js b/test/helpers.js index ab3effb29..553db161e 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -112,7 +112,7 @@ mocks.init = function(fixtures, controllerName, opts, done) { var headers = JSON.stringify(bwc._getHeaders(method, url, args)); // Fixes BWC version... TODO - headers = headers.replace(/bwc-\d\.\d\.\d/, 'bwc-2.4.0') + headers = headers.replace(/bwc-\d+\.\d+\.\d+/, 'bwc-2.4.0') var x = method + url + JSON.stringify(args) + headers; var sjcl = $delegate.getSJCL(); return sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(x)); @@ -226,6 +226,10 @@ mocks.init = function(fixtures, controllerName, opts, done) { done(); }); } else { + if (opts.noProfile){ + return done(); + } + _profileService_.create({ noWallet: true }, function(err) {