commit
55d657f0f0
87 changed files with 2059 additions and 609 deletions
|
|
@ -146,7 +146,7 @@ module.exports = function(grunt) {
|
|||
'src/js/externalServices.js',
|
||||
'src/js/init.js',
|
||||
'src/js/trezor-url.js',
|
||||
'bower_components/trezor-connect/login.js',
|
||||
'bower_components/trezor-connect/connect.js',
|
||||
'node_modules/bezier-easing/dist/bezier-easing.min.js',
|
||||
'node_modules/cordova-plugin-qrscanner/dist/cordova-plugin-qrscanner-lib.min.js'
|
||||
],
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@
|
|||
"windowsAppId": "2d1002d7-ee34-4f60-bd29-0c871ba0c195",
|
||||
"pushSenderId": "1036948132229",
|
||||
"description": "Secure Bitcoin Wallet",
|
||||
"version": "3.0.7",
|
||||
"androidVersion": "306000",
|
||||
"version": "3.1.1",
|
||||
"androidVersion": "311000",
|
||||
"_extraCSS": null,
|
||||
"_enabledExtensions": {
|
||||
"coinbase": true,
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@
|
|||
"windowsAppId": "804636ee-b017-4cad-8719-e58ac97ffa5c",
|
||||
"pushSenderId": "1036948132229",
|
||||
"description": "A Secure Bitcoin Wallet",
|
||||
"version": "3.0.7",
|
||||
"androidVersion": "306000",
|
||||
"version": "3.1.1",
|
||||
"androidVersion": "311000",
|
||||
"_extraCSS": null,
|
||||
"_enabledExtensions": {
|
||||
"coinbase": true,
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
"build:windows": "cordova prepare windows && cordova build windows -- --arch=\"x86\"",
|
||||
"build:ios-release": "cordova prepare ios && cordova build ios --release",
|
||||
"build:android-release": "cordova prepare android && cordova build android --release",
|
||||
"build:windows-release": "cordova prepare windows && cordova build windows --release --arch=\"x86\"",
|
||||
"build:desktop": "grunt desktop",
|
||||
"build:macos": "grunt macos",
|
||||
"open:ios": "open platforms/ios/*.xcodeproj",
|
||||
|
|
@ -101,6 +102,7 @@
|
|||
"final:www": "npm run build:www-release",
|
||||
"final:ios": "npm run final:www && npm run build:ios-release && npm run open:ios",
|
||||
"final:android": "npm run final:www && npm run build:android-release && npm run sign:android && npm run run:android-release",
|
||||
"final:windows": "npm run final:www && npm run build:windows-release",
|
||||
"final:desktop": "npm run build:desktop && npm run build:macos",
|
||||
"run:android": "cordova run android --device",
|
||||
"run:android-release": "cordova run android --device --release",
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@
|
|||
"angular-gettext": "2.2.1",
|
||||
"angular-moment": "0.10.1",
|
||||
"angular-qrcode": "bitpay/angular-qrcode#~6.3.0",
|
||||
"ionic": "1.3.1",
|
||||
"ionic": "https://github.com/driftyco/ionic-v1.git",
|
||||
"moment": "2.10.3",
|
||||
"ng-lodash": "0.2.3",
|
||||
"qrcode-decoder-js": "*",
|
||||
"trezor-connect": "~1.0.1",
|
||||
"trezor-connect": "~1.1.3",
|
||||
"ng-csv": "~0.3.6",
|
||||
"ionic-toast": "^0.4.1",
|
||||
"angular-clipboard": "^1.4.2",
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
"ngtouch": "^1.0.1"
|
||||
},
|
||||
"resolutions": {
|
||||
"angular": "1.5.3"
|
||||
"angular": "1.5.3",
|
||||
"ionic": "298ad4b645"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('advancedSettingsController', function($scope, $rootScope, $log, $window, lodash, configService, uxLanguage, platformInfo, profileService, feeService, storageService, $ionicHistory, $timeout, $ionicScrollDelegate) {
|
||||
angular.module('copayApp.controllers').controller('advancedSettingsController', function($scope, $log, configService) {
|
||||
|
||||
var updateConfig = function() {
|
||||
var config = configService.getSync();
|
||||
|
|
@ -11,7 +11,6 @@ angular.module('copayApp.controllers').controller('advancedSettingsController',
|
|||
$scope.recentTransactionsEnabled = {
|
||||
value: config.recentTransactions.enabled
|
||||
};
|
||||
|
||||
$scope.hideNextSteps = {
|
||||
value: config.hideNextSteps.enabled
|
||||
};
|
||||
|
|
@ -31,7 +30,7 @@ angular.module('copayApp.controllers').controller('advancedSettingsController',
|
|||
$scope.nextStepsChange = function() {
|
||||
var opts = {
|
||||
hideNextSteps: {
|
||||
enabled: $scope.hideNextSteps.value
|
||||
enabled: $scope.hideNextSteps.value
|
||||
},
|
||||
};
|
||||
configService.set(opts, function(err) {
|
||||
|
|
|
|||
|
|
@ -29,15 +29,18 @@ angular.module('copayApp.controllers').controller('amazonCardsController',
|
|||
var index = 0;
|
||||
var gcds = $scope.giftCards;
|
||||
lodash.forEach(gcds, function(dataFromStorage) {
|
||||
if (dataFromStorage.status == 'PENDING') {
|
||||
$log.debug("creating gift card");
|
||||
if (dataFromStorage.status == 'PENDING' || dataFromStorage.status == 'invalid') {
|
||||
$log.debug("Creating / Updating gift card");
|
||||
$scope.updatingPending[dataFromStorage.invoiceId] = true;
|
||||
|
||||
amazonService.createGiftCard(dataFromStorage, function(err, giftCard) {
|
||||
|
||||
$scope.updatingPending[dataFromStorage.invoiceId] = false;
|
||||
if (err) {
|
||||
popupService.showAlert('Error creating gift card', err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (giftCard.status != 'PENDING') {
|
||||
var newData = {};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('amountController', function($scope, $filter, $timeout, $ionicScrollDelegate, $ionicHistory, gettextCatalog, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, txFormatService, ongoingProcess, popupService, bwcError, payproService, profileService, bitcore, amazonService) {
|
||||
angular.module('copayApp.controllers').controller('amountController', function($scope, $filter, $timeout, $ionicScrollDelegate, $ionicHistory, gettextCatalog, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, txFormatService, ongoingProcess, popupService, bwcError, payproService, profileService, bitcore, amazonService, nodeWebkitService) {
|
||||
var _cardId;
|
||||
var unitToSatoshi;
|
||||
var satToUnit;
|
||||
|
|
@ -8,6 +8,7 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
var satToBtc;
|
||||
var SMALL_FONT_SIZE_LIMIT = 10;
|
||||
var LENGTH_EXPRESSION_LIMIT = 19;
|
||||
var isNW = platformInfo.isNW;
|
||||
$scope.isChromeApp = platformInfo.isChromeApp;
|
||||
|
||||
$scope.$on('$ionicView.leave', function() {
|
||||
|
|
@ -15,14 +16,14 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
});
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
|
||||
// Go to...
|
||||
_cardId = data.stateParams.id; // Optional (BitPay Card ID)
|
||||
$scope.nextStep = data.stateParams.nextStep;
|
||||
$scope.currency = data.stateParams.currency;
|
||||
$scope.forceCurrency = data.stateParams.forceCurrency;
|
||||
|
||||
$scope.showMenu = $ionicHistory.backView() && $ionicHistory.backView().stateName == 'tabs.send';
|
||||
$scope.showMenu = $ionicHistory.backView() && ($ionicHistory.backView().stateName == 'tabs.send' ||
|
||||
$ionicHistory.backView().stateName == 'tabs.bitpayCard');
|
||||
$scope.recipientType = data.stateParams.recipientType || null;
|
||||
$scope.toAddress = data.stateParams.toAddress;
|
||||
$scope.toName = data.stateParams.toName;
|
||||
|
|
@ -42,18 +43,20 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
var reOp = /^[\*\+\-\/]$/;
|
||||
|
||||
var disableKeys = angular.element($window).on('keydown', function(e) {
|
||||
if (!e.key) return;
|
||||
if (e.which === 8) { // you can add others here inside brackets.
|
||||
e.preventDefault();
|
||||
$scope.removeDigit();
|
||||
}
|
||||
|
||||
if (e.key && e.key.match(reNr))
|
||||
if (e.key.match(reNr)) {
|
||||
$scope.pushDigit(e.key);
|
||||
|
||||
else if (e.key && e.key.match(reOp))
|
||||
} else if (e.key.match(reOp)) {
|
||||
$scope.pushOperator(e.key);
|
||||
|
||||
else if (e.key && e.key == 'Enter')
|
||||
} else if (e.keyCode === 86) {
|
||||
if (e.ctrlKey || e.metaKey)
|
||||
processClipboard();
|
||||
} else if (e.keyCode === 13)
|
||||
$scope.finish();
|
||||
|
||||
$timeout(function() {
|
||||
|
|
@ -82,28 +85,35 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
$scope.amount = (($stateParams.toAmount) * satToUnit).toFixed(unitDecimals);
|
||||
}
|
||||
|
||||
processAmount($scope.amount);
|
||||
processAmount();
|
||||
|
||||
$timeout(function() {
|
||||
$ionicScrollDelegate.resize();
|
||||
}, 10);
|
||||
});
|
||||
|
||||
function paste(value) {
|
||||
$scope.amount = value;
|
||||
processAmount();
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
};
|
||||
|
||||
function processClipboard() {
|
||||
if (!isNW) return;
|
||||
var value = nodeWebkitService.readFromClipboard();
|
||||
if (value && evaluate(value) > 0) paste(evaluate(value));
|
||||
};
|
||||
|
||||
$scope.showSendMaxMenu = function() {
|
||||
$scope.showSendMax = true;
|
||||
};
|
||||
|
||||
$scope.sendMax = function() {
|
||||
$scope.showSendMax = false;
|
||||
$state.transitionTo('tabs.send.confirm', {
|
||||
recipientType: $scope.recipientType,
|
||||
toAmount: null,
|
||||
toAddress: $scope.toAddress,
|
||||
toName: $scope.toName,
|
||||
toEmail: $scope.toEmail,
|
||||
toColor: $scope.toColor,
|
||||
useSendMax: true,
|
||||
});
|
||||
$scope.useSendMax = true;
|
||||
$scope.finish();
|
||||
};
|
||||
|
||||
$scope.toggleAlternative = function() {
|
||||
|
|
@ -128,7 +138,7 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
|
||||
$scope.amount = ($scope.amount + digit).replace('..', '.');
|
||||
checkFontSize();
|
||||
processAmount($scope.amount);
|
||||
processAmount();
|
||||
};
|
||||
|
||||
$scope.pushOperator = function(operator) {
|
||||
|
|
@ -156,7 +166,7 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
|
||||
$scope.removeDigit = function() {
|
||||
$scope.amount = $scope.amount.slice(0, -1);
|
||||
processAmount($scope.amount);
|
||||
processAmount();
|
||||
checkFontSize();
|
||||
};
|
||||
|
||||
|
|
@ -166,17 +176,12 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
checkFontSize();
|
||||
};
|
||||
|
||||
function processAmount(val) {
|
||||
if (!val) {
|
||||
$scope.resetAmount();
|
||||
return;
|
||||
}
|
||||
|
||||
var formatedValue = format(val);
|
||||
function processAmount() {
|
||||
var formatedValue = format($scope.amount);
|
||||
var result = evaluate(formatedValue);
|
||||
$scope.allowSend = lodash.isNumber(result) && +result > 0;
|
||||
if (lodash.isNumber(result)) {
|
||||
$scope.globalResult = isExpression(val) ? '= ' + processResult(result) : '';
|
||||
$scope.globalResult = isExpression($scope.amount) ? '= ' + processResult(result) : '';
|
||||
$scope.amountResult = $filter('formatFiatAmount')(toFiat(result));
|
||||
$scope.alternativeResult = txFormatService.formatAmount(fromFiat(result) * unitToSatoshi, true);
|
||||
}
|
||||
|
|
@ -223,8 +228,9 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
if ($scope.nextStep) {
|
||||
$state.transitionTo($scope.nextStep, {
|
||||
id: _cardId,
|
||||
amount: _amount,
|
||||
currency: $scope.showAlternativeAmount ? $scope.alternativeIsoCode : ''
|
||||
amount: $scope.useSendMax ? null : _amount,
|
||||
currency: $scope.showAlternativeAmount ? $scope.alternativeIsoCode : $scope.unitName,
|
||||
useSendMax: $scope.useSendMax
|
||||
});
|
||||
} else {
|
||||
var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount;
|
||||
|
|
@ -236,13 +242,15 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
} else {
|
||||
$state.transitionTo('tabs.send.confirm', {
|
||||
recipientType: $scope.recipientType,
|
||||
toAmount: (amount * unitToSatoshi).toFixed(0),
|
||||
toAmount: $scope.useSendMax ? null : (amount * unitToSatoshi).toFixed(0),
|
||||
toAddress: $scope.toAddress,
|
||||
toName: $scope.toName,
|
||||
toEmail: $scope.toEmail,
|
||||
toColor: $scope.toColor,
|
||||
useSendMax: $scope.useSendMax
|
||||
});
|
||||
}
|
||||
}
|
||||
$scope.useSendMax = null;
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('backController', function($scope, $state, $stateParams, platformInfo) {
|
||||
|
||||
var isCordova = platformInfo.isCordova;
|
||||
var isWP = platformInfo.isWP;
|
||||
var usePushNotifications = isCordova && !isWP;
|
||||
angular.module('copayApp.controllers').controller('backController', function($scope, $state, $stateParams) {
|
||||
|
||||
$scope.importGoBack = function() {
|
||||
if ($stateParams.fromOnboarding) $state.go('onboarding.welcome');
|
||||
|
|
@ -12,8 +8,7 @@ angular.module('copayApp.controllers').controller('backController', function($sc
|
|||
};
|
||||
|
||||
$scope.onboardingMailSkip = function() {
|
||||
if (!usePushNotifications) $state.go('onboarding.backupRequest');
|
||||
else $state.go('onboarding.notifications');
|
||||
$state.go('onboarding.backupRequest');
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -112,8 +112,13 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio
|
|||
$scope.network = amazonService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: $scope.network
|
||||
network: $scope.network,
|
||||
hasFunds: true
|
||||
});
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('No wallets with funds');
|
||||
return;
|
||||
}
|
||||
$scope.wallet = $scope.wallets[0]; // Default first wallet
|
||||
});
|
||||
|
||||
|
|
@ -140,7 +145,13 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio
|
|||
amazonService.createBitPayInvoice(dataSrc, function(err, dataInvoice) {
|
||||
if (err) {
|
||||
ongoingProcess.set('buyingGiftCard', false, statusChangeHandler);
|
||||
showError('Error creating BitPay invoice', err);
|
||||
|
||||
if (err && err.message && err.message.match(/suspended/i)) {
|
||||
showError('Service not available', 'Amazon Gift Card Service is not available at this moment. Please try back later.');
|
||||
} else {
|
||||
showError('Could not access Gift Card Service', err);
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('buyCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService) {
|
||||
angular.module('copayApp.controllers').controller('buyCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService, txFormatService) {
|
||||
|
||||
var amount;
|
||||
var currency;
|
||||
|
|
@ -34,8 +34,8 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct
|
|||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.isFiat = data.stateParams.currency ? true : false;
|
||||
var parsedAmount = coinbaseService.parseAmount(
|
||||
$scope.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
data.stateParams.amount,
|
||||
data.stateParams.currency);
|
||||
|
||||
|
|
@ -48,6 +48,11 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct
|
|||
onlyComplete: true,
|
||||
network: $scope.network
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('No wallets available');
|
||||
return;
|
||||
}
|
||||
$scope.wallet = $scope.wallets[0]; // Default first wallet
|
||||
|
||||
ongoingProcess.set('connectingCoinbase', true);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('buyGlideraController', function($scope, $log, $state, $timeout, $ionicHistory, lodash, glideraService, popupService, profileService, ongoingProcess, walletService, platformInfo) {
|
||||
angular.module('copayApp.controllers').controller('buyGlideraController', function($scope, $log, $state, $timeout, $ionicHistory, lodash, glideraService, popupService, profileService, ongoingProcess, walletService, platformInfo, txFormatService) {
|
||||
|
||||
var amount;
|
||||
var currency;
|
||||
|
|
@ -36,8 +36,8 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
|
|||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.isFiat = data.stateParams.currency ? true : false;
|
||||
var parsedAmount = glideraService.parseAmount(
|
||||
$scope.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
data.stateParams.amount,
|
||||
data.stateParams.currency);
|
||||
|
||||
|
|
@ -50,6 +50,11 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
|
|||
onlyComplete: true,
|
||||
network: $scope.network
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('No wallets available');
|
||||
return;
|
||||
}
|
||||
$scope.wallet = $scope.wallets[0]; // Default first wallet
|
||||
|
||||
ongoingProcess.set('connectingGlidera', true);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('createController',
|
||||
function($scope, $rootScope, $timeout, $log, lodash, $state, $ionicScrollDelegate, $ionicHistory, profileService, configService, gettextCatalog, ledger, trezor, platformInfo, derivationPathHelper, ongoingProcess, walletService, storageService, popupService, appConfigService) {
|
||||
|
||||
var isChromeApp = platformInfo.isChromeApp;
|
||||
var isCordova = platformInfo.isCordova;
|
||||
var isDevel = platformInfo.isDevel;
|
||||
function($scope, $rootScope, $timeout, $log, lodash, $state, $ionicScrollDelegate, $ionicHistory, profileService, configService, gettextCatalog, ledger, trezor, intelTEE, derivationPathHelper, ongoingProcess, walletService, storageService, popupService, appConfigService) {
|
||||
|
||||
/* For compressed keys, m*73 + n*34 <= 496 */
|
||||
var COPAYER_PAIR_LIMITS = {
|
||||
|
|
@ -67,9 +63,11 @@ angular.module('copayApp.controllers').controller('createController',
|
|||
var seedOptions = [{
|
||||
id: 'new',
|
||||
label: gettextCatalog.getString('Random'),
|
||||
}, {
|
||||
supportsTestnet: true
|
||||
}, {
|
||||
id: 'set',
|
||||
label: gettextCatalog.getString('Specify Recovery Phrase...'),
|
||||
supportsTestnet: false
|
||||
}];
|
||||
|
||||
$scope.seedSource = seedOptions[0];
|
||||
|
|
@ -81,16 +79,26 @@ angular.module('copayApp.controllers').controller('createController',
|
|||
*/
|
||||
|
||||
if (appConfigService.name == 'copay') {
|
||||
if (n > 1 && isChromeApp) {
|
||||
if (n > 1 && walletService.externalSource.ledger.supported)
|
||||
seedOptions.push({
|
||||
id: 'ledger',
|
||||
label: 'Ledger Hardware Wallet',
|
||||
id: walletService.externalSource.ledger.id,
|
||||
label: walletService.externalSource.ledger.longName,
|
||||
supportsTestnet: walletService.externalSource.ledger.supportsTestnet
|
||||
});
|
||||
|
||||
if (walletService.externalSource.trezor.supported) {
|
||||
seedOptions.push({
|
||||
id: walletService.externalSource.trezor.id,
|
||||
label: walletService.externalSource.trezor.longName,
|
||||
supportsTestnet: walletService.externalSource.trezor.supportsTestnet
|
||||
});
|
||||
}
|
||||
if (isChromeApp || isDevel) {
|
||||
|
||||
if (walletService.externalSource.intelTEE.supported) {
|
||||
seedOptions.push({
|
||||
id: 'trezor',
|
||||
label: 'Trezor Hardware Wallet',
|
||||
id: walletService.externalSource.intelTEE.id,
|
||||
label: walletService.externalSource.intelTEE.longName,
|
||||
supportsTestnet: walletService.externalSource.intelTEE.supportsTestnet
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -151,23 +159,37 @@ angular.module('copayApp.controllers').controller('createController',
|
|||
return;
|
||||
}
|
||||
|
||||
if ($scope.seedSource.id == 'ledger' || $scope.seedSource.id == 'trezor') {
|
||||
if ($scope.seedSource.id == walletService.externalSource.ledger.id || $scope.seedSource.id == walletService.externalSource.trezor.id || $scope.seedSource.id == walletService.externalSource.intelTEE.id) {
|
||||
var account = $scope.formData.account;
|
||||
if (!account || account < 1) {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid account number'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($scope.seedSource.id == 'trezor')
|
||||
if ($scope.seedSource.id == walletService.externalSource.trezor.id || $scope.seedSource.id == walletService.externalSource.intelTEE.id)
|
||||
account = account - 1;
|
||||
|
||||
opts.account = account;
|
||||
ongoingProcess.set('connecting' + $scope.seedSource.id, true);
|
||||
ongoingProcess.set('connecting ' + $scope.seedSource.id, true);
|
||||
|
||||
var src = $scope.seedSource.id == 'ledger' ? ledger : trezor;
|
||||
var src;
|
||||
switch ($scope.seedSource.id) {
|
||||
case walletService.externalSource.ledger.id:
|
||||
src = ledger;
|
||||
break;
|
||||
case walletService.externalSource.trezor.id:
|
||||
src = trezor;
|
||||
break;
|
||||
case walletService.externalSource.intelTEE.id:
|
||||
src = intelTEE;
|
||||
break;
|
||||
default:
|
||||
this.error = gettextCatalog.getString('Invalid seed source id: ' + $scope.seedSource.id);
|
||||
return;
|
||||
}
|
||||
|
||||
src.getInfoForNewWallet(opts.n > 1, account, function(err, lopts) {
|
||||
ongoingProcess.set('connecting' + $scope.seedSource.id, false);
|
||||
src.getInfoForNewWallet(opts.n > 1, account, opts.networkName, function(err, lopts) {
|
||||
ongoingProcess.set('connecting ' + $scope.seedSource.id, false);
|
||||
if (err) {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
return;
|
||||
|
|
@ -211,6 +233,6 @@ angular.module('copayApp.controllers').controller('createController',
|
|||
}, 100);
|
||||
} else $state.go('tabs.home');
|
||||
});
|
||||
}, 100);
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
var errors = bwcService.getErrors();
|
||||
|
||||
$scope.init = function() {
|
||||
$scope.isDevel = platformInfo.isDevel;
|
||||
$scope.isChromeApp = platformInfo.isChromeApp;
|
||||
$scope.supportsLedger = platformInfo.supportsLedger;
|
||||
$scope.supportsTrezor = platformInfo.supportsTrezor;
|
||||
$scope.isCordova = platformInfo.isCordova;
|
||||
$scope.formData = {};
|
||||
$scope.formData.bwsurl = defaults.bws.url;
|
||||
|
|
@ -23,17 +23,17 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
|
||||
$scope.seedOptions = [];
|
||||
|
||||
if ($scope.isChromeApp) {
|
||||
if ($scope.supportsLedger) {
|
||||
$scope.seedOptions.push({
|
||||
id: 'ledger',
|
||||
label: 'Ledger Hardware Wallet',
|
||||
id: walletService.externalSource.ledger.id,
|
||||
label: walletService.externalSource.ledger.longName,
|
||||
});
|
||||
}
|
||||
|
||||
if ($scope.isChromeApp || $scope.isDevel) {
|
||||
if ($scope.supportsTrezor) {
|
||||
$scope.seedOptions.push({
|
||||
id: 'trezor',
|
||||
label: 'Trezor Hardware Wallet',
|
||||
id: walletService.externalSource.trezor.id,
|
||||
label: walletService.externalSource.trezor.longName,
|
||||
});
|
||||
$scope.formData.seedSource = $scope.seedOptions[0];
|
||||
}
|
||||
|
|
@ -260,14 +260,14 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
};
|
||||
|
||||
$scope.importTrezor = function(account, isMultisig) {
|
||||
trezor.getInfoForNewWallet(isMultisig, account, function(err, lopts) {
|
||||
trezor.getInfoForNewWallet(isMultisig, account, 'livenet', function(err, lopts) {
|
||||
ongoingProcess.clear();
|
||||
if (err) {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
return;
|
||||
}
|
||||
|
||||
lopts.externalSource = 'trezor';
|
||||
lopts.externalSource = walletService.externalSource.trezor.id;
|
||||
lopts.bwsurl = $scope.formData.bwsurl;
|
||||
ongoingProcess.set('importingWallet', true);
|
||||
$log.debug('Import opts', lopts);
|
||||
|
|
@ -293,7 +293,7 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
|
||||
var account = $scope.formData.account;
|
||||
|
||||
if ($scope.formData.seedSource.id == 'trezor') {
|
||||
if ($scope.formData.seedSource.id == walletService.externalSource.trezor.id) {
|
||||
if (account < 1) {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid account number'));
|
||||
return;
|
||||
|
|
@ -302,11 +302,11 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
}
|
||||
|
||||
switch ($scope.formData.seedSource.id) {
|
||||
case ('ledger'):
|
||||
case (walletService.externalSource.ledger.id):
|
||||
ongoingProcess.set('connectingledger', true);
|
||||
$scope.importLedger(account);
|
||||
break;
|
||||
case ('trezor'):
|
||||
case (walletService.externalSource.trezor.id):
|
||||
ongoingProcess.set('connectingtrezor', true);
|
||||
$scope.importTrezor(account, $scope.formData.isMultisig);
|
||||
break;
|
||||
|
|
@ -316,14 +316,14 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
};
|
||||
|
||||
$scope.importLedger = function(account) {
|
||||
ledger.getInfoForNewWallet(true, account, function(err, lopts) {
|
||||
ledger.getInfoForNewWallet(true, account, 'livenet', function(err, lopts) {
|
||||
ongoingProcess.clear();
|
||||
if (err) {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
return;
|
||||
}
|
||||
|
||||
lopts.externalSource = 'ledger';
|
||||
lopts.externalSource = lopts.externalSource = walletService.externalSource.ledger.id;
|
||||
lopts.bwsurl = $scope.formData.bwsurl;
|
||||
ongoingProcess.set('importingWallet', true);
|
||||
$log.debug('Import opts', lopts);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('joinController',
|
||||
function($scope, $rootScope, $timeout, $state, $ionicHistory, $ionicScrollDelegate, profileService, configService, storageService, applicationService, gettextCatalog, lodash, ledger, trezor, platformInfo, derivationPathHelper, ongoingProcess, walletService, $log, $stateParams, popupService, appConfigService) {
|
||||
|
||||
var isChromeApp = platformInfo.isChromeApp;
|
||||
var isDevel = platformInfo.isDevel;
|
||||
function($scope, $rootScope, $timeout, $state, $ionicHistory, $ionicScrollDelegate, profileService, configService, storageService, applicationService, gettextCatalog, lodash, ledger, trezor, intelTEE, derivationPathHelper, ongoingProcess, walletService, $log, $stateParams, popupService, appConfigService) {
|
||||
|
||||
var self = this;
|
||||
var defaults = configService.getDefaults();
|
||||
|
|
@ -64,17 +61,24 @@ angular.module('copayApp.controllers').controller('joinController',
|
|||
*/
|
||||
|
||||
if (appConfigService.name == 'copay') {
|
||||
if (isChromeApp) {
|
||||
if (walletService.externalSource.ledger.supported) {
|
||||
self.seedOptions.push({
|
||||
id: 'ledger',
|
||||
label: 'Ledger Hardware Wallet',
|
||||
id: walletService.externalSource.ledger.id,
|
||||
label: walletService.externalSource.ledger.longName
|
||||
});
|
||||
}
|
||||
|
||||
if (isChromeApp || isDevel) {
|
||||
if (walletService.externalSource.trezor.supported) {
|
||||
self.seedOptions.push({
|
||||
id: 'trezor',
|
||||
label: 'Trezor Hardware Wallet',
|
||||
id: walletService.externalSource.trezor.id,
|
||||
label: walletService.externalSource.trezor.longName
|
||||
});
|
||||
}
|
||||
|
||||
if (walletService.externalSource.intelTEE.supported) {
|
||||
seedOptions.push({
|
||||
id: walletService.externalSource.intelTEE.id,
|
||||
label: walletService.externalSource.intelTEE.longName
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -97,7 +101,7 @@ angular.module('copayApp.controllers').controller('joinController',
|
|||
var opts = {
|
||||
secret: form.secret.$modelValue,
|
||||
myName: form.myName.$modelValue,
|
||||
bwsurl: $scope.bwsurl,
|
||||
bwsurl: $scope.bwsurl
|
||||
}
|
||||
|
||||
var setSeed = self.seedSourceId == 'set';
|
||||
|
|
@ -130,21 +134,38 @@ angular.module('copayApp.controllers').controller('joinController',
|
|||
return;
|
||||
}
|
||||
|
||||
if (self.seedSourceId == 'ledger' || self.seedSourceId == 'trezor') {
|
||||
if (self.seedSourceId == walletService.externalSource.ledger.id || self.seedSourceId == walletService.externalSource.trezor.id || self.seedSourceId == walletService.externalSource.intelTEE.id) {
|
||||
var account = $scope.account;
|
||||
if (!account || account < 1) {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid account number'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.seedSourceId == 'trezor')
|
||||
if (self.seedSourceId == walletService.externalSource.trezor.id || self.seedSourceId == walletService.externalSource.intelTEE.id)
|
||||
account = account - 1;
|
||||
|
||||
opts.account = account;
|
||||
opts.isMultisig = true;
|
||||
ongoingProcess.set('connecting' + self.seedSourceId, true);
|
||||
var src = self.seedSourceId == 'ledger' ? ledger : trezor;
|
||||
|
||||
src.getInfoForNewWallet(true, account, function(err, lopts) {
|
||||
var src;
|
||||
switch (self.seedSourceId) {
|
||||
case walletService.externalSource.ledger.id:
|
||||
src = ledger;
|
||||
break;
|
||||
case walletService.externalSource.trezor.id:
|
||||
src = trezor;
|
||||
break;
|
||||
case walletService.externalSource.intelTEE.id:
|
||||
src = intelTEE;
|
||||
break;
|
||||
default:
|
||||
this.error = gettextCatalog.getString('Invalid seed source id: ' + self.seedSourceId);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: cannot currently join an intelTEE testnet wallet (need to detect from the secret)
|
||||
src.getInfoForNewWallet(true, account, 'livenet', function(err, lopts) {
|
||||
ongoingProcess.set('connecting' + self.seedSourceId, false);
|
||||
if (err) {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
|
|
|
|||
121
src/js/controllers/lockSetup.js
Normal file
121
src/js/controllers/lockSetup.js
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('lockSetupController', function($state, $scope, $timeout, $log, configService, popupService, gettextCatalog, appConfigService, fingerprintService, profileService, lodash) {
|
||||
|
||||
function init() {
|
||||
$scope.options = [
|
||||
{
|
||||
method: null,
|
||||
label: gettextCatalog.getString('Disabled'),
|
||||
},
|
||||
{
|
||||
method: 'pin',
|
||||
label: gettextCatalog.getString('Lock by PIN'),
|
||||
needsBackup: null,
|
||||
},
|
||||
];
|
||||
|
||||
if (fingerprintService.isAvailable()) {
|
||||
$scope.options.push({
|
||||
method: 'fingerprint',
|
||||
label: gettextCatalog.getString('Lock by Fingerprint'),
|
||||
needsBackup: null,
|
||||
});
|
||||
}
|
||||
|
||||
var config = configService.getSync();
|
||||
var method = config.lock && config.lock.method;
|
||||
if (!method) $scope.currentOption = $scope.options[0];
|
||||
else $scope.currentOption = lodash.find($scope.options, {
|
||||
'method': method
|
||||
});
|
||||
processWallets();
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event) {
|
||||
init();
|
||||
});
|
||||
|
||||
function processWallets() {
|
||||
var wallets = profileService.getWallets();
|
||||
var singleLivenetWallet = wallets.length == 1 && wallets[0].network == 'livenet' && wallets[0].needsBackup;
|
||||
var atLeastOneLivenetWallet = lodash.any(wallets, function(w) {
|
||||
return w.network == 'livenet' && w.needsBackup;
|
||||
});
|
||||
|
||||
if (singleLivenetWallet) {
|
||||
$scope.errorMsg = gettextCatalog.getString('Backup your wallet before using this function');
|
||||
disableOptsUntilBackup();
|
||||
} else if (atLeastOneLivenetWallet) {
|
||||
$scope.errorMsg = gettextCatalog.getString('Backup all livenet wallets before using this function');
|
||||
disableOptsUntilBackup();
|
||||
} else {
|
||||
enableOptsAfterBackup();
|
||||
$scope.errorMsg = null;
|
||||
}
|
||||
|
||||
function enableOptsAfterBackup() {
|
||||
$scope.options[1].needsBackup = false;
|
||||
if ($scope.options[2]) $scope.options[2].needsBackup = false;
|
||||
};
|
||||
|
||||
function disableOptsUntilBackup() {
|
||||
$scope.options[1].needsBackup = true;
|
||||
if ($scope.options[2]) $scope.options[2].needsBackup = true;
|
||||
};
|
||||
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.select = function(selectedMethod) {
|
||||
var config = configService.getSync();
|
||||
var savedMethod = config.lock && config.lock.method;
|
||||
|
||||
if (!selectedMethod)
|
||||
saveConfig();
|
||||
else if (selectedMethod == 'fingerprint') {
|
||||
if (savedMethod == 'pin') {
|
||||
askForDisablePin(function(disablePin) {
|
||||
if (disablePin) saveConfig('fingerprint');
|
||||
else init();
|
||||
});
|
||||
} else saveConfig('fingerprint');
|
||||
} else if (selectedMethod == 'pin') {
|
||||
if (savedMethod == 'pin') return;
|
||||
$state.transitionTo('tabs.pin', {
|
||||
fromSettings: true,
|
||||
locking: savedMethod == 'pin' ? false : true
|
||||
});
|
||||
}
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
};
|
||||
|
||||
function askForDisablePin(cb) {
|
||||
var message = gettextCatalog.getString('{{appName}} startup is locked by PIN. Are you sure you want to disable it?', {
|
||||
appName: appConfigService.nameCase
|
||||
});
|
||||
var okText = gettextCatalog.getString('Continue');
|
||||
var cancelText = gettextCatalog.getString('Cancel');
|
||||
popupService.showConfirm(null, message, okText, cancelText, function(ok) {
|
||||
if (!ok) return cb(false);
|
||||
return cb(true);
|
||||
});
|
||||
};
|
||||
|
||||
function saveConfig(method) {
|
||||
var opts = {
|
||||
lock: {
|
||||
method: method || null,
|
||||
value: null,
|
||||
}
|
||||
};
|
||||
|
||||
configService.set(opts, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
});
|
||||
};
|
||||
});
|
||||
17
src/js/controllers/lockedView.js
Normal file
17
src/js/controllers/lockedView.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('lockedViewController', function($state, $scope, $ionicHistory, fingerprintService, appConfigService, gettextCatalog) {
|
||||
$scope.$on("$ionicView.beforeEnter", function(event) {
|
||||
$scope.title = appConfigService.nameCase + ' ' + gettextCatalog.getString('is locked');
|
||||
$scope.appName = appConfigService.name;
|
||||
});
|
||||
|
||||
$scope.requestFingerprint = function() {
|
||||
fingerprintService.check('unlockingApp', function(err) {
|
||||
if (err) return;
|
||||
$state.transitionTo('tabs.home').then(function() {
|
||||
$ionicHistory.clearHistory();
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('collectEmailController', function($scope, $state, $timeout, $stateParams, $ionicConfig, profileService, configService, walletService, platformInfo, pushNotificationsService) {
|
||||
angular.module('copayApp.controllers').controller('collectEmailController', function($scope, $state, $timeout, $stateParams, $ionicConfig, profileService, configService, walletService) {
|
||||
|
||||
$scope.$on("$ionicView.beforeLeave", function() {
|
||||
$ionicConfig.views.swipeBackEnabled(true);
|
||||
|
|
@ -10,11 +10,6 @@ angular.module('copayApp.controllers').controller('collectEmailController', func
|
|||
$ionicConfig.views.swipeBackEnabled(false);
|
||||
});
|
||||
|
||||
var isCordova = platformInfo.isCordova;
|
||||
var isWP = platformInfo.isWP;
|
||||
var usePushNotifications = isCordova && !isWP;
|
||||
var requiresOptIn = platformInfo.isIOS;
|
||||
|
||||
var wallet = profileService.getWallet($stateParams.walletId);
|
||||
var walletId = wallet.credentials.walletId;
|
||||
$scope.data = {};
|
||||
|
|
@ -37,20 +32,9 @@ angular.module('copayApp.controllers').controller('collectEmailController', func
|
|||
};
|
||||
|
||||
$scope.goNextView = function() {
|
||||
if (!usePushNotifications) {
|
||||
$state.go('onboarding.backupRequest', {
|
||||
walletId: walletId
|
||||
});
|
||||
} else if (requiresOptIn) {
|
||||
$state.go('onboarding.notifications', {
|
||||
walletId: walletId
|
||||
});
|
||||
} else {
|
||||
pushNotificationsService.init();
|
||||
$state.go('onboarding.backupRequest', {
|
||||
walletId: walletId
|
||||
});
|
||||
}
|
||||
$state.go('onboarding.backupRequest', {
|
||||
walletId: walletId
|
||||
});
|
||||
};
|
||||
|
||||
$scope.confirm = function(emailForm) {
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('notificationsController', function($scope, $state, $timeout, $stateParams, $ionicConfig, profileService, configService, $interval, pushNotificationsService) {
|
||||
|
||||
$scope.$on("$ionicView.enter", function() {
|
||||
$ionicConfig.views.swipeBackEnabled(false);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.beforeLeave", function() {
|
||||
$ionicConfig.views.swipeBackEnabled(true);
|
||||
});
|
||||
|
||||
$scope.walletId = $stateParams.walletId;
|
||||
|
||||
$scope.allowNotif = function() {
|
||||
$scope.notificationDialogOpen = true;
|
||||
$timeout(function() {
|
||||
pushNotificationsService.init();
|
||||
});
|
||||
$scope.notificationPromise = $interval(function() {
|
||||
PushNotification.hasPermission(function(data) {
|
||||
if (data.isEnabled) {
|
||||
$interval.cancel($scope.notificationPromise);
|
||||
$state.go('onboarding.backupRequest', {
|
||||
walletId: $scope.walletId
|
||||
});
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
$scope.continue = function() {
|
||||
$interval.cancel($scope.notificationPromise);
|
||||
$state.go('onboarding.backupRequest', {
|
||||
walletId: $scope.walletId
|
||||
});
|
||||
}
|
||||
|
||||
$scope.disableNotif = function() {
|
||||
var opts = {
|
||||
pushNotifications: {
|
||||
enabled: false
|
||||
}
|
||||
};
|
||||
configService.set(opts, function(err) {
|
||||
if (err) $log.warn(err);
|
||||
$state.go('onboarding.backupRequest', {
|
||||
walletId: $scope.walletId
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -1,10 +1,6 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.controllers').controller('tourController',
|
||||
function($scope, $state, $log, $timeout, $filter, ongoingProcess, platformInfo, profileService, rateService, popupService, gettextCatalog) {
|
||||
|
||||
var isCordova = platformInfo.isCordova;
|
||||
var isWP = platformInfo.isWP;
|
||||
var usePushNotifications = isCordova && !isWP;
|
||||
function($scope, $state, $log, $timeout, $filter, ongoingProcess, profileService, rateService, popupService, gettextCatalog) {
|
||||
|
||||
$scope.data = {
|
||||
index: 0
|
||||
|
|
@ -43,38 +39,34 @@ angular.module('copayApp.controllers').controller('tourController',
|
|||
var retryCount = 0;
|
||||
$scope.createDefaultWallet = function() {
|
||||
ongoingProcess.set('creatingWallet', true);
|
||||
profileService.createDefaultWallet(function(err, walletClient) {
|
||||
if (err) {
|
||||
$log.warn(err);
|
||||
$timeout(function() {
|
||||
profileService.createDefaultWallet(function(err, walletClient) {
|
||||
if (err) {
|
||||
$log.warn(err);
|
||||
|
||||
return $timeout(function() {
|
||||
$log.warn('Retrying to create default wallet.....:' + ++retryCount);
|
||||
if (retryCount > 3) {
|
||||
ongoingProcess.set('creatingWallet', false);
|
||||
popupService.showAlert(
|
||||
gettextCatalog.getString('Cannot Create Wallet'), err,
|
||||
function() {
|
||||
retryCount = 0;
|
||||
return $scope.createDefaultWallet();
|
||||
}, gettextCatalog.getString('Retry'));
|
||||
} else {
|
||||
return $scope.createDefaultWallet();
|
||||
}
|
||||
}, 2000);
|
||||
};
|
||||
ongoingProcess.set('creatingWallet', false);
|
||||
var wallet = walletClient;
|
||||
var walletId = wallet.credentials.walletId;
|
||||
if (!usePushNotifications) {
|
||||
return $timeout(function() {
|
||||
$log.warn('Retrying to create default wallet.....:' + ++retryCount);
|
||||
if (retryCount > 3) {
|
||||
ongoingProcess.set('creatingWallet', false);
|
||||
popupService.showAlert(
|
||||
gettextCatalog.getString('Cannot Create Wallet'), err,
|
||||
function() {
|
||||
retryCount = 0;
|
||||
return $scope.createDefaultWallet();
|
||||
}, gettextCatalog.getString('Retry'));
|
||||
} else {
|
||||
return $scope.createDefaultWallet();
|
||||
}
|
||||
}, 2000);
|
||||
};
|
||||
ongoingProcess.set('creatingWallet', false);
|
||||
var wallet = walletClient;
|
||||
var walletId = wallet.credentials.walletId;
|
||||
$state.go('onboarding.backupRequest', {
|
||||
walletId: walletId
|
||||
});
|
||||
} else {
|
||||
$state.go('onboarding.notifications', {
|
||||
walletId: walletId
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 300);
|
||||
};
|
||||
|
||||
$scope.goBack = function() {
|
||||
|
|
|
|||
186
src/js/controllers/pin.js
Normal file
186
src/js/controllers/pin.js
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('pinController', function($state, $interval, $stateParams, $ionicHistory, $timeout, $scope, $log, configService, appConfigService) {
|
||||
var ATTEMPT_LIMIT = 3;
|
||||
var ATTEMPT_LOCK_OUT_TIME = 5 * 60;
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event) {
|
||||
$scope.currentPin = $scope.confirmPin = '';
|
||||
$scope.fromSettings = $stateParams.fromSettings == 'true' ? true : false;
|
||||
$scope.locking = $stateParams.locking == 'true' ? true : false;
|
||||
$scope.match = $scope.error = $scope.disableButtons = false;
|
||||
$scope.currentAttempts = 0;
|
||||
$scope.appName = appConfigService.name;
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event) {
|
||||
configService.whenAvailable(function(config) {
|
||||
if (!config.lock) return;
|
||||
$scope.bannedUntil = config.lock.bannedUntil || null;
|
||||
if ($scope.bannedUntil) {
|
||||
var now = Math.floor(Date.now() / 1000);
|
||||
if (now < $scope.bannedUntil) {
|
||||
$scope.error = $scope.disableButtons = true;
|
||||
lockTimeControl($scope.bannedUntil);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function checkAttempts() {
|
||||
$scope.currentAttempts += 1;
|
||||
$log.debug('Attempts to unlock:', $scope.currentAttempts);
|
||||
if ($scope.currentAttempts === ATTEMPT_LIMIT) {
|
||||
$scope.currentAttempts = 0;
|
||||
var limitTime = Math.floor(Date.now() / 1000) + ATTEMPT_LOCK_OUT_TIME;
|
||||
var config = configService.getSync();
|
||||
var opts = {
|
||||
lock: {
|
||||
method: 'pin',
|
||||
value: config.lock.value,
|
||||
bannedUntil: limitTime,
|
||||
attempts: config.lock.attempts + 1,
|
||||
}
|
||||
};
|
||||
|
||||
configService.set(opts, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
lockTimeControl(limitTime);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function lockTimeControl(limitTime) {
|
||||
$scope.limitTimeExpired = false;
|
||||
setExpirationTime();
|
||||
|
||||
var countDown = $interval(function() {
|
||||
setExpirationTime();
|
||||
}, 1000);
|
||||
|
||||
function setExpirationTime() {
|
||||
var now = Math.floor(Date.now() / 1000);
|
||||
if (now > limitTime) {
|
||||
$scope.limitTimeExpired = true;
|
||||
if (countDown) reset();
|
||||
} else {
|
||||
$scope.disableButtons = true;
|
||||
var totalSecs = limitTime - now;
|
||||
var m = Math.floor(totalSecs / 60);
|
||||
var s = totalSecs % 60;
|
||||
$scope.expires = ('0' + m).slice(-2) + ":" + ('0' + s).slice(-2);
|
||||
}
|
||||
};
|
||||
|
||||
function reset() {
|
||||
$scope.expires = $scope.error = $scope.disableButtons = null;
|
||||
$scope.currentPin = $scope.confirmPin = '';
|
||||
$interval.cancel(countDown);
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
return;
|
||||
};
|
||||
};
|
||||
|
||||
$scope.getFilledClass = function(limit) {
|
||||
return $scope.currentPin.length >= limit ? 'filled-' + $scope.appName : null;
|
||||
};
|
||||
|
||||
$scope.delete = function() {
|
||||
if ($scope.disableButtons) return;
|
||||
if ($scope.currentPin.length > 0) {
|
||||
$scope.currentPin = $scope.currentPin.substring(0, $scope.currentPin.length - 1);
|
||||
$scope.error = false;
|
||||
$scope.updatePin();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.isComplete = function() {
|
||||
if ($scope.currentPin.length < 4) return false;
|
||||
else return true;
|
||||
};
|
||||
|
||||
$scope.updatePin = function(value) {
|
||||
if ($scope.disableButtons) return;
|
||||
$scope.error = false;
|
||||
if (value && !$scope.isComplete()) {
|
||||
$scope.currentPin = $scope.currentPin + value;
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
}
|
||||
$scope.save();
|
||||
};
|
||||
|
||||
$scope.save = function() {
|
||||
if (!$scope.isComplete()) return;
|
||||
var config = configService.getSync();
|
||||
$scope.match = config.lock && config.lock.method == 'pin' && config.lock.value == $scope.currentPin ? true : false;
|
||||
if (!$scope.locking) {
|
||||
if ($scope.match) {
|
||||
if ($scope.fromSettings) saveSettings();
|
||||
else {
|
||||
saveSettings('pin', $scope.currentPin);
|
||||
$scope.error = false;
|
||||
}
|
||||
} else {
|
||||
$timeout(function() {
|
||||
$scope.confirmPin = $scope.currentPin = '';
|
||||
$scope.error = true;
|
||||
}, 200);
|
||||
checkAttempts();
|
||||
}
|
||||
} else {
|
||||
processCodes();
|
||||
}
|
||||
};
|
||||
|
||||
function processCodes() {
|
||||
if (!$scope.confirmPin) {
|
||||
$timeout(function() {
|
||||
$scope.confirmPin = $scope.currentPin;
|
||||
$scope.currentPin = '';
|
||||
}, 200);
|
||||
} else {
|
||||
if ($scope.confirmPin == $scope.currentPin)
|
||||
saveSettings('pin', $scope.confirmPin);
|
||||
else {
|
||||
$scope.confirmPin = $scope.currentPin = '';
|
||||
$scope.error = true;
|
||||
}
|
||||
}
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
};
|
||||
|
||||
function saveSettings(method, value) {
|
||||
var config = configService.getSync();
|
||||
var attempts = config.lock && config.lock.attempts ? config.lock.attempts : 0;
|
||||
var opts = {
|
||||
lock: {
|
||||
method: method || null,
|
||||
value: value || null,
|
||||
bannedUntil: null,
|
||||
attempts: attempts + 1,
|
||||
}
|
||||
};
|
||||
|
||||
configService.set(opts, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
$scope.close();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.close = function(delay) {
|
||||
$timeout(function() {
|
||||
var shouldReturn = $ionicHistory.viewHistory().backView && $ionicHistory.viewHistory().backView.stateName != 'starting';
|
||||
|
||||
if (shouldReturn)
|
||||
$ionicHistory.goBack()
|
||||
else
|
||||
$state.go('tabs.home');
|
||||
}, delay || 1);
|
||||
};
|
||||
});
|
||||
|
|
@ -89,9 +89,6 @@ angular.module('copayApp.controllers').controller('preferencesController',
|
|||
value: $scope.wallet.balanceHidden
|
||||
};
|
||||
|
||||
if (wallet.isPrivKeyExternal)
|
||||
$scope.externalSource = wallet.getPrivKeyExternalSourceName() == 'ledger' ? 'Ledger' : 'Trezor';
|
||||
|
||||
$scope.touchIdAvailable = fingerprintService.isAvailable();
|
||||
$scope.touchIdEnabled = {
|
||||
value: config.touchIdFor ? config.touchIdFor[walletId] : null
|
||||
|
|
|
|||
28
src/js/controllers/preferencesExternal.js
Normal file
28
src/js/controllers/preferencesExternal.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('preferencesExternalController', function($scope, $stateParams, lodash, gettextCatalog, popupService, profileService, walletService) {
|
||||
var wallet = profileService.getWallet($stateParams.walletId);
|
||||
|
||||
$scope.externalSource = lodash.find(walletService.externalSource, function(source) {
|
||||
return source.id == wallet.getPrivKeyExternalSourceName();
|
||||
});
|
||||
|
||||
if ($scope.externalSource.isEmbeddedHardware) {
|
||||
$scope.hardwareConnected = $scope.externalSource.version.length > 0;
|
||||
|
||||
$scope.showMneumonicFromHardwarePopup = function() {
|
||||
var title = gettextCatalog.getString('Warning!');
|
||||
var message = gettextCatalog.getString('Are you being watched? Anyone with your recovery phrase can access or spend your bitcoin.');
|
||||
popupService.showConfirm(title, message, null, null, function(res) {
|
||||
if (res) {
|
||||
walletService.showMneumonicFromHardware(wallet, function(err) {
|
||||
if (err) {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), err.message || err);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('preferencesInformation',
|
||||
function($scope, $log, $ionicHistory, platformInfo, lodash, profileService, configService, $stateParams, $state) {
|
||||
function($scope, $log, $ionicHistory, platformInfo, lodash, profileService, configService, $stateParams, $state, walletService) {
|
||||
var wallet = profileService.getWallet($stateParams.walletId);
|
||||
$scope.wallet = wallet;
|
||||
|
||||
|
|
@ -44,5 +44,13 @@ angular.module('copayApp.controllers').controller('preferencesInformation',
|
|||
$scope.M = c.m;
|
||||
$scope.N = c.n;
|
||||
$scope.pubKeys = lodash.pluck(c.publicKeyRing, 'xPubKey');
|
||||
$scope.externalSource = null;
|
||||
|
||||
if (wallet.isPrivKeyExternal()) {
|
||||
$scope.externalSource = lodash.find(walletService.externalSource, function(source) {
|
||||
return source.id == wallet.getPrivKeyExternalSourceName();
|
||||
}).name;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('sellCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService, appConfigService, configService) {
|
||||
angular.module('copayApp.controllers').controller('sellCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService, appConfigService, configService, txFormatService) {
|
||||
|
||||
var amount;
|
||||
var currency;
|
||||
|
|
@ -117,8 +117,8 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
|
|||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.isFiat = data.stateParams.currency ? true : false;
|
||||
var parsedAmount = coinbaseService.parseAmount(
|
||||
$scope.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
data.stateParams.amount,
|
||||
data.stateParams.currency);
|
||||
|
||||
|
|
@ -133,8 +133,15 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
|
|||
$scope.wallets = profileService.getWallets({
|
||||
m: 1, // Only 1-signature wallet
|
||||
onlyComplete: true,
|
||||
network: $scope.network
|
||||
network: $scope.network,
|
||||
hasFunds: true,
|
||||
minAmount: parsedAmount.amountSat
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('Insufficient funds');
|
||||
return;
|
||||
}
|
||||
$scope.wallet = $scope.wallets[0]; // Default first wallet
|
||||
|
||||
ongoingProcess.set('connectingCoinbase', true);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('sellGlideraController', function($scope, $log, $state, $timeout, $ionicHistory, lodash, glideraService, popupService, profileService, ongoingProcess, walletService, configService, platformInfo) {
|
||||
angular.module('copayApp.controllers').controller('sellGlideraController', function($scope, $log, $state, $timeout, $ionicHistory, lodash, glideraService, popupService, profileService, ongoingProcess, walletService, configService, platformInfo, txFormatService) {
|
||||
|
||||
var amount;
|
||||
var currency;
|
||||
|
|
@ -36,8 +36,8 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
|
|||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.isFiat = data.stateParams.currency ? true : false;
|
||||
var parsedAmount = glideraService.parseAmount(
|
||||
$scope.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
data.stateParams.amount,
|
||||
data.stateParams.currency);
|
||||
|
||||
|
|
@ -49,8 +49,15 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
|
|||
$scope.wallets = profileService.getWallets({
|
||||
m: 1, // Only 1-signature wallet
|
||||
onlyComplete: true,
|
||||
network: $scope.network
|
||||
network: $scope.network,
|
||||
hasFunds: true,
|
||||
minAmount: parsedAmount.amountSat
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('Insufficient funds');
|
||||
return;
|
||||
}
|
||||
$scope.wallet = $scope.wallets[0]; // Default first wallet
|
||||
|
||||
ongoingProcess.set('connectingGlidera', true);
|
||||
|
|
|
|||
|
|
@ -145,6 +145,22 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
});
|
||||
};
|
||||
|
||||
$scope.shouldShowReceiveAddressFromHardware = function() {
|
||||
var wallet = $scope.wallet;
|
||||
if (wallet.isPrivKeyExternal() && wallet.credentials.hwInfo) {
|
||||
return (wallet.credentials.hwInfo.name == walletService.externalSource.intelTEE.id);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.showReceiveAddressFromHardware = function() {
|
||||
var wallet = $scope.wallet;
|
||||
if (wallet.isPrivKeyExternal() && wallet.credentials.hwInfo) {
|
||||
walletService.showReceiveAddressFromHardware(wallet, $scope.addr, function(){});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.wallets = profileService.getWallets();
|
||||
|
||||
|
|
@ -165,6 +181,10 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
return w.id == $scope.wallet.id;
|
||||
});
|
||||
if (w) $scope.updateCurrentWallet();
|
||||
else if (screen.width > 700 && screen.height > 700 && $scope.wallets[0]) {
|
||||
$scope.setWallet(0)
|
||||
$scope.walletPosition(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,12 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct
|
|||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.isCordova = platformInfo.isCordova;
|
||||
$scope.isDevel = platformInfo.isDevel;
|
||||
$scope.appName = appConfigService.nameCase;
|
||||
configService.whenAvailable(function(config) {
|
||||
$scope.locked = config.lock && config.lock.method;
|
||||
$scope.method = $scope.locked ? config.lock.method.charAt(0).toUpperCase() + config.lock.method.slice(1) : gettextCatalog.getString('Disabled');
|
||||
});
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event, data) {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('topUpController', function($scope, $log, $state, $timeout, $ionicHistory, lodash, popupService, profileService, ongoingProcess, walletService, configService, platformInfo, bitpayService, bitpayCardService, payproService, bwcError) {
|
||||
angular.module('copayApp.controllers').controller('topUpController', function($scope, $log, $state, $timeout, $ionicHistory, lodash, popupService, profileService, ongoingProcess, walletService, configService, platformInfo, bitpayService, bitpayCardService, payproService, bwcError, txFormatService, sendMaxService) {
|
||||
|
||||
var amount;
|
||||
var currency;
|
||||
var cardId;
|
||||
var sendMax;
|
||||
|
||||
$scope.isCordova = platformInfo.isCordova;
|
||||
|
||||
|
|
@ -49,16 +50,32 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
|
|||
}
|
||||
};
|
||||
|
||||
var checkDailyLimit = function() {
|
||||
if (currency == 'USD' && amount > 10000) {
|
||||
showErrorAndBack('Top up is limited to USD 10,000 per day');
|
||||
return;
|
||||
}
|
||||
|
||||
bitpayCardService.getRates('USD', function(err, data) {
|
||||
if (err) $log.error(err);
|
||||
$scope.rate = data.rate;
|
||||
if (currency == 'BTC' && (amount * data.rate) > 10000) {
|
||||
showErrorAndBack('Top up is limited to USD 10,000 per day');
|
||||
return;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.isFiat = data.stateParams.currency ? true : false;
|
||||
cardId = data.stateParams.id;
|
||||
sendMax = data.stateParams.useSendMax;
|
||||
|
||||
if (!cardId) {
|
||||
showErrorAndBack('No card selected');
|
||||
return;
|
||||
}
|
||||
|
||||
var parsedAmount = bitpayCardService.parseAmount(
|
||||
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
data.stateParams.amount,
|
||||
data.stateParams.currency);
|
||||
|
||||
|
|
@ -80,11 +97,6 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
|
|||
}
|
||||
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
|
||||
|
||||
bitpayCardService.getRates(currency, function(err, data) {
|
||||
if (err) $log.error(err);
|
||||
$scope.rate = data.rate;
|
||||
});
|
||||
|
||||
bitpayCardService.get({ cardId: cardId, noRefresh: true }, function(err, card) {
|
||||
if (err) {
|
||||
showErrorAndBack(err);
|
||||
|
|
@ -189,6 +201,32 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
|
|||
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
if (sendMax) {
|
||||
ongoingProcess.set('retrievingInputs', true);
|
||||
sendMaxService.getInfo($scope.wallet, function(err, values) {
|
||||
ongoingProcess.set('retrievingInputs', false);
|
||||
if (err) {
|
||||
showErrorAndBack(err);
|
||||
return;
|
||||
}
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var unitName = config.unitName;
|
||||
var amountUnit = txFormatService.satToUnit(values.amount);
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
amountUnit,
|
||||
unitName);
|
||||
|
||||
amount = parsedAmount.amount;
|
||||
currency = parsedAmount.currency;
|
||||
checkDailyLimit();
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
}, 100);
|
||||
});
|
||||
} else {
|
||||
checkDailyLimit();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.goBackHome = function() {
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ angular.module('copayApp.directives')
|
|||
scope.$emit('Wallet/Changed', scope.wallets ? scope.wallets[0] : null);
|
||||
});
|
||||
|
||||
scope.$on("$ionicSlides.slideChangeEnd", function(event, data) {
|
||||
scope.$on("$ionicSlides.slideChangeStart", function(event, data) {
|
||||
scope.$emit('Wallet/Changed', scope.wallets ? scope.wallets[data.slider.activeIndex] : null);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
127
src/js/routes.js
127
src/js/routes.js
|
|
@ -119,6 +119,30 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
})
|
||||
|
||||
/*
|
||||
*
|
||||
* Pin
|
||||
*
|
||||
*/
|
||||
|
||||
.state('pin', {
|
||||
url: '/pin/',
|
||||
controller: 'pinController',
|
||||
templateUrl: 'views/pin.html',
|
||||
})
|
||||
|
||||
/*
|
||||
*
|
||||
* Locked
|
||||
*
|
||||
*/
|
||||
|
||||
.state('lockedView', {
|
||||
url: '/lockedView/',
|
||||
controller: 'lockedViewController',
|
||||
templateUrl: 'views/lockedView.html',
|
||||
})
|
||||
|
||||
/*
|
||||
*
|
||||
* URI
|
||||
|
|
@ -439,6 +463,25 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.lockSetup', {
|
||||
url: '/lockSetup',
|
||||
views: {
|
||||
'tab-settings@tabs': {
|
||||
controller: 'lockSetupController',
|
||||
templateUrl: 'views/lockSetup.html',
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.pin', {
|
||||
url: '/pin/:fromSettings/:locking',
|
||||
views: {
|
||||
'tab-settings@tabs': {
|
||||
controller: 'pinController',
|
||||
templateUrl: 'views/pin.html',
|
||||
cache: false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
*
|
||||
|
|
@ -536,6 +579,15 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.preferences.preferencesExternal', {
|
||||
url: '/preferencesExternal',
|
||||
views: {
|
||||
'tab-settings@tabs': {
|
||||
controller: 'preferencesExternalController',
|
||||
templateUrl: 'views/preferencesExternal.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.preferences.delete', {
|
||||
url: '/delete',
|
||||
views: {
|
||||
|
|
@ -725,15 +777,6 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
}
|
||||
})
|
||||
.state('onboarding.notifications', {
|
||||
url: '/notifications/:walletId',
|
||||
views: {
|
||||
'onboarding': {
|
||||
templateUrl: 'views/onboarding/notifications.html',
|
||||
controller: 'notificationsController'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('onboarding.backupRequest', {
|
||||
url: '/backupRequest/:walletId',
|
||||
views: {
|
||||
|
|
@ -1061,7 +1104,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
params: {
|
||||
id: null,
|
||||
currency: 'USD',
|
||||
forceCurrency: true
|
||||
useSendMax: null
|
||||
}
|
||||
})
|
||||
.state('tabs.bitpayCard.amount', {
|
||||
|
|
@ -1092,7 +1135,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
});
|
||||
})
|
||||
.run(function($rootScope, $state, $location, $log, $timeout, $ionicHistory, $ionicPlatform, $window, appConfigService, lodash, platformInfo, profileService, uxLanguage, gettextCatalog, openURLService, storageService, scannerService, /* plugins START HERE => */ coinbaseService, glideraService, amazonService, bitpayCardService) {
|
||||
.run(function($rootScope, $state, $location, $log, $timeout, startupService, fingerprintService, $ionicHistory, $ionicPlatform, $window, appConfigService, lodash, platformInfo, profileService, uxLanguage, gettextCatalog, openURLService, storageService, scannerService, configService, /* plugins START HERE => */ coinbaseService, glideraService, amazonService, bitpayCardService) {
|
||||
|
||||
uxLanguage.init();
|
||||
|
||||
|
|
@ -1124,12 +1167,11 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
var matchWelcome = $ionicHistory.currentStateName() == 'onboarding.welcome' ? true : false;
|
||||
var matchCollectEmail = $ionicHistory.currentStateName() == 'onboarding.collectEmail' ? true : false;
|
||||
var matchBackupRequest = $ionicHistory.currentStateName() == 'onboarding.backupRequest' ? true : false;
|
||||
var matchNotifications = $ionicHistory.currentStateName() == 'onboarding.notifications' ? true : false;
|
||||
var backedUp = $ionicHistory.backView().stateName == 'onboarding.backup' ? true : false;
|
||||
var noBackView = $ionicHistory.backView().stateName == 'starting' ? true : false;
|
||||
var matchDisclaimer = $ionicHistory.currentStateName() == 'onboarding.disclaimer' && (backedUp || noBackView) ? true : false;
|
||||
|
||||
var fromOnboarding = matchCollectEmail | matchBackupRequest | matchNotifications | matchWelcome | matchDisclaimer;
|
||||
var fromOnboarding = matchCollectEmail | matchBackupRequest | matchWelcome | matchDisclaimer;
|
||||
|
||||
//views with disable backbutton
|
||||
var matchComplete = $ionicHistory.currentStateName() == 'tabs.rate.complete' ? true : false;
|
||||
|
|
@ -1153,8 +1195,54 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
// Nothing to do
|
||||
});
|
||||
|
||||
|
||||
function checkAndApplyLock(onResume) {
|
||||
var defaultView = 'tabs.home';
|
||||
|
||||
if (!platformInfo.isCordova && !platformInfo.isDevel) {
|
||||
goTo(defaultView);
|
||||
}
|
||||
|
||||
if (onResume) {
|
||||
var now = Math.floor(Date.now() / 1000);
|
||||
if (now < openURLService.unlockUntil) {
|
||||
openURLService.unlockUntil = null;
|
||||
$log.debug('Skip startup locking');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function goTo(nextView) {
|
||||
nextView = nextView || defaultView;
|
||||
$state.transitionTo(nextView).then(function() {
|
||||
if (nextView == 'lockedView')
|
||||
$ionicHistory.clearHistory();
|
||||
});
|
||||
};
|
||||
|
||||
startupService.ready();
|
||||
|
||||
configService.whenAvailable(function(config) {
|
||||
var lockMethod = config.lock && config.lock.method;
|
||||
$log.debug('App Lock:' + (lockMethod || 'no'));
|
||||
|
||||
if (lockMethod == 'fingerprint' && fingerprintService.isAvailable()) {
|
||||
fingerprintService.check('unlockingApp', function(err) {
|
||||
if (err)
|
||||
goTo('lockedView');
|
||||
if ($ionicHistory.currentStateName() == 'lockedView' || !onResume)
|
||||
goTo('tabs.home');
|
||||
});
|
||||
} else if (lockMethod == 'pin') {
|
||||
goTo('pin');
|
||||
} else {
|
||||
goTo(defaultView);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$ionicPlatform.on('resume', function() {
|
||||
// Nothing to do
|
||||
checkAndApplyLock(true);
|
||||
});
|
||||
|
||||
$ionicPlatform.on('menubutton', function() {
|
||||
|
|
@ -1197,17 +1285,14 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
disableAnimate: true,
|
||||
historyRoot: true
|
||||
});
|
||||
$state.transitionTo('tabs.home').then(function() {
|
||||
// Clear history
|
||||
$ionicHistory.clearHistory();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
checkAndApplyLock();
|
||||
});
|
||||
};
|
||||
// After everything have been loaded, initialize handler URL
|
||||
$timeout(function() {
|
||||
openURLService.init();
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -72,8 +72,10 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo
|
|||
if (opts && opts.remove) {
|
||||
delete(inv[gc.invoiceId]);
|
||||
}
|
||||
|
||||
inv = JSON.stringify(inv);
|
||||
|
||||
|
||||
storageService.setAmazonGiftCards(network, inv, function(err) {
|
||||
|
||||
homeIntegrationsService.register(homeItem);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('bitpayCardService', function($log, $rootScope, $filter, lodash, storageService, bitauthService, platformInfo, moment, appIdentityService, bitpayService, nextStepsService, configService, txFormatService, appConfigService, rateService) {
|
||||
angular.module('copayApp.services').factory('bitpayCardService', function($log, $rootScope, $filter, lodash, storageService, bitauthService, platformInfo, moment, appIdentityService, bitpayService, nextStepsService, configService, txFormatService, appConfigService) {
|
||||
var root = {};
|
||||
|
||||
var _setError = function(msg, e) {
|
||||
|
|
@ -39,33 +39,6 @@ angular.module('copayApp.services').factory('bitpayCardService', function($log,
|
|||
return history;
|
||||
};
|
||||
|
||||
root.parseAmount = function(amount, currency) {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var satToBtc = 1 / 100000000;
|
||||
var unitToSatoshi = config.unitToSatoshi;
|
||||
var amountUnitStr;
|
||||
var amountSat;
|
||||
|
||||
// IF 'USD'
|
||||
if (currency) {
|
||||
amountUnitStr = $filter('formatFiatAmount')(amount) + ' ' + currency;
|
||||
amountSat = rateService.fromFiat(amount, currency).toFixed(0);
|
||||
} else {
|
||||
amountSat = parseInt((amount * unitToSatoshi).toFixed(0));
|
||||
amountUnitStr = txFormatService.formatAmountStr(amountSat);
|
||||
// convert unit to BTC
|
||||
amount = (amountSat * satToBtc).toFixed(8);
|
||||
currency = 'BTC';
|
||||
}
|
||||
|
||||
return {
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
amountSat: amountSat,
|
||||
amountUnitStr: amountUnitStr
|
||||
};
|
||||
};
|
||||
|
||||
root.sync = function(apiContext, cb) {
|
||||
var json = {
|
||||
method: 'getDebitCards'
|
||||
|
|
|
|||
|
|
@ -107,30 +107,6 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
};
|
||||
};
|
||||
|
||||
root.parseAmount = function(amount, currency) {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var satToBtc = 1 / 100000000;
|
||||
var unitToSatoshi = config.unitToSatoshi;
|
||||
var amountUnitStr;
|
||||
|
||||
// IF 'USD'
|
||||
if (currency) {
|
||||
amountUnitStr = $filter('formatFiatAmount')(amount) + ' ' + currency;
|
||||
} else {
|
||||
var amountSat = parseInt((amount * unitToSatoshi).toFixed(0));
|
||||
amountUnitStr = txFormatService.formatAmountStr(amountSat);
|
||||
// convert unit to BTC
|
||||
amount = (amountSat * satToBtc).toFixed(8);
|
||||
currency = 'BTC';
|
||||
}
|
||||
|
||||
return {
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
amountUnitStr: amountUnitStr
|
||||
};
|
||||
};
|
||||
|
||||
root.getSignupUrl = function() {
|
||||
return credentials.HOST + '/signup';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,13 @@ angular.module('copayApp.services').factory('configService', function(storageSer
|
|||
}
|
||||
},
|
||||
|
||||
lock: {
|
||||
method: null,
|
||||
value: null,
|
||||
bannedUntil: null,
|
||||
attempts: null,
|
||||
},
|
||||
|
||||
// External services
|
||||
recentTransactions: {
|
||||
enabled: true,
|
||||
|
|
|
|||
|
|
@ -51,10 +51,9 @@ angular.module('copayApp.services').factory('feeService', function($log, $stateP
|
|||
if (errLivenet || errTestnet) {
|
||||
return cb(gettextCatalog.getString('Could not get dynamic fee'));
|
||||
} else {
|
||||
for (var i = 0; i < 4; i++) {
|
||||
levelsLivenet[i]['feePerKBUnit'] = txFormatService.formatAmount(levelsLivenet[i].feePerKB) + ' ' + unitName;
|
||||
levelsTestnet[i]['feePerKBUnit'] = txFormatService.formatAmount(levelsTestnet[i].feePerKB) + ' ' + unitName;
|
||||
}
|
||||
lodash.each(lodash.union(levelsLivenet, levelsTestnet), function(level) {
|
||||
level.feePerKBUnit = txFormatService.formatAmount(level.feePerKB) + ' ' + unitName;
|
||||
});
|
||||
}
|
||||
|
||||
return cb(null, {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ angular.module('copayApp.services').factory('fingerprintService', function($log,
|
|||
function(msg) {
|
||||
FingerprintAuth.isAvailable(function(result) {
|
||||
|
||||
if (result.isAvailable)
|
||||
if (result.isAvailable)
|
||||
_isAvailable = 'ANDROID';
|
||||
|
||||
}, function() {
|
||||
|
|
@ -40,7 +40,7 @@ angular.module('copayApp.services').factory('fingerprintService', function($log,
|
|||
},
|
||||
function(msg) {
|
||||
$log.debug('Finger Failed:' + JSON.stringify(msg));
|
||||
return cb(gettextCatalog.getString('Finger Scan Failed') + ': ' + msg.localizedDescription);
|
||||
return cb(gettextCatalog.getString('Finger Scan Failed'));
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
|
|
@ -60,7 +60,7 @@ angular.module('copayApp.services').factory('fingerprintService', function($log,
|
|||
},
|
||||
function(msg) {
|
||||
$log.debug('Touch ID Failed:' + JSON.stringify(msg));
|
||||
return cb(gettextCatalog.getString('Touch ID Failed') + ': ' + msg.localizedDescription);
|
||||
return cb(gettextCatalog.getString('Touch ID Failed'));
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
|
|
@ -71,6 +71,7 @@ angular.module('copayApp.services').factory('fingerprintService', function($log,
|
|||
|
||||
var isNeeded = function(client) {
|
||||
if (!_isAvailable) return false;
|
||||
if (client === 'unlockingApp') return true;
|
||||
|
||||
var config = configService.getSync();
|
||||
config.touchIdFor = config.touchIdFor || {};
|
||||
|
|
@ -84,7 +85,7 @@ angular.module('copayApp.services').factory('fingerprintService', function($log,
|
|||
|
||||
root.check = function(client, cb) {
|
||||
if (isNeeded(client)) {
|
||||
$log.debug('FingerPrint Service:', _isAvailable);
|
||||
$log.debug('FingerPrint Service:', _isAvailable);
|
||||
if (_isAvailable == 'IOS')
|
||||
return requestTouchId(cb);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -53,30 +53,6 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l
|
|||
return 'USD';
|
||||
};
|
||||
|
||||
root.parseAmount = function(amount, currency) {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var satToBtc = 1 / 100000000;
|
||||
var unitToSatoshi = config.unitToSatoshi;
|
||||
var amountUnitStr;
|
||||
|
||||
// IF 'USD'
|
||||
if (currency) {
|
||||
amountUnitStr = $filter('formatFiatAmount')(amount) + ' ' + currency;
|
||||
} else {
|
||||
var amountSat = parseInt((amount * unitToSatoshi).toFixed(0));
|
||||
amountUnitStr = txFormatService.formatAmountStr(amountSat);
|
||||
// convert unit to BTC
|
||||
amount = (amountSat * satToBtc).toFixed(8);
|
||||
currency = 'BTC';
|
||||
}
|
||||
|
||||
return {
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
amountUnitStr: amountUnitStr
|
||||
};
|
||||
};
|
||||
|
||||
root.getSignupUrl = function() {
|
||||
return credentials.HOST + '/register';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@ angular.module('copayApp.services')
|
|||
|
||||
// Ledger magic number to get xPub without user confirmation
|
||||
root.ENTROPY_INDEX_PATH = "0xb11e/";
|
||||
root.M = 'm/';
|
||||
root.UNISIG_ROOTPATH = 44;
|
||||
root.MULTISIG_ROOTPATH = 48;
|
||||
root.LIVENET_PATH = 0;
|
||||
root.TESTNET_PATH = 1;
|
||||
|
||||
root._err = function(data) {
|
||||
var msg = data.error || data.message || 'unknown';
|
||||
|
|
@ -17,26 +19,49 @@ angular.module('copayApp.services')
|
|||
|
||||
|
||||
root.getRootPath = function(device, isMultisig, account) {
|
||||
if (!isMultisig) return root.UNISIG_ROOTPATH;
|
||||
|
||||
// Compat
|
||||
if (device == 'ledger' && account == 0) return root.UNISIG_ROOTPATH;
|
||||
|
||||
return root.MULTISIG_ROOTPATH;
|
||||
var path;
|
||||
if (isMultisig) {
|
||||
path = root.MULTISIG_ROOTPATH;
|
||||
} else {
|
||||
if (device == 'ledger' && account > 0) {
|
||||
path = root.MULTISIG_ROOTPATH;
|
||||
} else {
|
||||
path = root.UNISIG_ROOTPATH;
|
||||
}
|
||||
}
|
||||
if (device == 'intelTEE') {
|
||||
path = root.M + path;
|
||||
}
|
||||
return path;
|
||||
};
|
||||
|
||||
root.getAddressPath = function(device, isMultisig, account) {
|
||||
return root.getRootPath(device, isMultisig, account) + "'/" + root.LIVENET_PATH + "'/" + account + "'";
|
||||
}
|
||||
root.getAddressPath = function(device, isMultisig, account, network) {
|
||||
network = network || 'livenet';
|
||||
var networkPath = root.LIVENET_PATH;
|
||||
if (network == 'testnet') {
|
||||
networkPath = root.TESTNET_PATH;
|
||||
}
|
||||
return root.getRootPath(device, isMultisig, account) + "'/" + networkPath + "'/" + account + "'";
|
||||
};
|
||||
|
||||
root.getEntropyPath = function(device, isMultisig, account) {
|
||||
var path;
|
||||
var path = root.ENTROPY_INDEX_PATH;
|
||||
if (isMultisig) {
|
||||
path = path + "48'/"
|
||||
} else {
|
||||
path = path + "44'/"
|
||||
}
|
||||
|
||||
// Old ledger wallet compat
|
||||
if (device == 'ledger' && account == 0)
|
||||
return root.ENTROPY_INDEX_PATH + "0'";
|
||||
if (device == 'ledger' && account == 0) {
|
||||
return path + "0'/";
|
||||
}
|
||||
|
||||
return root.ENTROPY_INDEX_PATH + root.getRootPath(device, isMultisig, account) + "'/" + account + "'";
|
||||
if (device == 'intelTEE') {
|
||||
path = root.M + path;
|
||||
}
|
||||
|
||||
return path + account + "'";
|
||||
};
|
||||
|
||||
root.pubKeyToEntropySource = function(xPubKey) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('incomingData', function($log, $state, $timeout, $ionicHistory, bitcore, $rootScope, payproService, scannerService, appConfigService) {
|
||||
angular.module('copayApp.services').factory('incomingData', function($log, $state, $timeout, $ionicHistory, bitcore, $rootScope, payproService, scannerService, appConfigService, popupService, gettextCatalog) {
|
||||
|
||||
var root = {};
|
||||
|
||||
|
|
@ -93,10 +93,10 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
|
|||
|
||||
if (parsed.r) {
|
||||
payproService.getPayProDetails(parsed.r, function(err, details) {
|
||||
if (err && addr && amount) {
|
||||
goSend(addr, amount, message);
|
||||
}
|
||||
handlePayPro(details);
|
||||
if (err) {
|
||||
if (addr && amount) goSend(addr, amount, message);
|
||||
else popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
} else handlePayPro(details);
|
||||
});
|
||||
} else {
|
||||
goSend(addr, amount, message);
|
||||
|
|
|
|||
195
src/js/services/intelTEE.js
Normal file
195
src/js/services/intelTEE.js
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services')
|
||||
.factory('intelTEE', function($log, $timeout, gettext, lodash, bitcore, hwWallet, bwcService, platformInfo) {
|
||||
|
||||
var root = {};
|
||||
|
||||
root.description = {
|
||||
supported: platformInfo.supportsIntelTEE,
|
||||
version: platformInfo.versionIntelTEE,
|
||||
id: 'intelTEE',
|
||||
name: 'Intel TEE',
|
||||
longName: 'Intel TEE Hardware Wallet',
|
||||
derivationStrategy: 'BIP44',
|
||||
isEmbeddedHardware: true,
|
||||
supportsTestnet: true
|
||||
};
|
||||
|
||||
if (!root.description.supported) {
|
||||
return root;
|
||||
}
|
||||
|
||||
var IntelWallet = require('intelWalletCon');
|
||||
var TEE_APP_ID = '63279de1b6cb4dcf8c206716bd318092f8c206716bd31809263279de1b6cb4dc';
|
||||
|
||||
root.walletEnclave = new IntelWallet.Wallet();
|
||||
var walletEnclaveStatus = root.walletEnclave.initializeEnclave();
|
||||
if (walletEnclaveStatus != 0) {
|
||||
$log.error('Failed to create Intel Wallet enclave');
|
||||
}
|
||||
|
||||
root.getInfoForNewWallet = function(isMultisig, account, networkName, callback) {
|
||||
var opts = {};
|
||||
initSource(opts, function(err, opts) {
|
||||
if (err) return callback(err);
|
||||
|
||||
root.getEntropySource(opts.hwInfo.id, isMultisig, account, function(err, entropySource) {
|
||||
if (err) return callback(err);
|
||||
|
||||
opts.entropySource = entropySource;
|
||||
root.getXPubKey(opts.hwInfo.id, hwWallet.getAddressPath(root.description.id, isMultisig, account, networkName), function(data) {
|
||||
if (!data.success) {
|
||||
$log.warn(data.message);
|
||||
return callback(data);
|
||||
}
|
||||
opts.extendedPublicKey = data.xpubkey;
|
||||
opts.externalSource = root.description.id;
|
||||
opts.derivationStrategy = root.description.derivationStrategy;
|
||||
|
||||
return callback(null, opts);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
root.getXPubKey = function(teeWalletId, path, callback) {
|
||||
$log.debug('TEE deriving xPub path:', path);
|
||||
|
||||
// Expected to be a extended public key.
|
||||
var xpubkey = root.walletEnclave.getPublicKey(teeWalletId, path);
|
||||
|
||||
// Error messages returned in value.
|
||||
var result = {
|
||||
success: false,
|
||||
message: xpubkey.ExtendedPublicKey
|
||||
};
|
||||
|
||||
// Success indicated by status being equal to the tee wallet id.
|
||||
if (xpubkey.Status == teeWalletId) {
|
||||
result.success = true;
|
||||
result.message = 'OK';
|
||||
result.xpubkey = xpubkey.ExtendedPublicKey;
|
||||
} else {
|
||||
$log.error('Failed to get xpubkey from TEE wallet: ' + result.message);
|
||||
}
|
||||
|
||||
callback(result);
|
||||
};
|
||||
|
||||
root.getEntropySource = function(teeWalletId, isMultisig, account, callback) {
|
||||
root.getXPubKey(teeWalletId, hwWallet.getEntropyPath(root.description.id, isMultisig, account), function(data) {
|
||||
if (!data.success)
|
||||
return callback(hwWallet._err(data));
|
||||
|
||||
return callback(null, hwWallet.pubKeyToEntropySource(data.xpubkey));
|
||||
});
|
||||
};
|
||||
|
||||
root.showMneumonic = function(teeWalletId, cb) {
|
||||
var result = root.walletEnclave.displayWordList(teeWalletId, 'en');
|
||||
if (result != teeWalletId) {
|
||||
cb(result);
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
};
|
||||
|
||||
root.showReceiveAddress = function(teeWalletId, address, cb) {
|
||||
var isMultisig = false; // TODO
|
||||
var account = 0; // TODO
|
||||
var basePath = hwWallet.getAddressPath(root.description.id, isMultisig, account, address.network);
|
||||
var keyPath = address.path.replace('m', basePath);
|
||||
|
||||
var result = root.walletEnclave.displayReceiveAddress(teeWalletId, keyPath);
|
||||
if (result != teeWalletId) {
|
||||
cb(result);
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
};
|
||||
|
||||
root.signTx = function(teeWalletId, txp, callback) {
|
||||
var account = 0; // TODO
|
||||
var isMultisig = txp.requiredSignatures > 1;
|
||||
var basePath = hwWallet.getAddressPath(root.description.id, isMultisig, account, txp.network);
|
||||
|
||||
var rawTx = bwcService.Client.getRawTx(txp);
|
||||
var keypaths = lodash.map(lodash.pluck(txp.inputs, 'path'), function(path) {
|
||||
return path.replace('m', basePath);
|
||||
});
|
||||
var publicKeys = lodash.pluck(txp.inputs, 'publicKeys');
|
||||
var changePublicKeys = txp.changeAddress.publicKeys;
|
||||
publicKeys.push(changePublicKeys);
|
||||
|
||||
var changeaddrpath;
|
||||
if (txp.changeAddress) {
|
||||
changeaddrpath = txp.changeAddress.path.replace('m', basePath);
|
||||
}
|
||||
|
||||
var result;
|
||||
if (txp.requiredSignatures == 1) {
|
||||
result = root.walletEnclave.signTransaction(teeWalletId, rawTx, changeaddrpath, keypaths);
|
||||
} else {
|
||||
result = root.walletEnclave.signTransaction(teeWalletId, rawTx, changeaddrpath, keypaths, publicKeys, txp.requiredSignatures, changePublicKeys, txp.requiredSignatures);
|
||||
}
|
||||
|
||||
if (result.Status != teeWalletId) {
|
||||
return callback('TEE failed to sign transction: ' + result.Status);
|
||||
}
|
||||
return callback(null, result);
|
||||
};
|
||||
|
||||
function initSource(opts, callback) {
|
||||
var args = {
|
||||
"Testnet" : (opts.networkName == 'livenet'? false : true),
|
||||
"PINUnlockRequired" : false,
|
||||
"PINSignatureDataRequired" : false,
|
||||
"PINSignatureTransaction" : 0,
|
||||
"ExportCount" : 10,
|
||||
"MaxPINAttempts" : 3,
|
||||
"PINTimeout" : 30
|
||||
};
|
||||
|
||||
var teeStatus = root.walletEnclave.createWallet(TEE_APP_ID, args);
|
||||
switch (teeStatus) {
|
||||
case "CREATE WALLET FAILURE":
|
||||
case "CREATE WALLET FAILED TO INITIALIZE":
|
||||
case "CREATE WALLET FAILURE BAD INPUT":
|
||||
case "CREATE WALLET FAILURE case SERIALIZATION":
|
||||
case "DELETE_WALLET_AUTHORIZATION_UNSUCCESSFUL":
|
||||
case "LOAD_WALLET_FAILTURE":
|
||||
case "IMPORT WORD LIST FAILTURE":
|
||||
case "IMPORT WORD LIST FAILURE BAD INPUT":
|
||||
case "IMPORT WORD NOT IN DICTIONARY":
|
||||
case "INVALID PIN":
|
||||
case "INVALID APPLICATION ID":
|
||||
case "DISPLAY WORD LIST FAILURE":
|
||||
case "DELETE WALLET NO SUCH APPLICATION ID":
|
||||
case "SIGN DATA FAILURE":
|
||||
case "SIGN DATA INVALID HASH":
|
||||
case "SIGN DATA BUFFER TOO SMALL":
|
||||
case "SIGN DATA INVALID PIN":
|
||||
case "RECEIVE ADDRESS INVALID INPUT":
|
||||
case "RECEIVE ADDRESS NULL":
|
||||
case "RECEIVE ADDRESS BUFFER TOO SMALL":
|
||||
case "PUBLIC KEY BUFFER TOO SMALL":
|
||||
case "LOAD WALLET FAILURE":
|
||||
case "PUBLIC KEY FAILURE":
|
||||
case "PUBLIC KEY FAIL TO SERIALIZE":
|
||||
case "UKNOWN ERROR CODE":
|
||||
$log.error(teeStatus);
|
||||
return callback(teeStatus); // TODO: translate error text for display
|
||||
break;
|
||||
default:
|
||||
opts.hwInfo = {
|
||||
name: root.description.id,
|
||||
id: teeStatus
|
||||
};
|
||||
$log.debug('TEE wallet created: ' + opts.hwInfo.id);
|
||||
return callback(null, opts);
|
||||
}
|
||||
};
|
||||
|
||||
return root;
|
||||
});
|
||||
|
|
@ -1,10 +1,19 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services')
|
||||
.factory('ledger', function($log, bwcService, gettext, hwWallet) {
|
||||
.factory('ledger', function($log, bwcService, gettext, hwWallet, platformInfo) {
|
||||
var root = {};
|
||||
var LEDGER_CHROME_ID = "kkdpmhnladdopljabkgpacgpliggeeaf";
|
||||
|
||||
root.description = {
|
||||
supported: platformInfo.supportsLedger,
|
||||
id: 'ledger',
|
||||
name: 'Ledger',
|
||||
longName: 'Ledger Hardware Wallet',
|
||||
isEmbeddedHardware: false,
|
||||
supportsTestnet: false
|
||||
};
|
||||
|
||||
root.callbacks = {};
|
||||
root.hasSession = function() {
|
||||
root._message({
|
||||
|
|
@ -13,7 +22,7 @@ angular.module('copayApp.services')
|
|||
}
|
||||
|
||||
root.getEntropySource = function(isMultisig, account, callback) {
|
||||
root.getXPubKey(hwWallet.getEntropyPath('ledger', isMultisig, account), function(data) {
|
||||
root.getXPubKey(hwWallet.getEntropyPath(root.description.id, isMultisig, account), function(data) {
|
||||
if (!data.success)
|
||||
return callback(hwWallet._err(data));
|
||||
|
||||
|
|
@ -30,21 +39,28 @@ angular.module('copayApp.services')
|
|||
});
|
||||
};
|
||||
|
||||
root.getInfoForNewWallet = function(isMultisig, account, callback) {
|
||||
root.initSource = function(opts, callback) {
|
||||
// No initialization for this hardware source.
|
||||
return callback(opts);
|
||||
};
|
||||
|
||||
root.getInfoForNewWallet = function(isMultisig, account, networkName, callback) {
|
||||
// networkName not used for this hardware (always livenet)
|
||||
root.getEntropySource(isMultisig, account, function(err, entropySource) {
|
||||
if (err) return callback(err);
|
||||
|
||||
root.getXPubKey(hwWallet.getAddressPath('ledger', isMultisig, account), function(data) {
|
||||
if (!data.success) return callback(data);
|
||||
|
||||
var opts = {};
|
||||
opts.entropySource = entropySource;
|
||||
var opts = {};
|
||||
opts.entropySource = entropySource;
|
||||
root.getXPubKey(hwWallet.getAddressPath(root.description.id, isMultisig, account), function(data) {
|
||||
if (!data.success) {
|
||||
$log.warn(data.message);
|
||||
return callback(data);
|
||||
}
|
||||
opts.extendedPublicKey = data.xpubkey;
|
||||
opts.externalSource = 'ledger';
|
||||
opts.account = account;
|
||||
opts.externalSource = root.description.id;
|
||||
|
||||
// Old ledger compat
|
||||
opts.derivationStrategy = account ? 'BIP48' : 'BIP44';
|
||||
opts.derivationStrategy = opts.account ? 'BIP48' : 'BIP44';
|
||||
return callback(null, opts);
|
||||
});
|
||||
});
|
||||
|
|
@ -57,7 +73,7 @@ angular.module('copayApp.services')
|
|||
var tx = bwcService.getUtils().buildTx(txp);
|
||||
for (var i = 0; i < tx.inputs.length; i++) {
|
||||
redeemScripts.push(new ByteString(tx.inputs[i].redeemScript.toBuffer().toString('hex'), GP.HEX).toString());
|
||||
paths.push(hwWallet.getAddressPath('ledger', isMultisig, account) + txp.inputs[i].path.substring(1));
|
||||
paths.push(hwWallet.getAddressPath(root.description.id, isMultisig, account) + txp.inputs[i].path.substring(1));
|
||||
}
|
||||
var splitTransaction = root._splitTransaction(new ByteString(tx.toString(), GP.HEX));
|
||||
var inputs = [];
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
angular.module('copayApp.services').factory('ongoingProcess', function($log, $timeout, $filter, lodash, $ionicLoading, gettext, platformInfo) {
|
||||
var root = {};
|
||||
var isCordova = platformInfo.isCordova;
|
||||
var isWP = platformInfo.isWP;
|
||||
|
||||
var ongoingProcess = {};
|
||||
|
||||
|
|
@ -49,7 +50,7 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti
|
|||
|
||||
root.clear = function() {
|
||||
ongoingProcess = {};
|
||||
if (isCordova) {
|
||||
if (isCordova && !isWP) {
|
||||
window.plugins.spinnerDialog.hide();
|
||||
} else {
|
||||
$ionicLoading.hide();
|
||||
|
|
@ -79,21 +80,23 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti
|
|||
if (customHandler) {
|
||||
customHandler(processName, showName, isOn);
|
||||
} else if (root.onGoingProcessName) {
|
||||
if (isCordova) {
|
||||
if (isCordova && !isWP) {
|
||||
window.plugins.spinnerDialog.show(null, showName, root.clear);
|
||||
} else {
|
||||
|
||||
var tmpl = '<div class="item-icon-left">' + showName + '<ion-spinner class="spinner-stable" icon="lines"></ion-spinner></div>';
|
||||
var tmpl;
|
||||
if (isWP) tmpl = '<div>' + showName +'</div>';
|
||||
else tmpl = '<div class="item-icon-left">' + showName + '<ion-spinner class="spinner-stable" icon="lines"></ion-spinner></div>';
|
||||
$ionicLoading.show({
|
||||
template: tmpl
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (isCordova) {
|
||||
if (isCordova && !isWP) {
|
||||
window.plugins.spinnerDialog.hide();
|
||||
} else {
|
||||
$ionicLoading.hide();
|
||||
}
|
||||
$ionicLoading.hide();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('openURLService', function($rootScope, $ionicHistory, $document, $log, $state, platformInfo, lodash, profileService, incomingData, appConfigService) {
|
||||
var DELAY_UNLOCK_TIME = 2 * 60;
|
||||
var root = {};
|
||||
|
||||
root.unlockUntil = null;
|
||||
|
||||
var handleOpenURL = function(args) {
|
||||
root.unlockUntil = Math.floor(Date.now() / 1000) + DELAY_UNLOCK_TIME;
|
||||
$log.debug('Set unlock time until: ' + root.unlockUntil);
|
||||
|
||||
$log.info('Handling Open URL: ' + JSON.stringify(args));
|
||||
// Stop it from caching the first view as one to return when the app opens
|
||||
$ionicHistory.nextViewOptions({
|
||||
|
|
@ -103,5 +109,5 @@ angular.module('copayApp.services').factory('openURLService', function($rootScop
|
|||
});
|
||||
};
|
||||
|
||||
return root;
|
||||
return root;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,51 +1,39 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('payproService',
|
||||
function($window, profileService, platformInfo, popupService, gettextCatalog, ongoingProcess, $log) {
|
||||
function(profileService, platformInfo, gettextCatalog, ongoingProcess, $log) {
|
||||
|
||||
var ret = {};
|
||||
var ret = {};
|
||||
|
||||
ret.getPayProDetails = function(uri, cb, disableLoader) {
|
||||
if (!cb) cb = function() {};
|
||||
ret.getPayProDetails = function(uri, cb, disableLoader) {
|
||||
if (!cb) cb = function() {};
|
||||
|
||||
var wallet = profileService.getWallets({
|
||||
onlyComplete: true
|
||||
})[0];
|
||||
var wallet = profileService.getWallets({
|
||||
onlyComplete: true
|
||||
})[0];
|
||||
|
||||
if (!wallet) return cb();
|
||||
if (!wallet) return cb();
|
||||
|
||||
if (platformInfo.isChromeApp) {
|
||||
popupService.showAlert(gettextCatalog.getString('Payment Protocol not supported on Chrome App'));
|
||||
return cb(true);
|
||||
}
|
||||
|
||||
$log.debug('Fetch PayPro Request...', uri);
|
||||
|
||||
if(!disableLoader) {
|
||||
ongoingProcess.set('fetchingPayPro', true);
|
||||
}
|
||||
|
||||
wallet.fetchPayPro({
|
||||
payProUrl: uri,
|
||||
}, function(err, paypro) {
|
||||
|
||||
if(!disableLoader) {
|
||||
ongoingProcess.set('fetchingPayPro', false);
|
||||
if (platformInfo.isChromeApp) {
|
||||
return cb(gettextCatalog.getString('Payment Protocol not supported on Chrome App'));
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return cb(true);
|
||||
}
|
||||
$log.debug('Fetch PayPro Request...', uri);
|
||||
|
||||
if (!paypro.verified) {
|
||||
$log.warn('Failed to verify payment protocol signatures');
|
||||
popupService.showAlert(gettextCatalog.getString('Payment Protocol Invalid'));
|
||||
return cb(true);
|
||||
}
|
||||
cb(null, paypro);
|
||||
if (!disableLoader) ongoingProcess.set('fetchingPayPro', true);
|
||||
|
||||
});
|
||||
};
|
||||
wallet.fetchPayPro({
|
||||
payProUrl: uri,
|
||||
}, function(err, paypro) {
|
||||
if (!disableLoader) ongoingProcess.set('fetchingPayPro', false);
|
||||
if (err) return cb(err);
|
||||
else if (!paypro.verified) {
|
||||
$log.warn('Failed to verify payment protocol signatures');
|
||||
return cb(gettextCatalog.getString('Payment Protocol Invalid'));
|
||||
}
|
||||
return cb(null, paypro);
|
||||
});
|
||||
};
|
||||
|
||||
return ret;
|
||||
});
|
||||
return ret;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,6 +23,27 @@ angular.module('copayApp.services').factory('platformInfo', function($window) {
|
|||
}
|
||||
};
|
||||
|
||||
var getVersionIntelTee = function() {
|
||||
var v = '';
|
||||
var isWindows = navigator.platform.indexOf('Win') > -1;
|
||||
|
||||
if (!isNodeWebkit() || !isWindows) {
|
||||
return v;
|
||||
}
|
||||
|
||||
try {
|
||||
var IntelWallet = require('intelWalletCon');
|
||||
if (IntelWallet.getVersion) {
|
||||
v = IntelWallet.getVersion();
|
||||
} else {
|
||||
v = 'Alpha';
|
||||
}
|
||||
if (v.length > 0) {
|
||||
$log.info('Intel TEE library ' + v);
|
||||
}
|
||||
} catch (e) {}
|
||||
return v;
|
||||
};
|
||||
|
||||
// Detect mobile devices
|
||||
var ret = {
|
||||
|
|
@ -39,5 +60,11 @@ angular.module('copayApp.services').factory('platformInfo', function($window) {
|
|||
ret.isChromeApp = $window.chrome && chrome.runtime && chrome.runtime.id && !ret.isNW;
|
||||
ret.isDevel = !ret.isMobile && !ret.isChromeApp && !ret.isNW;
|
||||
|
||||
ret.supportsLedger = ret.isChromeApp;
|
||||
ret.supportsTrezor = ret.isChromeApp || ret.isDevel;
|
||||
|
||||
ret.versionIntelTEE = getVersionIntelTee();
|
||||
ret.supportsIntelTEE = ret.versionIntelTEE.length > 0;
|
||||
|
||||
return ret;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -347,6 +347,7 @@ angular.module('copayApp.services')
|
|||
account: opts.account || 0,
|
||||
derivationStrategy: opts.derivationStrategy || 'BIP44',
|
||||
});
|
||||
walletClient.credentials.hwInfo = opts.hwInfo;
|
||||
} catch (ex) {
|
||||
$log.warn("Creating wallet from Extended Public Key Arg:", ex, opts);
|
||||
return cb(gettextCatalog.getString('Could not create using the specified extended public key'));
|
||||
|
|
|
|||
36
src/js/services/sendMax.js
Normal file
36
src/js/services/sendMax.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').service('sendMaxService', function(feeService, configService, walletService) {
|
||||
|
||||
/**
|
||||
* Get sendMaxInfo
|
||||
*
|
||||
* @param {Obj} Wallet
|
||||
* @param {Callback} Function (optional)
|
||||
*
|
||||
*/
|
||||
this.getInfo = function(wallet, cb) {
|
||||
feeService.getCurrentFeeValue(wallet.credentials.network, function(err, feePerKb) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var config = configService.getSync().wallet;
|
||||
|
||||
walletService.getSendMaxInfo(wallet, {
|
||||
feePerKb: feePerKb,
|
||||
excludeUnconfirmedUtxos: !config.spendUnconfirmed,
|
||||
returnInputs: true,
|
||||
}, function(err, resp) {
|
||||
if (err) return cb(err);
|
||||
|
||||
return cb(null, {
|
||||
sendMax: true,
|
||||
amount: resp.amount,
|
||||
inputs: resp.inputs,
|
||||
fee: resp.fee,
|
||||
feePerKb: feePerKb,
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -1,14 +1,24 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services')
|
||||
.factory('trezor', function($log, $timeout, lodash, bitcore, hwWallet) {
|
||||
.factory('trezor', function($log, $timeout, lodash, bitcore, hwWallet, platformInfo) {
|
||||
var root = {};
|
||||
|
||||
var SETTLE_TIME = 3000;
|
||||
root.callbacks = {};
|
||||
|
||||
root.description = {
|
||||
supported: platformInfo.supportsTrezor,
|
||||
id: 'trezor',
|
||||
name: 'Trezor',
|
||||
longName: 'Trezor Hardware Wallet',
|
||||
derivationStrategy: 'BIP48',
|
||||
isEmbeddedHardware: false,
|
||||
supportsTestnet: false
|
||||
};
|
||||
|
||||
root.getEntropySource = function(isMultisig, account, callback) {
|
||||
root.getXPubKey(hwWallet.getEntropyPath('trezor', isMultisig, account), function(data) {
|
||||
root.getXPubKey(hwWallet.getEntropyPath(root.description.id, isMultisig, account), function(data) {
|
||||
if (!data.success)
|
||||
return callback(hwWallet._err(data));
|
||||
|
||||
|
|
@ -26,8 +36,13 @@ angular.module('copayApp.services')
|
|||
}
|
||||
};
|
||||
|
||||
root.initSource = function(opts, callback) {
|
||||
// No initialization for this hardware source.
|
||||
return callback(opts);
|
||||
};
|
||||
|
||||
root.getInfoForNewWallet = function(isMultisig, account, callback) {
|
||||
root.getInfoForNewWallet = function(isMultisig, account, networkName, callback) {
|
||||
// networkName not used for this hardware (always livenet)
|
||||
var opts = {};
|
||||
root.getEntropySource(isMultisig, account, function(err, data) {
|
||||
if (err) return callback(err);
|
||||
|
|
@ -35,13 +50,12 @@ angular.module('copayApp.services')
|
|||
$log.debug('Waiting TREZOR to settle...');
|
||||
$timeout(function() {
|
||||
|
||||
root.getXPubKey(hwWallet.getAddressPath('trezor', isMultisig, account), function(data) {
|
||||
root.getXPubKey(hwWallet.getAddressPath(root.description.id, isMultisig, account), function(data) {
|
||||
if (!data.success)
|
||||
return callback(hwWallet._err(data));
|
||||
|
||||
opts.extendedPublicKey = data.xpubkey;
|
||||
opts.externalSource = 'trezor';
|
||||
opts.account = account;
|
||||
opts.externalSource = root.description.id;
|
||||
|
||||
if (isMultisig)
|
||||
opts.derivationStrategy = 'BIP48';
|
||||
|
|
|
|||
|
|
@ -155,5 +155,42 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
return txps;
|
||||
};
|
||||
|
||||
root.parseAmount = function(amount, currency) {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var satToBtc = 1 / 100000000;
|
||||
var unitToSatoshi = config.unitToSatoshi;
|
||||
var amountUnitStr;
|
||||
var amountSat;
|
||||
var alternativeIsoCode = config.alternativeIsoCode;
|
||||
|
||||
// If fiat currency
|
||||
if (currency != 'bits' && currency != 'BTC') {
|
||||
amountUnitStr = $filter('formatFiatAmount')(amount) + ' ' + currency;
|
||||
amountSat = rateService.fromFiat(amount, currency).toFixed(0);
|
||||
} else {
|
||||
amountSat = parseInt((amount * unitToSatoshi).toFixed(0));
|
||||
amountUnitStr = root.formatAmountStr(amountSat);
|
||||
// convert unit to BTC
|
||||
amount = (amountSat * satToBtc).toFixed(8);
|
||||
currency = 'BTC';
|
||||
}
|
||||
|
||||
return {
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
alternativeIsoCode: alternativeIsoCode,
|
||||
amountSat: amountSat,
|
||||
amountUnitStr: amountUnitStr
|
||||
};
|
||||
};
|
||||
|
||||
root.satToUnit = function(amount) {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var unitToSatoshi = config.unitToSatoshi;
|
||||
var satToUnit = 1 / unitToSatoshi;
|
||||
var unitDecimals = config.unitDecimals;
|
||||
return parseFloat((amount * satToUnit).toFixed(unitDecimals));
|
||||
};
|
||||
|
||||
return root;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('walletService', function($log, $timeout, lodash, trezor, ledger, storageService, configService, rateService, uxLanguage, $filter, gettextCatalog, bwcError, $ionicPopup, fingerprintService, ongoingProcess, gettext, $rootScope, txFormatService, $ionicModal, $state, bwcService, bitcore, popupService) {
|
||||
angular.module('copayApp.services').factory('walletService', function($log, $timeout, lodash, trezor, ledger, intelTEE, storageService, configService, rateService, uxLanguage, $filter, gettextCatalog, bwcError, $ionicPopup, fingerprintService, ongoingProcess, gettext, $rootScope, txFormatService, $ionicModal, $state, bwcService, bitcore, popupService) {
|
||||
// `wallet` is a decorated version of client.
|
||||
|
||||
var root = {};
|
||||
|
||||
root.externalSource = {
|
||||
ledger: ledger.description,
|
||||
trezor: trezor.description,
|
||||
intelTEE: intelTEE.description
|
||||
}
|
||||
|
||||
root.WALLET_STATUS_MAX_TRIES = 7;
|
||||
root.WALLET_STATUS_DELAY_BETWEEN_TRIES = 1.4 * 1000;
|
||||
root.SOFT_CONFIRMATION_LIMIT = 12;
|
||||
|
|
@ -40,6 +46,43 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
});
|
||||
};
|
||||
|
||||
var _signWithIntelTEE = function(wallet, txp, cb) {
|
||||
$log.info('Requesting Intel TEE to sign the transaction');
|
||||
|
||||
intelTEE.signTx(wallet.credentials.hwInfo.id, txp, function(err, result) {
|
||||
if (err) return cb(err);
|
||||
|
||||
$log.debug('Intel TEE response', result);
|
||||
txp.signatures = result.Signatures;
|
||||
return wallet.signTxProposal(txp, cb);
|
||||
});
|
||||
};
|
||||
|
||||
root.showMneumonicFromHardware = function(wallet, cb) {
|
||||
switch (wallet.getPrivKeyExternalSourceName()) {
|
||||
case root.externalSource.intelTEE.id:
|
||||
return intelTEE.showMneumonic(wallet.credentials.hwInfo.id, cb);
|
||||
break;
|
||||
default:
|
||||
cb('Error: unrecognized external source');
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
root.showReceiveAddressFromHardware = function(wallet, address, cb) {
|
||||
switch (wallet.getPrivKeyExternalSourceName()) {
|
||||
case root.externalSource.intelTEE.id:
|
||||
root.getAddressObj(wallet, address, function(err, addrObj) {
|
||||
if (err) return cb(err);
|
||||
return intelTEE.showReceiveAddress(wallet.credentials.hwInfo.id, addrObj, cb);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
cb('Error: unrecognized external source');
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
root.invalidateCache = function(wallet) {
|
||||
if (wallet.cachedStatus)
|
||||
wallet.cachedStatus.isValid = false;
|
||||
|
|
@ -629,10 +672,12 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
|
||||
if (wallet.isPrivKeyExternal()) {
|
||||
switch (wallet.getPrivKeyExternalSourceName()) {
|
||||
case 'ledger':
|
||||
case root.externalSource.ledger.id:
|
||||
return _signWithLedger(wallet, txp, cb);
|
||||
case 'trezor':
|
||||
case root.externalSource.trezor.id:
|
||||
return _signWithTrezor(wallet, txp, cb);
|
||||
case root.externalSource.intelTEE.id:
|
||||
return _signWithIntelTEE(wallet, txp, cb);
|
||||
default:
|
||||
var msg = 'Unsupported External Key:' + wallet.getPrivKeyExternalSourceName();
|
||||
$log.error(msg);
|
||||
|
|
@ -845,6 +890,21 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
});
|
||||
};
|
||||
|
||||
root.getAddressObj = function(wallet, address, cb) {
|
||||
wallet.getMainAddresses({
|
||||
reverse: true
|
||||
}, function(err, addr) {
|
||||
if (err) return cb(err);
|
||||
var addrObj = lodash.find(addr, function(a) {
|
||||
return a.address == address;
|
||||
});
|
||||
var err = null;
|
||||
if (!addrObj) {
|
||||
err = 'Error: specified address not in wallet';
|
||||
}
|
||||
return cb(err, addrObj);
|
||||
});
|
||||
};
|
||||
|
||||
root.isReady = function(wallet, cb) {
|
||||
if (!wallet.isComplete())
|
||||
|
|
|
|||
|
|
@ -116,7 +116,6 @@ $v-onboarding-checkbox-on-border: $v-success-color !default;
|
|||
$v-onboarding-tour-phone-bg: url(../img/onboarding-tour-phone.svg) !default;
|
||||
$v-onboarding-tour-currency-bg: url(../img/onboarding-tour-currency-bg.svg) !default;
|
||||
$v-onboarding-tour-control-bg: url(../img/onboarding-tour-control.svg) !default;
|
||||
$v-onboarding-push-notification-bg: url(../img/onboarding-push-notifications.svg) !default;
|
||||
$v-onboarding-backup-warning-bg: url(../img/backup-warning.svg) !default;
|
||||
|
||||
$v-onboarding-button-back-color: #ffffff !default;
|
||||
|
|
|
|||
|
|
@ -89,6 +89,17 @@
|
|||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
&.low-fees {
|
||||
border-top: none;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
color: #aaa;
|
||||
align-items: center;
|
||||
margin-top: -20px;
|
||||
i {
|
||||
padding-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.item-divider {
|
||||
padding-top: 1.2rem;
|
||||
|
|
|
|||
42
src/sass/views/lockedView.scss
Normal file
42
src/sass/views/lockedView.scss
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#locked-view {
|
||||
@mixin img-frame {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
box-shadow: none;
|
||||
margin: auto;
|
||||
}
|
||||
.img-container-copay {
|
||||
padding: 20%;
|
||||
@media(min-width: 480px) {
|
||||
max-height: 150px;
|
||||
}
|
||||
.big-icon-svg {
|
||||
> .bg {
|
||||
@include img-frame;
|
||||
background-image: url("../img/icon-fingerprint-copay.svg");
|
||||
}
|
||||
}
|
||||
}
|
||||
.img-container-bitpay {
|
||||
padding: 20%;
|
||||
@media(min-width: 480px) {
|
||||
max-height: 150px;
|
||||
}
|
||||
.big-icon-svg {
|
||||
> .bg {
|
||||
@include img-frame;
|
||||
background-image: url("../img/icon-fingerprint-bitpay.svg");
|
||||
}
|
||||
}
|
||||
}
|
||||
.comments {
|
||||
text-align: center;
|
||||
.header {
|
||||
font-size: 20px;
|
||||
}
|
||||
.text-content {
|
||||
width: 90%;
|
||||
margin: 5% auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#onboarding-push-notifications {
|
||||
#notifications-topic {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
#cta-buttons {
|
||||
@extend %cta-buttons;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -82,7 +82,6 @@
|
|||
@import "onboard-backup-request";
|
||||
@import "../backup-warning";
|
||||
@import "onboard-disclaimer";
|
||||
@import "onboard-push-notifications";
|
||||
|
||||
%onboarding-illustration {
|
||||
width: 100%;
|
||||
|
|
@ -124,10 +123,6 @@
|
|||
@extend %onboarding-illustration;
|
||||
background-image: $v-onboarding-tour-control-bg;
|
||||
}
|
||||
&-notifications {
|
||||
@extend %onboarding-illustration;
|
||||
background-image: $v-onboarding-push-notification-bg;
|
||||
}
|
||||
&-backup-warning {
|
||||
@extend %onboarding-illustration;
|
||||
background-image: $v-onboarding-backup-warning-bg;
|
||||
|
|
|
|||
95
src/sass/views/pin.scss
Normal file
95
src/sass/views/pin.scss
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
#pin {
|
||||
background-color: #FAFAFA;
|
||||
.bar.bar-clear {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
.back-button .icon:before {
|
||||
color: #2d3f50;
|
||||
}
|
||||
}
|
||||
.content {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.app-icon {
|
||||
margin-top: -55px;
|
||||
.big-icon-svg {
|
||||
> .bg {
|
||||
background-image: url("../img/app/icon.png");
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
.block-text {
|
||||
align-items: center;
|
||||
background-color: #F1F1F1;
|
||||
height: 30%;
|
||||
border-bottom: 1px solid #c5c5c5;
|
||||
.message {
|
||||
margin: auto;
|
||||
}
|
||||
span {
|
||||
width: 60%;
|
||||
margin: 10% auto;
|
||||
}
|
||||
@media(min-width: 480px) {
|
||||
span {
|
||||
font-size: 30px;
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.block-code {
|
||||
width: 50%;
|
||||
margin: auto;
|
||||
@media(min-width: 480px) {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
.block-buttons {
|
||||
.col {
|
||||
padding: 5%;
|
||||
}
|
||||
color: $v-dark-gray;
|
||||
font-size: 1.7rem;
|
||||
font-family: $v-font-family-light;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
bottom: 3%;
|
||||
left: 5%;
|
||||
width: 90%;
|
||||
@media(min-width: 480px) {
|
||||
left: 15%;
|
||||
width: 70%;
|
||||
max-height: 55%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@mixin circle {
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 3px 0px #5b5b5b;
|
||||
transition: background-color .2s ease-in-out;
|
||||
padding: 7%;
|
||||
margin: 5%;
|
||||
}
|
||||
.circle-copay {
|
||||
@include circle;
|
||||
border: 1px solid $v-accent-color;
|
||||
}
|
||||
.circle-bitpay {
|
||||
@include circle;
|
||||
border: 1px solid $v-primary-color;
|
||||
}
|
||||
.filled-copay {
|
||||
background-color: $v-accent-color;
|
||||
}
|
||||
.filled-bitpay {
|
||||
background-color: #1f3598;
|
||||
}
|
||||
.error {
|
||||
color: #f13333;
|
||||
max-width: 70%;
|
||||
}
|
||||
}
|
||||
|
|
@ -162,6 +162,17 @@
|
|||
transform: translate(100%, -40%);
|
||||
}
|
||||
}
|
||||
.overlay {
|
||||
position: absolute;
|
||||
width: 220px;
|
||||
height: 100%;
|
||||
background-color: rgba(255,255,255,0.8);
|
||||
button {
|
||||
width: 100%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
@media(max-height: 700px) {
|
||||
padding: 10vh 0 4vh;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,13 @@
|
|||
.icon-bitpay {
|
||||
background-image: url("../img/icon-bitpay.svg");
|
||||
}
|
||||
.warning {
|
||||
color: $v-warning-color;
|
||||
}
|
||||
.centered {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.disabled {
|
||||
color: $v-light-gray;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,3 +46,5 @@
|
|||
@import "includes/accountSelector";
|
||||
@import "integrations/integrations";
|
||||
@import "custom-amount";
|
||||
@import "pin";
|
||||
@import "lockedView";
|
||||
|
|
|
|||
|
|
@ -209,6 +209,20 @@
|
|||
font-size: 13px;
|
||||
color: $v-mid-gray;
|
||||
}
|
||||
.low-fees {
|
||||
.comment {
|
||||
color: $v-mid-gray;
|
||||
font-size: 12.5px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
margin-left: 25px;
|
||||
}
|
||||
img {
|
||||
position: absolute;
|
||||
margin-top: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wallet-details-wallet-info {
|
||||
|
|
@ -238,7 +252,7 @@ a.item {
|
|||
|
||||
.recent svg {
|
||||
margin-left:5px;
|
||||
width:0.7em;
|
||||
width:0.7em;
|
||||
height:0.7em;
|
||||
stroke: #eee;
|
||||
}
|
||||
|
|
|
|||
52
www/img/icon-fingerprint-bitpay.svg
Normal file
52
www/img/icon-fingerprint-bitpay.svg
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 425.034 425.034" style="enable-background:new 0 0 425.034 425.034;" xml:space="preserve" width="512px" height="512px">
|
||||
<g>
|
||||
<path d="M133.822,384.2c-33.836-24.953-54.037-64.915-54.037-106.898V147.731c0-3.798,0.162-7.633,0.482-11.396 c0.351-4.127-2.711-7.757-6.838-8.108c-4.123-0.347-7.757,2.711-8.108,6.838c-0.355,4.184-0.536,8.446-0.536,12.666v129.571 c0,23.526,5.669,46.938,16.395,67.704c10.375,20.087,25.5,37.815,43.739,51.266c1.34,0.988,2.899,1.464,4.446,1.464 c2.301,0,4.572-1.055,6.042-3.049C137.865,391.354,137.156,386.659,133.822,384.2z" fill="#1e3186"/>
|
||||
<path d="M168.819,402.675c-4.619-1.61-9.197-3.499-13.61-5.615c-3.734-1.791-8.215-0.215-10.005,3.521 c-1.791,3.735-0.215,8.215,3.52,10.005c4.915,2.356,10.014,4.46,15.158,6.253c0.817,0.285,1.65,0.42,2.469,0.42 c3.102,0,6.003-1.939,7.082-5.033C174.795,408.315,172.73,404.039,168.819,402.675z" fill="#1e3186"/>
|
||||
<path d="M352.749,243.219c-4.143,0-7.5,3.358-7.5,7.5v26.584c0,73.188-59.543,132.731-132.732,132.731 c-5.179,0-10.395-0.301-15.502-0.895c-4.12-0.479-7.838,2.469-8.316,6.584c-0.479,4.115,2.469,7.838,6.583,8.316 c5.681,0.661,11.479,0.995,17.235,0.995c81.459,0,147.731-66.272,147.731-147.731v-26.584 C360.249,246.576,356.891,243.219,352.749,243.219z" fill="#1e3186"/>
|
||||
<path d="M212.517,0c-31.895,0-62.263,10.003-87.824,28.928C99.64,47.478,81.373,72.889,71.867,102.417 c-1.27,3.943,0.898,8.168,4.841,9.438c3.944,1.268,8.168-0.898,9.438-4.841c8.54-26.525,24.955-49.358,47.473-66.03 C156.577,23.985,183.86,15,212.517,15c73.188,0,132.731,59.543,132.731,132.731v72.987c0,4.142,3.357,7.5,7.5,7.5 s7.5-3.358,7.5-7.5v-72.987C360.249,66.272,293.976,0,212.517,0z" fill="#1e3186"/>
|
||||
<path d="M111.172,318.746c-3.715,1.833-5.24,6.33-3.408,10.044c9.504,19.263,24.13,35.549,42.296,47.096 c18.678,11.873,40.275,18.149,62.457,18.149c16.784,0,32.996-3.504,48.187-10.415c3.771-1.715,5.437-6.162,3.722-9.932 c-1.716-3.77-6.162-5.438-9.933-3.721c-13.227,6.017-27.35,9.068-41.976,9.068c-19.327,0-38.142-5.466-54.411-15.808 c-15.846-10.073-28.603-24.276-36.89-41.073C119.384,318.439,114.885,316.913,111.172,318.746z" fill="#1e3186"/>
|
||||
<path d="M284.635,366.78c1.761,0,3.529-0.616,4.954-1.872c25.204-22.199,39.659-54.13,39.659-87.605V147.732 c0-24.963-7.801-48.792-22.559-68.909c-2.449-3.34-7.142-4.061-10.483-1.611c-3.34,2.45-4.061,7.144-1.61,10.484 c12.856,17.526,19.652,38.286,19.652,60.036v129.571c0,29.169-12.602,56.997-34.573,76.349c-3.108,2.738-3.409,7.477-0.671,10.585 C280.487,365.92,282.556,366.78,284.635,366.78z" fill="#1e3186"/>
|
||||
<path d="M270.318,64.059c1.304,0.903,2.792,1.337,4.266,1.337c2.377,0,4.715-1.127,6.171-3.228 c2.359-3.405,1.513-8.077-1.892-10.437c-5.678-3.935-11.733-7.382-18-10.244c-3.771-1.721-8.217-0.061-9.938,3.706 c-1.721,3.768-0.062,8.217,3.706,9.938C260.091,57.625,265.369,60.628,270.318,64.059z" fill="#1e3186"/>
|
||||
<path d="M232.047,32.634C225.635,31.55,219.064,31,212.517,31C148.152,31,95.786,83.366,95.786,147.732v125.987 c0,4.142,3.358,7.5,7.5,7.5s7.5-3.358,7.5-7.5V147.732C110.786,91.637,156.423,46,212.517,46c5.711,0,11.44,0.479,17.027,1.424 c4.096,0.69,7.955-2.061,8.646-6.144C238.882,37.196,236.131,33.325,232.047,32.634z" fill="#1e3186"/>
|
||||
<path d="M141.452,99.821c-2.32,3.431-1.419,8.094,2.012,10.414c3.431,2.319,8.094,1.419,10.414-2.012 C167.097,88.672,189.018,77,212.517,77c39.001,0,70.731,31.73,70.731,70.732v83.987c0,4.142,3.357,7.5,7.5,7.5s7.5-3.358,7.5-7.5 v-83.987c0-47.273-38.459-85.732-85.731-85.732C184.031,62,157.465,76.139,141.452,99.821z" fill="#1e3186"/>
|
||||
<path d="M134.286,173.218c4.142,0,7.5-3.358,7.5-7.5v-17.986c0-4.142-3.358-7.5-7.5-7.5s-7.5,3.358-7.5,7.5v17.986 C126.786,169.86,130.144,173.218,134.286,173.218z" fill="#1e3186"/>
|
||||
<path d="M126.786,277.303c0,31.025,16.878,59.725,44.048,74.901c1.158,0.647,2.412,0.954,3.65,0.954 c2.629,0,5.182-1.385,6.555-3.844c2.02-3.616,0.726-8.185-2.891-10.205c-22.429-12.528-36.362-36.21-36.362-61.805v-81.584 c0-4.142-3.358-7.5-7.5-7.5s-7.5,3.358-7.5,7.5V277.303z" fill="#1e3186"/>
|
||||
<path d="M298.249,277.303v-13.584c0-4.142-3.357-7.5-7.5-7.5s-7.5,3.358-7.5,7.5v13.584c0,39.001-31.73,70.732-70.731,70.732 c-5.698,0-11.369-0.682-16.853-2.028c-4.025-0.987-8.084,1.474-9.071,5.497s1.474,8.084,5.497,9.071 c6.653,1.632,13.526,2.46,20.427,2.46C259.79,363.034,298.249,324.575,298.249,277.303z" fill="#1e3186"/>
|
||||
<path d="M267.249,148.524c0-30.05-24.079-54.953-53.677-55.514c-14.822-0.28-28.786,5.283-39.369,15.668 c-10.587,10.388-16.417,24.258-16.417,39.054v129.571c0,4.142,3.358,7.5,7.5,7.5s7.5-3.358,7.5-7.5V147.732 c0-10.736,4.234-20.803,11.923-28.347c7.685-7.541,17.873-11.576,28.578-11.377c21.483,0.407,38.962,18.583,38.962,40.517v71.194 c0,4.142,3.357,7.5,7.5,7.5s7.5-3.358,7.5-7.5V148.524z" fill="#1e3186"/>
|
||||
<path d="M188.786,285.987c0,21.632,17.599,39.232,39.231,39.232c21.632,0,39.231-17.599,39.231-39.232v-36.269 c0-4.142-3.357-7.5-7.5-7.5s-7.5,3.358-7.5,7.5v36.269c0,13.361-10.87,24.232-24.231,24.232s-24.231-10.87-24.231-24.232v-64.268 c0-4.142-3.358-7.5-7.5-7.5s-7.5,3.358-7.5,7.5V285.987z" fill="#1e3186"/>
|
||||
<path d="M228.749,290.603c4.143,0,7.5-3.358,7.5-7.5v-134.9c0-12.932-9.902-23.55-22.545-24.174 c-6.567-0.323-12.787,1.991-17.541,6.516c-4.688,4.463-7.377,10.727-7.377,17.187v41.987c0,4.142,3.358,7.5,7.5,7.5 s7.5-3.358,7.5-7.5v-41.987c0-2.407,0.966-4.653,2.72-6.322c1.75-1.666,4.034-2.518,6.46-2.399 c4.567,0.225,8.283,4.349,8.283,9.192v134.9C221.249,287.245,224.606,290.603,228.749,290.603z" fill="#1e3186"/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
52
www/img/icon-fingerprint-copay.svg
Normal file
52
www/img/icon-fingerprint-copay.svg
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 425.034 425.034" style="enable-background:new 0 0 425.034 425.034;" xml:space="preserve" width="512px" height="512px">
|
||||
<g>
|
||||
<path d="M133.822,384.2c-33.836-24.953-54.037-64.915-54.037-106.898V147.731c0-3.798,0.162-7.633,0.482-11.396 c0.351-4.127-2.711-7.757-6.838-8.108c-4.123-0.347-7.757,2.711-8.108,6.838c-0.355,4.184-0.536,8.446-0.536,12.666v129.571 c0,23.526,5.669,46.938,16.395,67.704c10.375,20.087,25.5,37.815,43.739,51.266c1.34,0.988,2.899,1.464,4.446,1.464 c2.301,0,4.572-1.055,6.042-3.049C137.865,391.354,137.156,386.659,133.822,384.2z" fill="#1abb9b"/>
|
||||
<path d="M168.819,402.675c-4.619-1.61-9.197-3.499-13.61-5.615c-3.734-1.791-8.215-0.215-10.005,3.521 c-1.791,3.735-0.215,8.215,3.52,10.005c4.915,2.356,10.014,4.46,15.158,6.253c0.817,0.285,1.65,0.42,2.469,0.42 c3.102,0,6.003-1.939,7.082-5.033C174.795,408.315,172.73,404.039,168.819,402.675z" fill="#1abb9b"/>
|
||||
<path d="M352.749,243.219c-4.143,0-7.5,3.358-7.5,7.5v26.584c0,73.188-59.543,132.731-132.732,132.731 c-5.179,0-10.395-0.301-15.502-0.895c-4.12-0.479-7.838,2.469-8.316,6.584c-0.479,4.115,2.469,7.838,6.583,8.316 c5.681,0.661,11.479,0.995,17.235,0.995c81.459,0,147.731-66.272,147.731-147.731v-26.584 C360.249,246.576,356.891,243.219,352.749,243.219z" fill="#1abb9b"/>
|
||||
<path d="M212.517,0c-31.895,0-62.263,10.003-87.824,28.928C99.64,47.478,81.373,72.889,71.867,102.417 c-1.27,3.943,0.898,8.168,4.841,9.438c3.944,1.268,8.168-0.898,9.438-4.841c8.54-26.525,24.955-49.358,47.473-66.03 C156.577,23.985,183.86,15,212.517,15c73.188,0,132.731,59.543,132.731,132.731v72.987c0,4.142,3.357,7.5,7.5,7.5 s7.5-3.358,7.5-7.5v-72.987C360.249,66.272,293.976,0,212.517,0z" fill="#1abb9b"/>
|
||||
<path d="M111.172,318.746c-3.715,1.833-5.24,6.33-3.408,10.044c9.504,19.263,24.13,35.549,42.296,47.096 c18.678,11.873,40.275,18.149,62.457,18.149c16.784,0,32.996-3.504,48.187-10.415c3.771-1.715,5.437-6.162,3.722-9.932 c-1.716-3.77-6.162-5.438-9.933-3.721c-13.227,6.017-27.35,9.068-41.976,9.068c-19.327,0-38.142-5.466-54.411-15.808 c-15.846-10.073-28.603-24.276-36.89-41.073C119.384,318.439,114.885,316.913,111.172,318.746z" fill="#1abb9b"/>
|
||||
<path d="M284.635,366.78c1.761,0,3.529-0.616,4.954-1.872c25.204-22.199,39.659-54.13,39.659-87.605V147.732 c0-24.963-7.801-48.792-22.559-68.909c-2.449-3.34-7.142-4.061-10.483-1.611c-3.34,2.45-4.061,7.144-1.61,10.484 c12.856,17.526,19.652,38.286,19.652,60.036v129.571c0,29.169-12.602,56.997-34.573,76.349c-3.108,2.738-3.409,7.477-0.671,10.585 C280.487,365.92,282.556,366.78,284.635,366.78z" fill="#1abb9b"/>
|
||||
<path d="M270.318,64.059c1.304,0.903,2.792,1.337,4.266,1.337c2.377,0,4.715-1.127,6.171-3.228 c2.359-3.405,1.513-8.077-1.892-10.437c-5.678-3.935-11.733-7.382-18-10.244c-3.771-1.721-8.217-0.061-9.938,3.706 c-1.721,3.768-0.062,8.217,3.706,9.938C260.091,57.625,265.369,60.628,270.318,64.059z" fill="#1abb9b"/>
|
||||
<path d="M232.047,32.634C225.635,31.55,219.064,31,212.517,31C148.152,31,95.786,83.366,95.786,147.732v125.987 c0,4.142,3.358,7.5,7.5,7.5s7.5-3.358,7.5-7.5V147.732C110.786,91.637,156.423,46,212.517,46c5.711,0,11.44,0.479,17.027,1.424 c4.096,0.69,7.955-2.061,8.646-6.144C238.882,37.196,236.131,33.325,232.047,32.634z" fill="#1abb9b"/>
|
||||
<path d="M141.452,99.821c-2.32,3.431-1.419,8.094,2.012,10.414c3.431,2.319,8.094,1.419,10.414-2.012 C167.097,88.672,189.018,77,212.517,77c39.001,0,70.731,31.73,70.731,70.732v83.987c0,4.142,3.357,7.5,7.5,7.5s7.5-3.358,7.5-7.5 v-83.987c0-47.273-38.459-85.732-85.731-85.732C184.031,62,157.465,76.139,141.452,99.821z" fill="#1abb9b"/>
|
||||
<path d="M134.286,173.218c4.142,0,7.5-3.358,7.5-7.5v-17.986c0-4.142-3.358-7.5-7.5-7.5s-7.5,3.358-7.5,7.5v17.986 C126.786,169.86,130.144,173.218,134.286,173.218z" fill="#1abb9b"/>
|
||||
<path d="M126.786,277.303c0,31.025,16.878,59.725,44.048,74.901c1.158,0.647,2.412,0.954,3.65,0.954 c2.629,0,5.182-1.385,6.555-3.844c2.02-3.616,0.726-8.185-2.891-10.205c-22.429-12.528-36.362-36.21-36.362-61.805v-81.584 c0-4.142-3.358-7.5-7.5-7.5s-7.5,3.358-7.5,7.5V277.303z" fill="#1abb9b"/>
|
||||
<path d="M298.249,277.303v-13.584c0-4.142-3.357-7.5-7.5-7.5s-7.5,3.358-7.5,7.5v13.584c0,39.001-31.73,70.732-70.731,70.732 c-5.698,0-11.369-0.682-16.853-2.028c-4.025-0.987-8.084,1.474-9.071,5.497s1.474,8.084,5.497,9.071 c6.653,1.632,13.526,2.46,20.427,2.46C259.79,363.034,298.249,324.575,298.249,277.303z" fill="#1abb9b"/>
|
||||
<path d="M267.249,148.524c0-30.05-24.079-54.953-53.677-55.514c-14.822-0.28-28.786,5.283-39.369,15.668 c-10.587,10.388-16.417,24.258-16.417,39.054v129.571c0,4.142,3.358,7.5,7.5,7.5s7.5-3.358,7.5-7.5V147.732 c0-10.736,4.234-20.803,11.923-28.347c7.685-7.541,17.873-11.576,28.578-11.377c21.483,0.407,38.962,18.583,38.962,40.517v71.194 c0,4.142,3.357,7.5,7.5,7.5s7.5-3.358,7.5-7.5V148.524z" fill="#1abb9b"/>
|
||||
<path d="M188.786,285.987c0,21.632,17.599,39.232,39.231,39.232c21.632,0,39.231-17.599,39.231-39.232v-36.269 c0-4.142-3.357-7.5-7.5-7.5s-7.5,3.358-7.5,7.5v36.269c0,13.361-10.87,24.232-24.231,24.232s-24.231-10.87-24.231-24.232v-64.268 c0-4.142-3.358-7.5-7.5-7.5s-7.5,3.358-7.5,7.5V285.987z" fill="#1abb9b"/>
|
||||
<path d="M228.749,290.603c4.143,0,7.5-3.358,7.5-7.5v-134.9c0-12.932-9.902-23.55-22.545-24.174 c-6.567-0.323-12.787,1.991-17.541,6.516c-4.688,4.463-7.377,10.727-7.377,17.187v41.987c0,4.142,3.358,7.5,7.5,7.5 s7.5-3.358,7.5-7.5v-41.987c0-2.407,0.966-4.653,2.72-6.322c1.75-1.666,4.034-2.518,6.46-2.399 c4.567,0.225,8.283,4.349,8.283,9.192v134.9C221.249,287.245,224.606,290.603,228.749,290.603z" fill="#1abb9b"/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
28
www/img/icon-inteltee-white.svg
Normal file
28
www/img/icon-inteltee-white.svg
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0"
|
||||
id="svg2328" inkscape:output_extension="org.inkscape.output.svg.inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:cc="http://web.resource.org/cc/" sodipodi:version="0.32" sodipodi:docbase="C:\Documents and Settings\Alex Broersma.D2KY7761\Desktop" xmlns:dc="http://purl.org/dc/elements/1.1/" inkscape:version="0.45.1" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" sodipodi:docname="aa.svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="293px" height="194px"
|
||||
viewBox="0 0 293 194" enable-background="new 0 0 293 194" xml:space="preserve">
|
||||
<sodipodi:namedview id="base" inkscape:current-layer="svg2328" inkscape:window-y="-4" inkscape:window-x="-4" inkscape:cy="131.76504" inkscape:cx="219.80302" inkscape:zoom="4.0618557" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" objecttolerance="10.0" gridtolerance="10.0" guidetolerance="10.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:window-width="1440" inkscape:window-height="844">
|
||||
</sodipodi:namedview>
|
||||
<path id="path6" fill="#FFFFFF" d="M291.287,55.059c-13.78-67.174-143.762-71.429-227.549-20.25v5.652
|
||||
C147.415-2.731,266.148-2.456,276.953,59.422c3.641,20.499-7.826,41.818-28.387,54.086v16.053
|
||||
C273.316,120.48,298.616,91.088,291.287,55.059 M138.926,172.67c-57.824,5.353-118.073-3.071-126.508-48.434
|
||||
C8.229,101.9,18.427,78.193,31.878,63.484v-7.875C7.624,76.957-5.551,103.961,2.056,135.844
|
||||
c9.701,40.916,61.407,64.076,140.344,56.364c31.255-3.018,72.157-13.116,100.543-28.782v-22.258
|
||||
C217.146,156.617,174.479,169.381,138.926,172.67z"/>
|
||||
<path id="path8" fill="#FFFFFF" d="M238.312,45.348h-15.158v67.812c0,7.965,3.804,14.891,15.158,15.989"/>
|
||||
<path id="path10" fill="#FFFFFF" d="M57.73,70.13H42.571v44.292c0,7.967,3.804,14.893,15.159,15.99"/>
|
||||
<rect id="rect12" x="42.571" y="47.408" fill="#FFFFFF" width="15.159" height="14.426"/>
|
||||
<path id="path14" fill="#FFFFFF" d="M148.571,129.699c-12.291,0-17.473-8.574-17.473-17.036V53.838h14.993V70.13h11.354V82.33
|
||||
h-11.354v29.426c0,3.461,1.654,5.359,5.235,5.359h6.119v12.584H148.571"/>
|
||||
<path id="path16" fill="#FFFFFF" d="M188.426,81.589c-5.125,0-9.094,2.665-10.748,6.264c-0.992,2.17-1.323,3.819-1.486,6.486h23.206
|
||||
C199.066,87.826,196.143,81.589,188.426,81.589 M176.191,104.613c0,7.722,4.848,13.406,13.337,13.406
|
||||
c6.671,0,9.979-1.868,13.837-5.684l9.262,8.929c-5.954,5.878-12.183,9.45-23.207,9.45c-14.387,0-28.168-7.885-28.168-30.855
|
||||
c0-19.645,12.016-30.744,27.837-30.744c16.04,0,25.245,12.996,25.245,30.059v5.44L176.191,104.613"/>
|
||||
<path id="path18" fill="#FFFFFF" d="M98.576,82.33c4.409,0,6.229,2.171,6.229,5.715v41.735h15.049V87.99
|
||||
c0-8.49-4.521-17.86-17.694-17.86H71.125v59.65h14.993V82.329"/>
|
||||
<text transform="matrix(1.0217 0 0 1 246.8975 55.2607)" fill="#127CC1" font-family="'ArialMT'" font-size="13.8854">®</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
BIN
www/img/icon-warning.png
Normal file
BIN
www/img/icon-warning.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1 KiB |
|
|
@ -13,7 +13,7 @@
|
|||
<div class="comment" translate>
|
||||
If enabled, wallets will also try to spend unconfirmed funds. This option may cause transaction delays.
|
||||
</div>
|
||||
|
||||
|
||||
<div class="item item-divider"></div>
|
||||
|
||||
<ion-toggle class="has-comment" ng-show="!isWP" ng-model="recentTransactionsEnabled.value" toggle-class="toggle-balanced" ng-change="recentTransactionsChange()">
|
||||
|
|
|
|||
|
|
@ -14,16 +14,16 @@
|
|||
<img src="img/a-smile_color_btn.png" alt="{{id}}" width="40">
|
||||
<ion-spinner class="spinner-dark recent right m10 size-16" icon="crescent" ng-show="updatingPending[item.invoiceId]">
|
||||
</ion-spinner>
|
||||
<h2>
|
||||
<span ng-if="item.claimCode">{{item.amount | currency : '$ ' : 2}} {{item.currency}}</span>
|
||||
<span ng-if="!item.claimCode">-</span>
|
||||
<h2 ng-if="item.amount">
|
||||
{{item.amount | currency : '$ ' : 2}} {{item.currency}}
|
||||
</h2>
|
||||
<p>
|
||||
<span class="assertive" ng-if="item.status == 'FAILURE' || item.status == 'RESEND'">Error</span>
|
||||
<span class="assertive" ng-if="item.status == 'expired'">Expired</span>
|
||||
<span class="assertive" ng-if="item.status == 'invalid'">Still waiting confirmation<br> (Use higher fees setting to faster delivery)</span>
|
||||
<span class="text-gray" ng-if="item.status == 'PENDING'">Pending to confirmation</span>
|
||||
<span class="assertive" ng-if="item.status == 'SUCCESS' && item.cardStatus == 'Canceled'">Canceled</span>
|
||||
<span class="text-gray" ng-if="item.status == 'SUCCESS' && item.cardStatus == 'Fulfilled'">{{item.date | amTimeAgo}}</span>
|
||||
<span class="text-gray">{{item.date | amTimeAgo}}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@
|
|||
|
||||
<div class="col col-50">
|
||||
<div class="size-12 text-bold">
|
||||
{{tx.merchant.name}}
|
||||
{{tx.merchant.name || 'Unknown Merchant'}}
|
||||
</div>
|
||||
<div class="size-12 text-gray">
|
||||
<span ng-show="tx.merchant.city && tx.merchant.state">{{tx.merchant.city}}, {{tx.merchant.state}}</span>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
<span translate>File/Text</span>
|
||||
</div>
|
||||
<div class="col" ng-click="hardware = true; phrase = file = false" ng-style="hardware &&
|
||||
{'border-bottom-style': 'solid'}" ng-show="isCopay && (isChromeApp || isDevel)">
|
||||
{'border-bottom-style': 'solid'}" ng-show="isCopay && (supportsLedger || supportsTrezor)">
|
||||
<span translate>Hardware wallet</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@
|
|||
<img style="height:0.6em; margin-right: 1px;" ng-show="wallet.network != 'livenet'" src="img/icon-testnet-white.svg">
|
||||
<img style="height:0.6em; margin-right: 1px;" ng-show="!wallet.canSign() && !wallet.isPrivKeyExternal()" src="img/icon-read-only-white.svg">
|
||||
|
||||
<img style="height:0.6em; margin-right: 1px;" ng-show="wallet.getPrivKeyExternalSourceName() == 'trezor'" src="img/icon-trezor-white.svg">
|
||||
<img style="height:0.6em; margin-right: 1px;" ng-show="wallet.getPrivKeyExternalSourceName() == 'ledger'" src="img/icon-ledger-white.svg">
|
||||
<img style="height:0.6em; margin-right: 1px;" ng-show="wallet.getPrivKeyExternalSourceName() == 'trezor'" src="img/icon-trezor-white.svg">
|
||||
<img style="height:0.6em; margin-right: 1px;" ng-show="wallet.getPrivKeyExternalSourceName() == 'ledger'" src="img/icon-ledger-white.svg">
|
||||
<img style="height:0.6em; margin-right: 1px;" ng-show="wallet.getPrivKeyExternalSourceName() == 'intelTEE'" src="img/icon-inteltee-white.svg">
|
||||
<span ng-show="wallet.credentials.n > 1" class="size-12"><span translate>{{wallet.m}}-of-{{wallet.n}}</span></span>
|
||||
<span class="size-12 dib" style="height:0.6em; margin-right: 1px;" ng-show="wallet.credentials.account">#{{wallet.credentials.account || 0}} </span>
|
||||
|
||||
|
|
|
|||
17
www/views/lockSetup.html
Normal file
17
www/views/lockSetup.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<ion-view class="settings">
|
||||
<ion-nav-bar class="bar-royal">
|
||||
<ion-nav-title>{{'Startup Lock' | translate}}</ion-nav-title>
|
||||
<ion-nav-back-button>
|
||||
</ion-nav-back-button>
|
||||
</ion-nav-bar>
|
||||
|
||||
<ion-content>
|
||||
<ion-radio ng-repeat="opt in options" ng-value="opt" ng-model="currentOption" ng-click="select(opt.method)" ng-disabled="opt.needsBackup">
|
||||
<span ng-class="{'disabled': opt.needsBackup}">{{opt.label}}</span>
|
||||
</ion-radio>
|
||||
|
||||
<div class="assertive" style="text-align: center; margin: 4rem" ng-if="errorMsg">
|
||||
{{errorMsg}}
|
||||
</div>
|
||||
</ion-content>
|
||||
</ion-view>
|
||||
21
www/views/lockedView.html
Normal file
21
www/views/lockedView.html
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<ion-view id="locked-view">
|
||||
<ion-nav-bar class="bar-royal">
|
||||
<ion-nav-title>{{title}}</ion-nav-title>
|
||||
</ion-nav-bar>
|
||||
|
||||
<ion-content>
|
||||
<div ng-if="appName == 'copay'" class="img-container-copay">
|
||||
<i class="icon big-icon-svg"><div class="bg"></div></i>
|
||||
</div>
|
||||
<div ng-if="appName == 'bitpay'" class="img-container-bitpay">
|
||||
<i class="icon big-icon-svg"><div class="bg"></div></i>
|
||||
</div>
|
||||
<div class="comments">
|
||||
<div class="header" translate>One-touch Sign In</div>
|
||||
<div class="text-content" translate>Please place your fingertip on the scanner to verify your identity</div>
|
||||
</div>
|
||||
<button type="submit" style="margin-top: 15%"
|
||||
class="button button-standard button-primary" ng-click="requestFingerprint()" translate>Scan again
|
||||
</button>
|
||||
</ion-content>
|
||||
</ion-view>
|
||||
|
|
@ -11,13 +11,21 @@
|
|||
<div class="header-modal text-center">
|
||||
<img src="img/a_generic.jpg" alt="Amazon.com Gift Card" width="230" ng-click="refreshGiftCard()">
|
||||
|
||||
<div class="m10t">
|
||||
Gift Card Amount:
|
||||
<span class="text-bold">
|
||||
{{card.amount | currency : '$ ' : 2}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="m10t">
|
||||
Created
|
||||
{{card.date | amTimeAgo}}
|
||||
</div>
|
||||
|
||||
|
||||
<div ng-show="card.claimCode">
|
||||
<div class="m10t">
|
||||
Gift Card Amount:
|
||||
<span class="text-bold">
|
||||
{{card.amount | currency : '$ ' : 2}}
|
||||
</span>
|
||||
</div>
|
||||
<div ng-show="card.cardStatus !== 'Canceled'">
|
||||
Claim code: <span class="text-bold" copy-to-clipboard="card.claimCode">{{card.claimCode}}</span>
|
||||
</div>
|
||||
|
|
@ -42,6 +50,10 @@
|
|||
<span class="text-bold" ng-show="card.status == 'PENDING'">
|
||||
PENDING
|
||||
</span>
|
||||
<span class="text-bold" ng-show="card.status=='invalid'">
|
||||
STILL PENDING
|
||||
</span>
|
||||
|
||||
<span class="text-bold" ng-show="card.status == 'FAILURE' || card.status == 'RESEND'">
|
||||
FAILURE
|
||||
</span>
|
||||
|
|
|
|||
73
www/views/pin.html
Normal file
73
www/views/pin.html
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<ion-view id="pin" hide-tabs hide-back-button="!fromSettings">
|
||||
<ion-nav-bar class="bar-clear">
|
||||
<ion-nav-back-button>
|
||||
</ion-nav-back-button>
|
||||
</ion-nav-bar>
|
||||
<div class="content">
|
||||
<div class="block-text row">
|
||||
<div class="message" ng-if="!confirmPin && !error" translate>Please enter your PIN</div>
|
||||
<div class="message" ng-if="confirmPin && !error" translate>Confirm your PIN</div>
|
||||
<div class="message error" ng-if="error">
|
||||
<div ng-if="!expires" translate>Incorrect PIN, try again.</div>
|
||||
<time ng-if="expires" translate>Try again in {{expires}}</time>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-icon">
|
||||
<i class="icon big-icon-svg">
|
||||
<div class="bg"></div>
|
||||
</i>
|
||||
</div>
|
||||
<div class="block-code">
|
||||
<div class="row">
|
||||
<div class="col circle-{{appName}}" ng-class="getFilledClass(1)"></div>
|
||||
<div class="col circle-{{appName}}" ng-class="getFilledClass(2)"></div>
|
||||
<div class="col circle-{{appName}}" ng-class="getFilledClass(3)"></div>
|
||||
<div class="col circle-{{appName}}" ng-class="getFilledClass(4)"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="block-buttons">
|
||||
<div class="row">
|
||||
<div class="col" ng-click="updatePin('1')">
|
||||
<div class="keyboard">1</div>
|
||||
</div>
|
||||
<div class="col" ng-click="updatePin('2')">
|
||||
<div class="keyboard">2</div>
|
||||
</div>
|
||||
<div class="col" ng-click="updatePin('3')">
|
||||
<div class="keyboard">3</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col" ng-click="updatePin('4')">
|
||||
<div class="keyboard">4</div>
|
||||
</div>
|
||||
<div class="col" ng-click="updatePin('5')">
|
||||
<div class="keyboard">5</div>
|
||||
</div>
|
||||
<div class="col" ng-click="updatePin('6')">
|
||||
<div class="keyboard">6</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col" ng-click="updatePin('7')">
|
||||
<div class="keyboard">7</div>
|
||||
</div>
|
||||
<div class="col" ng-click="updatePin('8')">
|
||||
<div class="keyboard">8</div>
|
||||
</div>
|
||||
<div class="col" ng-click="updatePin('9')">
|
||||
<div class="keyboard">9</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col"></div>
|
||||
<div class="col" ng-click="updatePin('0')">
|
||||
<div class="">0</div>
|
||||
</div>
|
||||
<div class="col" ng-click="delete()">
|
||||
<div class="keyboard icon ion-arrow-left-a"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ion-view>
|
||||
|
|
@ -18,12 +18,6 @@
|
|||
</span>
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
</a>
|
||||
<a class="item" ng-show="wallet.isPrivKeyExternal()">
|
||||
<span translate>Hardware Wallet</span>
|
||||
<span class="item-note">
|
||||
{{externalSource}}
|
||||
</span>
|
||||
</a>
|
||||
<a class="item item-icon-right" ui-sref="tabs.preferences.preferencesColor">
|
||||
<span translate>Color</span>
|
||||
<span class="item-note">
|
||||
|
|
@ -38,7 +32,7 @@
|
|||
<span class="toggle-label" translate>Hide Balance</span>
|
||||
</ion-toggle>
|
||||
|
||||
<div class="item item-divider" translate>
|
||||
<div class="item item-divider" ng-hide="wallet.isPrivKeyExternal() || !wallet.canSign()" translate>
|
||||
Security
|
||||
</div>
|
||||
<a class="item item-icon-right" ui-sref="tabs.preferences.backupWarning({from: 'tabs.preferences'})" ng-hide="wallet.isPrivKeyExternal()">
|
||||
|
|
|
|||
41
www/views/preferencesExternal.html
Normal file
41
www/views/preferencesExternal.html
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<ion-view class="settings">
|
||||
<ion-nav-bar class="bar-royal">
|
||||
<ion-nav-title>{{externalSource.longName}}</ion-nav-title>
|
||||
<ion-nav-back-button>
|
||||
</ion-nav-back-button>
|
||||
</ion-nav-bar>
|
||||
<ion-content>
|
||||
<div ng-include="'views/includes/walletItem.html'"></div>
|
||||
|
||||
<div ng-if="!externalSource.isEmbeddedHardware">
|
||||
<div ng-if="!hardwareConnected" class="info centered">
|
||||
<span translate>No hardware information available.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="externalSource.isEmbeddedHardware">
|
||||
<div ng-if="!hardwareConnected" class="warning centered">
|
||||
<span translate>Hardware not connected.</span><br>
|
||||
<span translate>Check installation and retry.</span>
|
||||
</div>
|
||||
|
||||
<div ng-if="hardwareConnected">
|
||||
<div class="list">
|
||||
<div class="item">
|
||||
<span translate>Version</span>
|
||||
<span class="item-note">
|
||||
{{externalSource.version || 'hardware disconnected'}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="padding">
|
||||
<button class="button button-standard button-assertive" ng-click="showMneumonicFromHardwarePopup()">
|
||||
{{'Show Recovery Phrase'|translate}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ion-content>
|
||||
</ion-view>
|
||||
|
|
@ -43,12 +43,19 @@
|
|||
{{derivationStrategy}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="item" ng-show="wallet.isPrivKeyExternal()">
|
||||
<div class="item" ng-show="wallet.isPrivKeyExternal() && !externalSource.isEmbeddedHardware">
|
||||
<span translate>Hardware Wallet</span>
|
||||
<span class="item-note">
|
||||
{{wallet.getPrivKeyExternalSourceName()}}
|
||||
{{externalSource}}
|
||||
</span>
|
||||
</div>
|
||||
<a class="item item-icon-right" href ui-sref="tabs.preferences.preferencesExternal" ng-show="wallet.isPrivKeyExternal() && externalSource.isEmbeddedHardware">
|
||||
<span translate>Hardware Wallet</span>
|
||||
<span class="item-note">
|
||||
{{externalSource}}
|
||||
</span>
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
</a>
|
||||
<div class="item" ng-show="!wallet.isPrivKeyExternal() && !wallet.canSign()">
|
||||
<span translate></span>
|
||||
<span class="item-note">
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@
|
|||
ng-model="formData.derivationPath">
|
||||
</label>
|
||||
|
||||
<ion-toggle ng-show="seedSource.id == 'new'" ng-model="formData.testnetEnabled" toggle-class="toggle-positive">
|
||||
<ion-toggle ng-show="seedSource.supportsTestnet" ng-model="formData.testnetEnabled" toggle-class="toggle-positive">
|
||||
<span translate>Testnet</span>
|
||||
</ion-toggle>
|
||||
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@
|
|||
ng-model="formData.derivationPath">
|
||||
</label>
|
||||
|
||||
<ion-toggle ng-show="seedSource.id == 'new'" ng-model="formData.testnetEnabled" toggle-class="toggle-positive">
|
||||
<ion-toggle ng-show="seedSource.supportsTestnet" ng-model="formData.testnetEnabled" toggle-class="toggle-positive">
|
||||
Testnet
|
||||
</ion-toggle>
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@
|
|||
</span>
|
||||
<span ng-if="wallet.isComplete()">
|
||||
<span ng-if="!wallet.balanceHidden"> {{wallet.status.totalBalanceStr ? wallet.status.totalBalanceStr : ( wallet.cachedBalance ? wallet.cachedBalance + (wallet.cachedBalanceUpdatedOn ? ' · ' + ( wallet.cachedBalanceUpdatedOn * 1000 | amTimeAgo) : '') : '' ) }} </span>
|
||||
|
||||
|
||||
<span ng-if="wallet.balanceHidden" translate>[Balance Hidden]</span>
|
||||
<span class="tab-home__wallet__multisig-number" ng-if="wallet.n > 1">
|
||||
{{wallet.m}}-of-{{wallet.n}}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
<select ng-model="formData.seedSource" ng-options="seed as seed.label for seed in seedOptions"></select>
|
||||
</label>
|
||||
|
||||
<label class="item item-input item-stacked-label" ng-show="formData.seedSource.id == 'trezor' || formData.seedSource.id == 'ledger'">
|
||||
<label class="item item-input item-stacked-label" ng-show="formData.seedSource.id == 'trezor' || formData.seedSource.id == 'ledger' || formData.seedSource.id == 'intelTee'">
|
||||
<span class="input-label" translate>Account Number</span>
|
||||
<input type="number" ng-model="formData.account" ignore-mouse-wheel>
|
||||
</label>
|
||||
|
|
|
|||
|
|
@ -53,6 +53,11 @@
|
|||
</div>
|
||||
<div class="row qr">
|
||||
<div class="text-center col center-block" copy-to-clipboard="addr" ng-repeat="wallet in wallets track by $index" ng-class="walletPosition($index)">
|
||||
<span class="overlay" ng-show="shouldShowReceiveAddressFromHardware()">
|
||||
<button class="button button-standard button-primary" ng-click="showReceiveAddressFromHardware()">
|
||||
<span translate>Show address</span>
|
||||
</button>
|
||||
</span>
|
||||
<qrcode ng-if="walletAddrs[wallet.id]" size="220" data="bitcoin:{{walletAddrs[wallet.id]}}" color="#334"></qrcode>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
<i class="icon big-icon-svg">
|
||||
<img src="img/icon-heart.svg" class="bg"/>
|
||||
</i>
|
||||
<span>{{'Share'|translate}} {{appName}}</span>
|
||||
<span translate>Share {{appName}}</span>
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
</a>
|
||||
|
||||
|
|
@ -89,6 +89,16 @@
|
|||
<i class="icon bp-arrow-right"></i>
|
||||
</a>
|
||||
|
||||
<a class="item has-setting-value item-icon-left item-icon-right" ui-sref="tabs.lockSetup" ng-if="isCordova || isDevel">
|
||||
<i class="icon ion-ios-locked-outline" ng-if="locked"></i>
|
||||
<i class="icon ion-ios-unlocked-outline" ng-if="!locked"></i>
|
||||
<span class="setting-title">{{'Lock App' | translate}}</span>
|
||||
<span class="setting-value">
|
||||
{{method}}
|
||||
</span>
|
||||
<i class="icon bp-arrow-right"></i>
|
||||
</a>
|
||||
|
||||
<div class="item item-divider" ng-show="wallets[0]">{{'Wallets & Integrations' | translate}}</div>
|
||||
|
||||
<a class="item item-icon-left item-icon-right" href
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@
|
|||
</div>
|
||||
<div class="amount-label">
|
||||
<div class="amount-final">{{amountUnitStr}}</div>
|
||||
<div class="alternative" ng-show="isFiat && rate">
|
||||
@ {{rate | currency:'$':2}} per BTC
|
||||
<div class="alternative">
|
||||
<span ng-if="rate">@ {{rate | currency:'$':2}} per BTC</span>
|
||||
<span ng-if="!rate">...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -84,6 +84,10 @@
|
|||
<span ng-if="toggleFeeFiat">{{feeFiatStr}}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="item low-fees" ng-if="btx.action == 'received' && btx.lowFees">
|
||||
<i class="icon"><img src="img/icon-warning.png" width="20px"></i>
|
||||
<span translate>This transaction could take a long time to confirm or could be dropped due to the low fees set by the sender</span>
|
||||
</div>
|
||||
<div class="item single-line">
|
||||
<span class="label" translate>Confirmations</span>
|
||||
<span class="item-note">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<ion-view id="walletDetails">
|
||||
<ion-view id="walletDetails" hide-tabs>
|
||||
|
||||
<ion-nav-bar ng-class="{'wallet-background-color-default': !wallet.color}" ng-style="{'background-color': wallet.color}">
|
||||
<ion-nav-title>{{wallet.name}}</ion-nav-title>
|
||||
|
|
@ -103,7 +103,7 @@
|
|||
<div
|
||||
ng-style="{'background-color':wallet.color}"
|
||||
class="amount"
|
||||
ng-class="{'collapsible': amountIsCollapsible, 'wallet-background-color-default': !wallet.color}"
|
||||
ng-class="{'collapsible': amountIsCollapsible, 'wallet-background-color-default': !wallet.color}"
|
||||
>
|
||||
<div ng-if="!updatingStatus">
|
||||
|
||||
|
|
@ -238,6 +238,10 @@
|
|||
<div ng-show="btx.action == 'received'" class="ellipsis">
|
||||
<div ng-if="btx.note.body" class="wallet-details__tx-message ellipsis">{{btx.note.body}}</div>
|
||||
<div ng-if="!btx.note.body" class="wallet-details__tx-message ellipsis" translate>Received</div>
|
||||
<div class="low-fees" ng-if="btx.lowFees">
|
||||
<i class="icon"><img src="img/icon-warning.png" width="20px"></i>
|
||||
<span class="comment" translate>Low fees</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-show="btx.action == 'sent'" class="ellipsis">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue