diff --git a/Gruntfile.js b/Gruntfile.js index 998453b7e..4a48970ed 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -90,7 +90,6 @@ module.exports = function(grunt) { 'bower_components/qrcode-generator/js/qrcode.js', 'bower_components/qrcode-decoder-js/lib/qrcode-decoder.js', 'bower_components/moment/min/moment-with-locales.js', - 'bower_components/angular/angular.js', 'bower_components/angular-ui-router/release/angular-ui-router.js', 'bower_components/angular-foundation/mm-foundation-tpls.js', 'bower_components/angular-moment/angular-moment.js', diff --git a/bower.json b/bower.json index 774cdfec4..15f45d9e6 100644 --- a/bower.json +++ b/bower.json @@ -7,13 +7,12 @@ "bitcore" ], "dependencies": { - "angular": "1.4.6", "angular-mocks": "1.4.10", "angular-foundation": "0.8.0", "angular-gettext": "2.2.1", "angular-moment": "0.10.1", "angular-qrcode": "monospaced/angular-qrcode#~6.2.1", - "angular-ui-router": "0.2.18", + "angular-ui-router": "0.2.13", "animate.css": "3.5.1", "foundation": "5.5.3", "foundation-icon-fonts": "*", @@ -25,8 +24,8 @@ "ng-csv": "~0.3.6" }, "resolutions": { - "angular": "1.4.6", + "angular": "1.5.3", "qrcode-generator": "0.1.0", - "angular-ui-router": "0.2.18" + "angular-ui-router": "0.2.13" } } diff --git a/package.json b/package.json index 55c254da6..05878f04e 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "url": "https://github.com/bitpay/copay/issues" }, "dependencies": { - "bitcore-wallet-client": "~2.5.0", + "bitcore-wallet-client": "2.6.0", "express": "^4.11.2", "fs": "0.0.2", "grunt": "^0.4.5", diff --git a/public/views/import.html b/public/views/import.html index da78df49a..990f0a7a6 100644 --- a/public/views/import.html +++ b/public/views/import.html @@ -33,11 +33,29 @@
-
- + +
+
+
Could not access the wallet at the server. Please check:
+
    +
  • The password of the recovery phrase (if set) +
  • +
  • The derivation path +
  • +
  • The wallet service URL +
+
+ NOTE: To import a wallet from a 3rd party software, please go to Add Wallet > Create Wallet, and specify the Recovery Phrase there.
+
+
+
+ +
+
{{import.error|translate}} -
+
+
diff --git a/src/js/controllers/import.js b/src/js/controllers/import.js index 35d18b5a4..010520814 100644 --- a/src/js/controllers/import.js +++ b/src/js/controllers/import.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copayApp.controllers').controller('importController', - function($scope, $rootScope, $ionicScrollDelegate, $timeout, $log, profileService, configService, notification, go, sjcl, gettext, lodash, ledger, trezor, derivationPathHelper, platformInfo) { + function($scope, $rootScope, $ionicScrollDelegate, $timeout, $log, profileService, configService, notification, go, sjcl, gettext, lodash, ledger, trezor, derivationPathHelper, platformInfo, bwsError, bwcService) { var isChromeApp = platformInfo.isChromeApp; var isDevel = platformInfo.isDevel; @@ -9,9 +9,11 @@ angular.module('copayApp.controllers').controller('importController', var self = this; var reader = new FileReader(); var defaults = configService.getDefaults(); + var errors = bwcService.getErrors(); $scope.bwsurl = defaults.bws.url; $scope.derivationPath = derivationPathHelper.default; $scope.account = 1; + self.importErr = false; window.ignoreMobilePause = true; $scope.$on('$destroy', function() { @@ -20,6 +22,7 @@ angular.module('copayApp.controllers').controller('importController', }, 100); }); + var updateSeedSourceSelect = function() { self.seedOptions = []; @@ -52,7 +55,7 @@ angular.module('copayApp.controllers').controller('importController', try { str2 = sjcl.decrypt(self.password, str); } catch (e) { - err = gettext('Could not decrypt file, check your spending password'); + err = gettext('Could not decrypt file, check your password'); $log.warn(e); }; @@ -91,12 +94,17 @@ angular.module('copayApp.controllers').controller('importController', profileService.importExtendedPrivateKey(xPrivKey, opts, function(err, walletId) { self.loading = false; if (err) { - self.error = err; + if (err instanceof errors.NOT_AUTHORIZED) { + self.importErr = true; + } else { + self.error = err; + } $ionicScrollDelegate.scrollTop(); return $timeout(function() { $scope.$apply(); }); } + $rootScope.$emit('Local/WalletImported', walletId); notification.success(gettext('Success'), gettext('Your wallet has been imported correctly')); go.walletHome(); @@ -110,13 +118,19 @@ angular.module('copayApp.controllers').controller('importController', $timeout(function() { profileService.importMnemonic(words, opts, function(err, walletId) { self.loading = false; + if (err) { - self.error = err; + if (err instanceof errors.NOT_AUTHORIZED) { + self.importErr = true; + } else { + self.error = err; + } $ionicScrollDelegate.scrollTop(); return $timeout(function() { $scope.$apply(); }); } + $rootScope.$emit('Local/WalletImported', walletId); notification.success(gettext('Success'), gettext('Your wallet has been imported correctly')); go.walletHome(); @@ -265,6 +279,7 @@ angular.module('copayApp.controllers').controller('importController', return; } this.error = ''; + this.importErr = false; var account = +$scope.account; diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index f90c36af9..fab54e654 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -301,6 +301,7 @@ angular.module('copayApp.services') var name = opts.name || gettextCatalog.getString('Personal Wallet'); var myName = opts.myName || gettextCatalog.getString('me'); +console.log('[profileService.js.303]', opts); //TODO walletClient.createWallet(name, myName, opts.m, opts.n, { network: opts.networkName, singleAddress: opts.singleAddress, @@ -543,8 +544,12 @@ angular.module('copayApp.services') $log.debug('Importing Wallet xPrivKey'); walletClient.importFromExtendedPrivateKey(xPrivKey, opts, function(err) { - if (err) + if (err) { + if (err instanceof errors.NOT_AUTHORIZED) + return cb(err); + return bwsError.cb(err, gettext('Could not import'), cb); + } root.addAndBindWalletClient(walletClient, { bwsurl: opts.bwsurl, @@ -571,8 +576,12 @@ angular.module('copayApp.services') passphrase: opts.passphrase, account: opts.account || 0, }, function(err) { - if (err) + if (err) { + if (err instanceof errors.NOT_AUTHORIZED) + return cb(err); + return bwsError.cb(err, gettext('Could not import'), cb); + } root.addAndBindWalletClient(walletClient, { bwsurl: opts.bwsurl, diff --git a/test/controllers/create.test.js b/test/controllers/create.test.js index 3951acb9c..8010fde85 100644 --- a/test/controllers/create.test.js +++ b/test/controllers/create.test.js @@ -5,19 +5,20 @@ describe('createController', function() { '1eda3e702196b8d5d82fae129249bc79f0d5be2f5309a4e39855e7eb4ad31428': {}, '31f5deeef4cf7fd8fc67297179232e8e4590532960454ad958009132fef3daae': {}, // createWallet 1-1 - '56db6f58f2c212591afb4d508d03e5fb40bb786f23dc56c43b98bde42dc513e5': { - "walletId": "267bfa75-5575-4af7-8aa3-f5186bc99262" + // + 'b665ad8991c67f8f7e8ffb7e86c3b930fd3ff56c68eb6fd441bf374559cfe59c': { + "walletId": "63d910e8-3e1b-4aac-97e9-aa0299a74c2c" }, - // join ^ - 'd2f00a570de17f52fcda4b1b4b4ed1bc688a3b33c193b71630c3183dab70e6ec': { + 'd5cc6adebc752c154998f1c96af2b24e21e52dbd7c07008c333af03b905ffb85': { "copayerId": "a9dcee10fe9c611300e6c7926ece20780f89b9a98baaa342928038b5503ed929", "wallet": { "version": "1.0.0", - "createdOn": 1463488747, - "id": "267bfa75-5575-4af7-8aa3-f5186bc99262", + "createdOn": 1465385318, + "id": "63d910e8-3e1b-4aac-97e9-aa0299a74c2c", "name": "{\"iv\":\"BZQVWAP6d1e4G8Fq1rQKbA==\",\"v\":1,\"iter\":1,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"ct\":\"70OA+k4+xTPxim+QSdDtA5/Cf055\"}", "m": 1, "n": 1, + "singleAddress": false, "status": "complete", "publicKeyRing": [{ "xPubKey": "xpub6DRjAgkh3vGTWDcEmDp4TPwy48Nu8yrp6swCEdCCLL615CgnZon7r3vXYr8LYibMLJh5DriGSito1FRBwVoBkjD1ZWG4dmgiC935wLj3nQC", @@ -25,7 +26,7 @@ describe('createController', function() { }], "copayers": [{ "version": 2, - "createdOn": 1463490295, + "createdOn": 1465385318, "xPubKey": "xpub6DRjAgkh3vGTWDcEmDp4TPwy48Nu8yrp6swCEdCCLL615CgnZon7r3vXYr8LYibMLJh5DriGSito1FRBwVoBkjD1ZWG4dmgiC935wLj3nQC", "id": "a9dcee10fe9c611300e6c7926ece20780f89b9a98baaa342928038b5503ed929", "name": "{\"iv\":\"BZQVWAP6d1e4G8Fq1rQKbA==\",\"v\":1,\"iter\":1,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"ct\":\"wwZd+2LQgYR6cA==\"}", @@ -51,27 +52,26 @@ describe('createController', function() { "scanStatus": null } }, - //createWallet 2-2 - 'e46ef870b70e6deca6bbfa61bd0d83b0dc5b712402538b0dabcd0d4f038b0eba': { - "walletId": "7bd8d22f-d132-43e1-b259-d5b430752553" + '5a1d11ebc2a011f018b049de6b5c6b990cdc8e280644103f95a995321dbf0248': { + "walletId": "2f50f598-7550-4e54-8032-15aa892309fb" }, - - // join ^ - '2df76b91e0080f1552926b7d3ce5dd99db054bc4dfce309d8455cab5d9a93ad4': { + // join + '58f2f3a6f11cd7dee9a75e026e3ba570c09b952bfea05f596fdb48e6ea323f21': { "copayerId": "3d4eb9b439eee1b2b73cf792eda52e420f4665109c7234a50cf3cdbf296ea8fb", "wallet": { "version": "1.0.0", - "createdOn": 1463511645, - "id": "7bd8d22f-d132-43e1-b259-d5b430752553", + "createdOn": 1465347188, + "id": "2f50f598-7550-4e54-8032-15aa892309fb", "name": "{\"iv\":\"BZQVWAP6d1e4G8Fq1rQKbA==\",\"v\":1,\"iter\":1,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"ct\":\"70OA+k4+xTPxim+QSdDtA5/Cf055\"}", "m": 2, "n": 2, + "singleAddress": false, "status": "pending", "publicKeyRing": [], "copayers": [{ "version": 2, - "createdOn": 1463511988, + "createdOn": 1465347188, "xPubKey": "xpub6CkPnrzSUp9qzBVM3hpo4oS2JKC6GJq6brE1yW59QrnhDpvkFLakpxUGRGXH62fiXb5S2VbnD4h2DLoCMfSkwfonbNgNYTJw9Ko5SqWEqCR", "id": "3d4eb9b439eee1b2b73cf792eda52e420f4665109c7234a50cf3cdbf296ea8fb", "name": "{\"iv\":\"BZQVWAP6d1e4G8Fq1rQKbA==\",\"v\":1,\"iter\":1,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"ct\":\"wwZd+2LQgYR6cA==\"}", @@ -97,6 +97,7 @@ describe('createController', function() { "scanStatus": null } }, + }; // TODO: Read from file beforeEach(function(done) { @@ -134,16 +135,16 @@ describe('createController', function() { should.not.exist(ctrl.error); mocks.go.walletHome.calledOnce.should.equal(true); - + // // check resulting profile - storageService.getProfile(function(err, profile) { - should.not.exist(err); - var c = profile.credentials[0]; - c.network.should.equal('livenet'); - // from test vectors from https://dcpos.github.io/bip39/ - c.xPrivKey.should.equal('xprv9s21ZrQH143K2x4gnzRB1eZDq92Uuvy9CXbvgQGdvykXZ9mkkot6LBjzDpgaAfvzkuxJe9JKJXQ38VoPutxvACA5MsyoBs5UyQ4HZKGshGs'); - done(); - }); + storageService.getProfile(function(err, profile) { + should.not.exist(err); + var c = profile.credentials[0]; + c.network.should.equal('livenet'); + // from test vectors from https://dcpos.github.io/bip39/ + c.xPrivKey.should.equal('xprv9s21ZrQH143K2x4gnzRB1eZDq92Uuvy9CXbvgQGdvykXZ9mkkot6LBjzDpgaAfvzkuxJe9JKJXQ38VoPutxvACA5MsyoBs5UyQ4HZKGshGs'); + done(); + }); }); diff --git a/test/controllers/disclaimer.test.js b/test/controllers/disclaimer.test.js index 5502aecce..52452b026 100644 --- a/test/controllers/disclaimer.test.js +++ b/test/controllers/disclaimer.test.js @@ -3,18 +3,19 @@ describe('disclaimerController', function() { var storeProfile; var fixtures = { - '8dc332881e99c908c655147dc6bc605e102b0bd3cf2dbee02ed2a0f4daf2925a': { - "walletId": "eddaef15-f412-462f-9d3e-a793a7f6f6ba" + 'e4d8ae25e03e5fef2e553615b088cfce222083828c13fdb37b8b6cf87bf76236': { + "walletId": "215f125d-57e7-414a-9723-448256113440", }, - '654145bc3f15f03a8b1ccf55aa1bdcd1cfd5bbe3de90e909fd4e7f9f69ec4d79': { + '3f3b354d45c3eae3e4fe8830fcb728e5e570515af86e1a35deff0048a7a5e6b5': { "copayerId": "1a91ead1b6d13da882a25377a20e460df557e77008ea4f60eecbf984f786cf03", "wallet": { "version": "1.0.0", - "createdOn": 1465152783, - "id": "eddaef15-f412-462f-9d3e-a793a7f6f6ba", + "createdOn": 1465347281, + "id": "215f125d-57e7-414a-9723-448256113440", "name": "{\"iv\":\"BZQVWAP6d1e4G8Fq1rQKbA==\",\"v\":1,\"iter\":1,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"ct\":\"/gaG7FIkhCiwsWKZUR0sL/cxH+zHMK0=\"}", "m": 1, "n": 1, + "singleAddress": false, "status": "complete", "publicKeyRing": [{ "xPubKey": "xpub6Cb7MYAX7mJR28MfFueCsoDVVHhoWkQxRC4viAeHanYwRNgDo5xMF42xmAeExzfyPXX3GaALNA8hWFMekVYvDF2BALommUhMgZ52szh88fd", @@ -22,7 +23,7 @@ describe('disclaimerController', function() { }], "copayers": [{ "version": 2, - "createdOn": 1465152783, + "createdOn": 1465347281, "xPubKey": "xpub6Cb7MYAX7mJR28MfFueCsoDVVHhoWkQxRC4viAeHanYwRNgDo5xMF42xmAeExzfyPXX3GaALNA8hWFMekVYvDF2BALommUhMgZ52szh88fd", "id": "1a91ead1b6d13da882a25377a20e460df557e77008ea4f60eecbf984f786cf03", "name": "{\"iv\":\"BZQVWAP6d1e4G8Fq1rQKbA==\",\"v\":1,\"iter\":1,\"ks\":128,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"ct\":\"wwZd+2LQgYR6cA==\"}", @@ -47,7 +48,8 @@ describe('disclaimerController', function() { }, "scanStatus": null } - }, + } + }; // TODO: Read from file beforeEach(function(done) { @@ -62,7 +64,7 @@ describe('disclaimerController', function() { }); it('should be defined', function() { - should.exist(ctrl); + should.exist(ctrl); }); it('should create the initial profile', function(done) { diff --git a/test/helpers.js b/test/helpers.js index 59520af00..b8adbfb58 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -64,8 +64,8 @@ mocks.$document = { mocks.init = function(fixtures, controllerName, opts, done) { console.log(' * Mock init()'); opts = opts || {}; - should.exist(controllerName, 'Provide the name of the Controller to mocks.init()'); + should.exist(controllerName, 'Provide the name of the Controller to mocks.init()'); mocks.go = {}; mocks.go.walletHome = sinon.stub(); mocks.go.path = sinon.stub(); @@ -86,6 +86,7 @@ mocks.init = function(fixtures, controllerName, opts, done) { module('gettext'); module('stateMock'); module('bwcModule', function($provide) { + console.log(' * bwcService decorator'); $provide.decorator('bwcService', function($delegate, lodash) { var getClient = $delegate.getClient; @@ -182,8 +183,12 @@ mocks.init = function(fixtures, controllerName, opts, done) { rate: 452.92 }); + $httpBackend.whenGET(/views.*/).respond(200, ''); + + _configService_.get(function() { function startController() { + console.log(' * starting Controller:', controllerName); ctrl = $controller(controllerName, { $scope: scope, $modal: mocks.modal, @@ -216,6 +221,7 @@ mocks.init = function(fixtures, controllerName, opts, done) { done(); }); } else { + _profileService_.create({ noWallet: true }, function(err) { @@ -226,6 +232,7 @@ mocks.init = function(fixtures, controllerName, opts, done) { _profileService_.setDisclaimerAccepted(function() { if (!opts.initController) startController(); + done(); }); }); diff --git a/test/karma.conf.js b/test/karma.conf.js index 0f8935976..e94449c8b 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -18,7 +18,7 @@ module.exports = function(config) { 'bower_components/qrcode-generator/js/qrcode.js', 'bower_components/qrcode-decoder-js/lib/qrcode-decoder.js', 'bower_components/moment/min/moment-with-locales.js', - 'bower_components/angular/angular.js', + 'bower_components/ionic/release/js/ionic.bundle.min.js', 'bower_components/angular-ui-router/release/angular-ui-router.js', 'bower_components/angular-foundation/mm-foundation-tpls.js', 'bower_components/angular-moment/angular-moment.js', @@ -28,7 +28,6 @@ module.exports = function(config) { 'bower_components/angular-sanitize/angular-sanitize.js', 'bower_components/ng-csv/build/ng-csv.js', 'bower_components/angular-mocks/angular-mocks.js', - 'bower_components/ionic/release/js/ionic.bundle.min.js', 'angular-bitcore-wallet-client/angular-bitcore-wallet-client.js', 'src/js/**/*.js', 'test/helpers.js',