Wallet/src/js/controllers/import.js

375 lines
12 KiB
JavaScript
Raw Normal View History

2015-03-06 12:00:10 -03:00
'use strict';
angular.module('copayApp.controllers').controller('importController',
2016-12-27 15:19:53 -03:00
function($scope, $timeout, $log, $state, $stateParams, $ionicHistory, $ionicScrollDelegate, profileService, configService, sjcl, ledger, trezor, derivationPathHelper, platformInfo, bwcService, ongoingProcess, walletService, popupService, gettextCatalog, appConfigService) {
2015-03-06 12:00:10 -03:00
var reader = new FileReader();
2015-10-16 12:35:18 -03:00
var defaults = configService.getDefaults();
2016-06-07 17:11:57 -03:00
var errors = bwcService.getErrors();
2016-09-06 16:40:57 -03:00
$scope.init = function() {
2017-01-07 22:11:46 -03:00
$scope.isDevel = platformInfo.isDevel;
$scope.isChromeApp = platformInfo.isChromeApp;
2016-09-06 16:40:57 -03:00
$scope.isCordova = platformInfo.isCordova;
$scope.formData = {};
$scope.formData.bwsurl = defaults.bws.url;
$scope.formData.derivationPath = derivationPathHelper.default;
$scope.formData.account = 1;
$scope.importErr = false;
2017-01-07 22:11:46 -03:00
$scope.isCopay = appConfigService.name == 'copay';
2016-09-06 16:40:57 -03:00
if ($stateParams.code)
$scope.processWalletInfo($stateParams.code);
2016-06-29 10:19:49 -03:00
$scope.seedOptions = [];
2015-11-04 15:45:33 -03:00
2017-01-07 22:11:46 -03:00
if ($scope.isChromeApp) {
2016-06-29 10:19:49 -03:00
$scope.seedOptions.push({
2015-11-05 16:00:38 -03:00
id: 'ledger',
label: 'Ledger Hardware Wallet',
2015-11-05 16:00:38 -03:00
});
2016-12-28 17:50:53 -03:00
}
2015-11-05 16:00:38 -03:00
2017-01-07 22:11:46 -03:00
if ($scope.isChromeApp || $scope.isDevel) {
2016-06-29 10:19:49 -03:00
$scope.seedOptions.push({
2015-11-05 16:00:38 -03:00
id: 'trezor',
label: 'Trezor Hardware Wallet',
2015-11-05 16:00:38 -03:00
});
2016-12-28 17:50:53 -03:00
$scope.formData.seedSource = $scope.seedOptions[0];
2015-11-05 16:00:38 -03:00
}
2017-01-07 22:11:46 -03:00
$timeout(function() {
$scope.$apply();
});
2015-11-04 15:45:33 -03:00
};
2016-06-29 17:04:40 -03:00
$scope.processWalletInfo = function(code) {
2016-07-15 13:25:25 -03:00
if (!code) return;
2016-09-06 16:40:57 -03:00
2016-06-29 10:19:49 -03:00
$scope.importErr = false;
var parsedCode = code.split('|');
2016-06-28 17:29:47 -03:00
2016-06-29 17:04:40 -03:00
if (parsedCode.length != 5) {
2016-06-30 17:28:09 -03:00
/// Trying to import a malformed wallet export QR code
2016-09-01 10:56:13 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Incorrect code format'));
2016-06-28 17:29:47 -03:00
return;
}
var info = {
type: parsedCode[0],
2016-06-28 17:29:47 -03:00
data: parsedCode[1],
2016-06-29 17:04:40 -03:00
network: parsedCode[2],
derivationPath: parsedCode[3],
hasPassphrase: parsedCode[4] == 'true' ? true : false
};
if (info.type == 1 && info.hasPassphrase)
2016-10-26 17:10:21 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Password required. Make sure to enter your password in advanced options'));
2016-09-06 16:40:57 -03:00
$scope.formData.derivationPath = info.derivationPath;
$scope.formData.testnetEnabled = info.network == 'testnet' ? true : false;
$timeout(function() {
2016-09-06 16:40:57 -03:00
$scope.formData.words = info.data;
$scope.$apply();
}, 1);
2015-08-24 17:09:59 -03:00
};
var _importBlob = function(str, opts) {
var str2, err;
2015-03-06 12:00:10 -03:00
try {
2016-09-06 15:11:02 -03:00
str2 = sjcl.decrypt($scope.formData.password, str);
2015-03-06 12:00:10 -03:00
} catch (e) {
2016-09-01 10:56:13 -03:00
err = gettextCatalog.getString('Could not decrypt file, check your password');
2015-03-06 12:00:10 -03:00
$log.warn(e);
};
if (err) {
2016-09-01 10:56:13 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), err);
return;
}
2016-06-13 15:25:40 -03:00
ongoingProcess.set('importingWallet', true);
2015-10-20 12:03:08 -03:00
opts.compressed = null;
opts.password = null;
2015-03-06 12:00:10 -03:00
$timeout(function() {
2016-08-18 00:27:23 -03:00
profileService.importWallet(str2, opts, function(err, client) {
2016-06-13 15:25:40 -03:00
ongoingProcess.set('importingWallet', false);
2015-03-06 12:00:10 -03:00
if (err) {
2016-09-01 10:56:13 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), err);
2016-08-15 16:07:30 -03:00
return;
2015-03-06 12:00:10 -03:00
}
2016-09-01 16:03:43 -03:00
finish(client);
2015-03-06 12:00:10 -03:00
});
}, 100);
};
2015-10-20 12:03:08 -03:00
var _importExtendedPrivateKey = function(xPrivKey, opts) {
2016-06-13 15:25:40 -03:00
ongoingProcess.set('importingWallet', true);
2015-09-05 00:11:14 -03:00
$timeout(function() {
2016-08-18 00:27:23 -03:00
profileService.importExtendedPrivateKey(xPrivKey, opts, function(err, client) {
2016-06-13 15:25:40 -03:00
ongoingProcess.set('importingWallet', false);
2015-09-05 00:11:14 -03:00
if (err) {
2016-06-07 17:11:57 -03:00
if (err instanceof errors.NOT_AUTHORIZED) {
2016-06-29 10:19:49 -03:00
$scope.importErr = true;
2016-06-07 17:11:57 -03:00
} else {
2016-09-01 10:56:13 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), err);
2016-06-07 17:11:57 -03:00
}
2015-09-05 00:11:14 -03:00
return $timeout(function() {
$scope.$apply();
});
}
2016-09-01 16:03:43 -03:00
finish(client);
2015-09-05 00:11:14 -03:00
});
}, 100);
};
2016-06-29 17:04:40 -03:00
/*
IMPORT FROM PUBLIC KEY - PENDING
var _importExtendedPublicKey = function(xPubKey, opts) {
ongoingProcess.set('importingWallet', true);
$timeout(function() {
profileService.importExtendedPublicKey(opts, function(err, walletId) {
ongoingProcess.set('importingWallet', false);
if (err) {
$scope.error = err;
return $timeout(function() {
$scope.$apply();
});
}
2016-09-01 16:08:41 -03:00
profileService.setBackupFlag(walletId);
if ($stateParams.fromOnboarding) {
profileService.setDisclaimerAccepted(function(err) {
if (err) $log.error(err);
});
}
2016-09-06 15:11:02 -03:00
2016-08-19 13:07:18 -03:00
$state.go('tabs.home');
2016-06-29 17:04:40 -03:00
});
}, 100);
};
*/
2015-09-03 01:49:48 -03:00
var _importMnemonic = function(words, opts) {
2016-06-13 15:25:40 -03:00
ongoingProcess.set('importingWallet', true);
2015-08-24 17:09:59 -03:00
$timeout(function() {
2016-08-18 00:27:23 -03:00
profileService.importMnemonic(words, opts, function(err, client) {
2016-06-13 15:25:40 -03:00
ongoingProcess.set('importingWallet', false);
2016-06-07 17:11:57 -03:00
if (err) {
if (err instanceof errors.NOT_AUTHORIZED) {
2016-06-29 10:19:49 -03:00
$scope.importErr = true;
2016-06-07 17:11:57 -03:00
} else {
2016-09-01 10:56:13 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), err);
2016-06-07 17:11:57 -03:00
}
2015-08-24 17:09:59 -03:00
return $timeout(function() {
$scope.$apply();
});
}
2016-09-01 16:03:43 -03:00
finish(client);
2015-08-24 17:09:59 -03:00
});
}, 100);
};
2016-09-06 15:11:02 -03:00
$scope.setDerivationPath = function() {
2016-09-06 16:40:57 -03:00
$scope.formData.derivationPath = $scope.formData.testnetEnabled ? derivationPathHelper.defaultTestnet : derivationPathHelper.default;
};
2015-03-06 12:00:10 -03:00
$scope.getFile = function() {
// If we use onloadend, we need to check the readyState.
reader.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
2015-10-20 12:03:08 -03:00
var opts = {};
2016-09-06 15:11:02 -03:00
opts.bwsurl = $scope.formData.bwsurl;
2015-10-20 12:03:08 -03:00
_importBlob(evt.target.result, opts);
2015-03-06 12:00:10 -03:00
}
}
};
2016-06-29 10:19:49 -03:00
$scope.importBlob = function(form) {
2015-03-06 12:00:10 -03:00
if (form.$invalid) {
2016-09-01 10:56:13 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('There is an error in the form'));
2015-03-06 12:00:10 -03:00
return;
}
2016-09-06 15:11:02 -03:00
var backupFile = $scope.formData.file;
var backupText = $scope.formData.backupText;
var password = $scope.formData.password;
2015-03-06 12:00:10 -03:00
if (!backupFile && !backupText) {
2016-09-01 10:56:13 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Please, select your backup file'));
2015-03-06 12:00:10 -03:00
return;
}
if (backupFile) {
reader.readAsBinaryString(backupFile);
} else {
2015-10-20 12:03:08 -03:00
var opts = {};
2016-09-06 15:11:02 -03:00
opts.bwsurl = $scope.formData.bwsurl;
2015-10-20 12:03:08 -03:00
_importBlob(backupText, opts);
2015-08-24 17:09:59 -03:00
}
};
2016-06-29 10:19:49 -03:00
$scope.importMnemonic = function(form) {
2015-08-24 17:09:59 -03:00
if (form.$invalid) {
2016-09-01 10:56:13 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('There is an error in the form'));
2015-08-24 17:09:59 -03:00
return;
}
var opts = {};
2016-09-06 15:11:02 -03:00
if ($scope.formData.bwsurl)
opts.bwsurl = $scope.formData.bwsurl;
2016-09-06 16:40:57 -03:00
var pathData = derivationPathHelper.parse($scope.formData.derivationPath);
2016-05-09 12:03:25 -03:00
if (!pathData) {
2016-09-01 10:56:13 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid derivation path'));
2016-05-09 12:03:25 -03:00
return;
}
2016-09-06 15:11:02 -03:00
2016-05-09 12:03:25 -03:00
opts.account = pathData.account;
opts.networkName = pathData.networkName;
opts.derivationStrategy = pathData.derivationStrategy;
2016-09-06 15:11:02 -03:00
var words = $scope.formData.words || null;
2015-08-24 17:09:59 -03:00
2015-09-02 15:56:00 -03:00
if (!words) {
2016-10-26 17:10:21 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Please enter the recovery phrase'));
2016-12-29 13:37:00 -03:00
return;
2015-10-16 12:35:18 -03:00
} else if (words.indexOf('xprv') == 0 || words.indexOf('tprv') == 0) {
2015-10-20 12:03:08 -03:00
return _importExtendedPrivateKey(words, opts);
2016-06-29 17:04:40 -03:00
} else if (words.indexOf('xpub') == 0 || words.indexOf('tpuv') == 0) {
return _importExtendedPublicKey(words, opts);
2015-09-02 15:56:00 -03:00
} else {
var wordList = words.split(/[\u3000\s]+/);
2015-09-05 01:02:01 -03:00
2016-05-30 16:32:28 -03:00
if ((wordList.length % 3) != 0) {
2016-10-26 17:10:21 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Wrong number of recovery words: ') + wordList.length);
2016-09-01 10:56:13 -03:00
return;
2016-05-30 16:32:28 -03:00
}
2015-09-02 15:56:00 -03:00
}
2016-09-06 15:11:02 -03:00
opts.passphrase = $scope.formData.passphrase || null;
2015-09-03 01:49:48 -03:00
_importMnemonic(words, opts);
2015-03-06 12:00:10 -03:00
};
2016-06-29 10:19:49 -03:00
$scope.importTrezor = function(account, isMultisig) {
2015-11-04 00:53:26 -03:00
trezor.getInfoForNewWallet(isMultisig, account, function(err, lopts) {
2016-06-13 15:25:40 -03:00
ongoingProcess.clear();
if (err) {
2016-09-01 10:56:13 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), err);
return;
}
2015-10-20 12:46:46 -03:00
lopts.externalSource = 'trezor';
2016-09-06 16:40:57 -03:00
lopts.bwsurl = $scope.formData.bwsurl;
2016-06-13 15:25:40 -03:00
ongoingProcess.set('importingWallet', true);
$log.debug('Import opts', lopts);
2015-10-20 12:46:46 -03:00
2016-08-15 16:07:30 -03:00
profileService.importExtendedPublicKey(lopts, function(err, wallet) {
2016-06-13 15:25:40 -03:00
ongoingProcess.set('importingWallet', false);
if (err) {
2016-09-01 10:56:13 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), err);
return;
}
2016-09-01 16:03:43 -03:00
finish(wallet);
});
}, 100);
};
2016-06-29 10:19:49 -03:00
$scope.importHW = function(form) {
2016-12-28 16:49:42 -03:00
if (form.$invalid || $scope.formData.account < 0) {
2016-10-26 17:10:21 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('There is an error in the form'));
return;
}
2016-09-06 16:40:57 -03:00
2016-06-29 10:19:49 -03:00
$scope.importErr = false;
2015-11-04 15:45:33 -03:00
2016-12-28 16:49:42 -03:00
var account = $scope.formData.account;
2016-05-30 16:32:28 -03:00
2016-12-28 17:50:53 -03:00
if ($scope.formData.seedSource.id == 'trezor') {
2016-05-30 16:32:28 -03:00
if (account < 1) {
2016-10-26 17:10:21 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid account number'));
return;
}
account = account - 1;
}
2015-11-04 15:45:33 -03:00
2016-12-28 17:50:53 -03:00
switch ($scope.formData.seedSource.id) {
2015-11-04 15:45:33 -03:00
case ('ledger'):
2016-06-13 15:25:40 -03:00
ongoingProcess.set('connectingledger', true);
2016-06-29 10:19:49 -03:00
$scope.importLedger(account);
2015-11-04 15:45:33 -03:00
break;
case ('trezor'):
2016-06-13 15:25:40 -03:00
ongoingProcess.set('connectingtrezor', true);
2016-09-06 16:40:57 -03:00
$scope.importTrezor(account, $scope.formData.isMultisig);
2015-11-04 15:45:33 -03:00
break;
default:
throw ('Error: bad source id');
};
};
2016-06-29 10:19:49 -03:00
$scope.importLedger = function(account) {
2015-11-04 00:53:26 -03:00
ledger.getInfoForNewWallet(true, account, function(err, lopts) {
2016-06-13 15:25:40 -03:00
ongoingProcess.clear();
if (err) {
2016-09-01 10:56:13 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), err);
return;
}
2015-10-20 12:46:46 -03:00
lopts.externalSource = 'ledger';
2016-09-06 16:40:57 -03:00
lopts.bwsurl = $scope.formData.bwsurl;
2016-06-13 15:25:40 -03:00
ongoingProcess.set('importingWallet', true);
$log.debug('Import opts', lopts);
2015-10-20 12:46:46 -03:00
2016-08-15 16:07:30 -03:00
profileService.importExtendedPublicKey(lopts, function(err, wallet) {
2016-06-13 15:25:40 -03:00
ongoingProcess.set('importingWallet', false);
if (err) {
2016-09-01 10:56:13 -03:00
popupService.showAlert(gettextCatalog.getString('Error'), err);
return;
}
2016-09-01 16:03:43 -03:00
finish(wallet);
});
}, 100);
};
2016-08-15 16:07:30 -03:00
2016-09-01 16:03:43 -03:00
var finish = function(wallet) {
2017-01-16 16:00:09 -03:00
walletService.updateRemotePreferences(wallet);
2016-08-30 17:31:29 -03:00
2016-09-01 16:03:43 -03:00
profileService.setBackupFlag(wallet.credentials.walletId);
if ($stateParams.fromOnboarding) {
profileService.setDisclaimerAccepted(function(err) {
if (err) $log.error(err);
});
2016-09-01 16:03:43 -03:00
}
2016-09-23 12:42:33 -03:00
$ionicHistory.removeBackView();
$state.go('tabs.home', {
fromOnboarding: $stateParams.fromOnboarding
});
};
2016-10-12 17:43:23 -03:00
$scope.showAdvChange = function() {
$scope.showAdv = !$scope.showAdv;
2017-01-06 19:03:09 -03:00
$timeout(function() {
$scope.resizeView();
}, 100);
2016-10-12 17:43:23 -03:00
};
$scope.resizeView = function() {
$timeout(function() {
$ionicScrollDelegate.resize();
}, 10);
2016-10-12 17:43:23 -03:00
};
2017-01-04 20:43:04 -03:00
$scope.$on("$ionicView.afterEnter", function(event, data) {
2017-01-06 19:03:09 -03:00
$scope.showAdv = false;
$scope.init();
});
2015-03-06 12:00:10 -03:00
});