import now working with ledger

Signed-off-by: Matias Alejo Garcia <ematiu@gmail.com>
This commit is contained in:
Matias Alejo Garcia 2015-09-04 21:18:20 -03:00
commit 4d9a477ae5
10 changed files with 148 additions and 47 deletions

View file

@ -17,7 +17,7 @@
"ng-lodash": "~0.2.0",
"angular-moment": "0.10.1",
"moment": "2.10.3",
"angular-bitcore-wallet-client": "0.2.0",
"angular-bitcore-wallet-client": "0.2.2",
"angular-ui-router": "~0.2.13",
"qrcode-decoder-js": "*",
"fastclick": "*",

View file

@ -102,27 +102,27 @@
</div>
<div ng-hide="hideAdv" class="row">
<div class="large-12 columns">
<label ng-show="create.isChromeApp()" for="hw-ledger" class="line-b oh">
<label ng-show="create.isChromeApp()" for="hw-ledger" class="oh">
<span translate>Use Ledger hardware wallet</span>
<switch id="hw-ledger" name="hwLedger" ng-model="hwLedger" ng-change="isTestnet=false" class="green right m5t m10b"></switch>
</label>
<div ng-hide="!hwLedger">
<label class="line-b oh"><span translate>Select slot number for Ledger key</span>
<div ng-show="hwLedger">
<label class="oh line-b "><span translate>Select slot number for Ledger key</span>
<select class="m10t" ng-model="externalIndex" ng-options="externalIndex as externalIndex for externalIndex in create.externalIndexValues">
</select>
</label>
</div>
<label for="network-name" class="oh">
<label for="network-name" class="oh" ng-show="!hwLedger">
<span translate>Testnet</span>
<switch id="network-name" name="isTestnet" ng-model="isTestnet" class="green right m5t m10b"></switch>
</label>
<label ng-hide="hwLedger" for="seed" class="oh">
<label ng-show="!hwLedger" for="seed" class="oh">
<span translate>Specify your wallet seed</span>
<switch id="seed" name="setSeed" ng-model="setSeed" class="green right m5t m10b"></switch>
</label>
<label for="createPassphrase" class="line-b oh" ng-show="!setSeed" ><span translate>Seed Passphrase</span> <small translate>Add an optional passphrase to secure the seed</small>
<label for="createPassphrase" class="line-b oh" ng-show="!setSeed && !hwLedger" ><span translate>Seed Passphrase</span> <small translate>Add an optional passphrase to secure the seed</small>
<div class="input">
<input type="text" class="form-control"
name="createPassphrase" ng-model="createPassphrase">
@ -136,11 +136,11 @@
type="text"
name="privateKey" ng-model="privateKey">
</label>
<label for="passphrase" class="line-b oh" ng-show="setSeed && !hwLedger"><span translate>Seed Passphrase</span> <small translate>The seed could require a passphrase to be imported</small>
<div class="input">
<input type="text" class="form-control" name="passphrase" ng-model="passphrase">
</div>
</label>
<label for="passphrase" class="line-b oh" ng-show="setSeed && !hwLedger"><span translate>Seed Passphrase</span> <small translate>The seed could require a passphrase to be imported</small>
<div class="input">
<input type="text" class="form-control" name="passphrase" ng-model="passphrase">
</div>
</label>
</div>
</div>

View file

@ -5,7 +5,7 @@
</div>
<div class="content p20v" ng-controller="importController as import" ng-init="type='12'">
<div class="onGoingProcess" ng-show="import.loading">
<div class="onGoingProcess" ng-show="import.loading && !import.ledger">
<div class="onGoingProcess-content" ng-style="{'background-color':'#222'}">
<div class="spinner">
<div class="rect1"></div>
@ -17,9 +17,23 @@
<span translate>Importing wallet...</span>
</div>
</div>
<div class="onGoingProcess" ng-show="import.ledger">
<div class="onGoingProcess-content" ng-style="{'background-color':'#222'}">
<div class="spinner">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
<span translate>Connecting to Ledger Wallet...</span>
</div>
</div>
<div class="create-tab small-only-text-center" ng-hide="create.hideTabs">
<div class="row">
<div class="row" ng-show="!index.isChromeApp">
<div class="tab-container small-6 medium-6 large-6">
<a href
ng-class="{'selected': type =='12'}"
@ -30,14 +44,27 @@
ng-class="{'selected': type=='file'}"
ng-click="import.setType('file')" translate>File/Text Backup</a>
</div>
<!-- <div class="tab&#45;container small&#45;4 medium&#45;4 large&#45;4"> -->
<!-- <a href -->
<!-- ng&#45;class="{'selected': type=='qr'}" -->
<!-- ng&#45;click="import.setType('qr')" translate>QR Code</a> -->
<!-- </div> -->
</div>
<div class="row" ng-show="index.isChromeApp">
<div class="tab-container small-4 medium-4 large-4">
<a href
ng-class="{'selected': type =='12'}"
ng-click="import.setType('12')" translate>Walled Seed</a>
</div>
<div class="tab-container small-4 medium-4 large-4">
<a href
ng-class="{'selected': type=='file'}"
ng-click="import.setType('file')" translate>File/Text Backup</a>
</div>
<div class="tab-container small-4 medium-4 large-4">
<a href
ng-class="{'selected': type=='ledger'}"
ng-click="import.setType('ledger')" translate>Ledger</a>
</div>
</div>
</div>
@ -139,9 +166,29 @@
</div>
</div>
<div class="row" ng-show="type == 'qr'">
<div class="row" ng-show="type == 'ledger'">
<div class="large-12 columns">
TODO
<form name="importForm3" ng-submit="import.importLedger(importForm3)" novalidate>
<div class="box-notification" ng-show="import.error">
<span class="text-warning size-14">
{{import.error|translate}}
</span>
</div>
<div class="large-12 columns">
<label class="line-b oh">
<span translate>Select slot number for Ledger key</span>
<select class="m10t" ng-model="externalIndex" ng-options="externalIndex as externalIndex for externalIndex in import.externalIndexValues">
</select>
</label>
<button translate type="submit" class="button round expand black"
ng-disabled="import.loading || import.ledger">
Import backup
</button>
</div>
</form>
</div>
</div>

View file

@ -86,7 +86,7 @@
</a>
<div ng-show="join.hideAdv" class="row">
<div class="large-12 columns" ng-show="join.isChromeApp()">
<label for="hw-ledger" class="line-b oh">
<label for="hw-ledger" class="oh">
<span translate>Use Ledger hardware wallet</span>
<switch id="hw-ledger" name="hwLedger" ng-model="hwLedger" class="green right m5t m10b"></switch>
</label>
@ -100,26 +100,26 @@
</div>
<div class="large-12 columns">
<label for="seed" class="oh">
<label ng-show="!hwLedger" for="seed" class="oh">
<span translate>Specify your wallet seed</span>
<switch id="seed" name="setSeed" ng-model="setSeed" class="green right m5t m10b"></switch>
</label>
<label for="createPassphrase" class="line-b oh" ng-show="!setSeed" ><span translate>Seed Passphrase</span> <small translate>Add an optional passphrase to secure the seed</small>
<label for="createPassphrase" class="line-b oh" ng-show="!setSeed && !hwLedger" ><span translate>Seed Passphrase</span> <small translate>Add an optional passphrase to secure the seed</small>
<div class="input">
<input type="text" class="form-control"
name="createPassphrase" ng-model="createPassphrase">
</div>
</label>
<label for="ext-master" class="m10t" ng-show="setSeed">
<label for="ext-master" class="m10t" ng-show="setSeed && !hwLedger">
<span translate>Wallet Seed</span>
<small translate>Enter the 12 words seed (BIP39)</small>
<input id="ext-master"
type="text"
name="privateKey" ng-model="privateKey">
</label>
<label for="passphrase" class="line-b oh" ng-show="setSeed"><span translate>Seed Passphrase</span> <small translate>The seed could require a passphrase to be imported</small>
<label for="passphrase" class="line-b oh" ng-show="setSeed && !hwLedger"><span translate>Seed Passphrase</span> <small translate>The seed could require a passphrase to be imported</small>
<div class="input">
<input type="text" class="form-control" name="passphrase" ng-model="passphrase">
</div>
@ -136,10 +136,6 @@
</span>
</div>
<button translate type="submit" class="button expand black m0 round"
ng-disabled="joinForm.$invalid || join.loading">Join</button>
</form>

View file

@ -106,7 +106,7 @@ angular.module('copayApp.controllers').controller('createController',
});
}
else {
if ( ( opts.mnemonic && opts.n==1) || otps.externalSource ) {
if ( ( opts.mnemonic && opts.n==1) || opts.externalSource ) {
$rootScope.$emit('Local/WalletImported', walletId);
} else {
go.walletHome();

View file

@ -1,12 +1,14 @@
'use strict';
angular.module('copayApp.controllers').controller('importController',
function($scope, $rootScope, $location, $timeout, $log, profileService, notification, go, isMobile, isCordova, sjcl, gettext, lodash) {
function($scope, $rootScope, $location, $timeout, $log, profileService, notification, go, isMobile, isCordova, sjcl, gettext, lodash, ledger) {
var self = this;
this.isSafari = isMobile.Safari();
this.isCordova = isCordova;
this.externalIndexValues = lodash.range(0, ledger.MAX_SLOT);
$scope.externalIndex = 0;
var reader = new FileReader();
window.ignoreMobilePause = true;
@ -80,13 +82,6 @@ angular.module('copayApp.controllers').controller('importController',
}, 100);
};
// {
// network: opts.network,
// m: opts.m,
// n: opts.n,
// publicKeyRing: opts.publicKeyRing,
// },
//
$scope.getFile = function() {
// If we use onloadend, we need to check the readyState.
reader.onloadend = function(evt) {
@ -146,10 +141,12 @@ angular.module('copayApp.controllers').controller('importController',
if (!words) {
this.error = gettext('Please enter the backup words');
} else {
var wordList = words.split(/ /).filter(function(v){ return v.length>0; });
var wordList = words.split(/ /).filter(function(v) {
return v.length > 0;
});
if (wordList.length != 12)
this.error = gettext('Please enter 12 backup words');
else
else
words = wordList.join(' ');
}
@ -166,4 +163,41 @@ angular.module('copayApp.controllers').controller('importController',
_importMnemonic(words, opts);
};
this.importLedger = function(form) {
var self = this;
if (form.$invalid) {
this.error = gettext('There is an error in the form');
$timeout(function() {
$scope.$apply();
});
return;
}
self.ledger = true;
ledger.getInfoForNewWallet($scope.externalIndex, function(err, lopts) {
self.ledger = false;
if (err) {
self.error = err;
$scope.$apply();
return;
}
lopts.externalIndex = $scope.externalIndex;
lopts.externalSource = 'ledger';
self.loading = true;
$log.debug('Import opts', lopts);
profileService.importExtendedPublicKey(lopts, function(err, walletId) {
self.loading = false;
if (err) {
self.error = err;
return $timeout(function() {
$scope.$apply();
});
}
$rootScope.$emit('Local/WalletImported', walletId);
notification.success(gettext('Success'), gettext('Your wallet has been imported correctly'));
go.walletHome();
});
}, 100);
};
});

View file

@ -3,6 +3,7 @@
angular.module('copayApp.controllers').controller('indexController', function($rootScope, $scope, $log, $filter, $timeout, lodash, go, profileService, configService, isCordova, rateService, storageService, addressService, gettext, amMoment, nodeWebkit, addonManager, feeService, isChromeApp, bwsError, txFormatService, uxLanguage, $state, glideraService) {
var self = this;
self.isCordova = isCordova;
self.isChromeApp = isChromeApp;
self.onGoingProcess = {};
self.limitHistory = 5;
@ -653,16 +654,18 @@ angular.module('copayApp.controllers').controller('indexController', function($r
return str;
}
var step = 6;
function getHistory(skip, cb) {
skip = skip || 0;
fc.getTxHistory({
skip: skip,
limit: 100
limit: step,
}, function(err, txs) {
if (err) return cb(err);
if (txs && txs.length > 0) {
allTxs.push(txs);
return getHistory(skip + 100, cb);
return getHistory(skip + step, cb);
} else {
return cb(null, lodash.flatten(allTxs));
}

View file

@ -4,7 +4,7 @@ angular.module('copayApp.controllers').controller('joinController',
function($scope, $rootScope, $timeout, go, isMobile, notification, profileService, isCordova, isChromeApp, $modal, gettext, lodash, ledger) {
var self = this;
this.externalIndexValues = lodash.range(0,20);
this.externalIndexValues = lodash.range(0,ledger.MAX_SLOT);
$scope.externalIndex = 0;
this.isChromeApp = function() {

View file

@ -25,7 +25,7 @@ angular.module('copayApp.services')
body = gettextCatalog.getString('Copayer already in this wallet');
break;
case 'COPAYER_REGISTERED':
body = gettextCatalog.getString('Copayer already registered');
body = gettextCatalog.getString('Wallet already registered');
break;
case 'COPAYER_VOTED':
body = gettextCatalog.getString('Copayer already voted on this spend proposal');

View file

@ -179,8 +179,9 @@ angular.module('copayApp.services')
}
} else if (opts.extendedPublicKey) {
try {
walletClient.seedFromExternalWalletPublicKey(opts.extendedPublicKey, opts.externalSource, opts.externalIndex, opts.entropySource);
walletClient.seedFromExtendedPublicKey(opts.extendedPublicKey, opts.externalSource, opts.externalIndex, opts.entropySource);
} catch (ex) {
$log.warn(ex);
return cb(gettext('Could not create using the specified extended public key'));
}
} else {
@ -191,7 +192,7 @@ angular.module('copayApp.services')
$log.info('Error creating seed: ' + e.message);
if (e.message.indexOf('language') > 0) {
$log.info('Using default language for mnemonic');
walletClient.seedFromRandomWithMnemonic(network, opts.passphrase);
walletClient.seedFromRandomWithMnemonic(network, opts.passphrase);
} else {
return cb(e);
}
@ -358,6 +359,26 @@ angular.module('copayApp.services')
});
};
root.importExtendedPublicKey = function(opts, cb) {
var walletClient = bwcService.getClient();
$log.debug('Importing Wallet XPubKey');
walletClient.importFromExtendedPublicKey(opts.extendedPublicKey, opts.externalSource, opts.externalIndex, opts.entropySource, function(err) {
if (err) {
// in HW wallets, req key is always the same. They can't addAccess.
if (err.code == 'NOT_AUTHORIZED')
err.code = 'WALLET_DOES_NOT_EXIST';
return bwsError.cb(err, gettext('Could not import'), cb);
}
root._addWalletClient(walletClient, cb);
});
};
root.create = function(opts, cb) {
$log.info('Creating profile');
configService.get(function(err) {