diff --git a/.gitignore b/.gitignore
index 16ebb09f3..18d9fa5ea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,7 +50,7 @@ build/Release
node_modules
bower_components
angular-bitcore-wallet-client/angular-bitcore-wallet-client.js
-angular-pbkdf2/angular-pbkdf2.js
+angular-bitauth/angular-bitauth.js
# Users Environment Variables
.lock-wscript
diff --git a/Gruntfile.js b/Gruntfile.js
index bd234152c..cd74aed4b 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -128,7 +128,7 @@ module.exports = function(grunt) {
'bower_components/angular-md5/angular-md5.js',
'bower_components/angular-mocks/angular-mocks.js',
'bower_components/ngtouch/src/ngTouch.js',
- 'angular-pbkdf2/angular-pbkdf2.js',
+ 'angular-bitauth/angular-bitauth.js',
'angular-bitcore-wallet-client/angular-bitcore-wallet-client.js'
],
dest: 'www/lib/angular.js'
@@ -251,7 +251,7 @@ module.exports = function(grunt) {
dist: {
files: {
'angular-bitcore-wallet-client/angular-bitcore-wallet-client.js': ['angular-bitcore-wallet-client/index.js'],
- 'angular-pbkdf2/angular-pbkdf2.js': ['angular-pbkdf2/index.js']
+ 'angular-bitauth/angular-bitauth.js': ['angular-bitauth/index.js']
},
}
}
diff --git a/angular-bitauth/index.js b/angular-bitauth/index.js
new file mode 100644
index 000000000..cb6ebaa2e
--- /dev/null
+++ b/angular-bitauth/index.js
@@ -0,0 +1,18 @@
+var bitauthModule = angular.module('bitauthModule', []);
+var bitauth = require('../node_modules/bitauth');
+
+bitauthModule.constant('MODULE_VERSION', '1.0.0');
+
+bitauthModule.provider("bitauthService", function() {
+ var provider = {};
+
+ provider.$get = function() {
+ var service = {};
+
+ service = bitauth;
+
+ return service;
+ };
+
+ return provider;
+});
diff --git a/angular-pbkdf2/index.js b/angular-pbkdf2/index.js
deleted file mode 100644
index 4e1e0d9b9..000000000
--- a/angular-pbkdf2/index.js
+++ /dev/null
@@ -1,18 +0,0 @@
-var pbkdf2Module = angular.module('pbkdf2Module', []);
-var pbkdf2Sync = require('../node_modules/pbkdf2').pbkdf2Sync;
-
-pbkdf2Module.constant('MODULE_VERSION', '1.0.0');
-
-pbkdf2Module.provider("pbkdf2Service", function() {
- var provider = {};
-
- provider.$get = function() {
- var service = {};
-
- service.pbkdf2Sync = pbkdf2Sync;
-
- return service;
- };
-
- return provider;
-});
diff --git a/app-template/apply.js b/app-template/apply.js
index 14fdaab57..7ecad93d8 100755
--- a/app-template/apply.js
+++ b/app-template/apply.js
@@ -5,6 +5,7 @@
//
var templates = {
+ 'package.json': '/',
'Makefile': 'cordova/',
'ProjectMakefile': 'cordova/',
'config-template.xml': '/',
diff --git a/app-template/bitpay/appConfig.json b/app-template/bitpay/appConfig.json
index 79eb58f52..54faf2203 100644
--- a/app-template/bitpay/appConfig.json
+++ b/app-template/bitpay/appConfig.json
@@ -5,12 +5,13 @@
"purposeLine": "Secure Bitcoin Wallet",
"bundleName": "wallet",
"appUri": "bitpay",
-
"name": "bitpay",
"nameNoSpace": "bitpay",
"nameCase": "BitPay",
"nameCaseNoSpace": "BitPay",
"gitHubRepoName": "bitpay-wallet",
+ "gitHubRepoUrl": "git://github.com/bitpay/bitpay-wallet.git",
+ "gitHubRepoBugs": "https://github.com/bitpay/bitpay-wallet/issues",
"disclaimerUrl": "",
"url": "https://bitpay.com",
"appDescription": "Secure Bitcoin Wallet",
diff --git a/app-template/bitpay/img/favicon.ico b/app-template/bitpay/img/favicon.ico
new file mode 100644
index 000000000..166c0bcaf
Binary files /dev/null and b/app-template/bitpay/img/favicon.ico differ
diff --git a/app-template/bitpay/img/icon-128.png b/app-template/bitpay/img/icon-128.png
new file mode 100644
index 000000000..6958667cd
Binary files /dev/null and b/app-template/bitpay/img/icon-128.png differ
diff --git a/app-template/config-template.xml b/app-template/config-template.xml
index 1db63c59a..faa71f449 100644
--- a/app-template/config-template.xml
+++ b/app-template/config-template.xml
@@ -56,8 +56,9 @@
-
-
+
+
+
diff --git a/app-template/copay/appConfig.json b/app-template/copay/appConfig.json
index 7a6ee7ef3..6e66bd2bf 100644
--- a/app-template/copay/appConfig.json
+++ b/app-template/copay/appConfig.json
@@ -3,14 +3,15 @@
"packageDescription": "Copay Bitcoin Wallet",
"userVisibleName": "Copay",
"purposeLine": "Copay Bitcoin Wallet",
+ "bundleName": "copay",
"appUri": "copay",
-
"name": "copay",
"nameNoSpace": "copay",
"nameCase": "Copay",
"nameCaseNoSpace": "Copay",
- "bundleName": "copay",
"gitHubRepoName": "copay",
+ "gitHubRepoUrl": "git://github.com/bitpay/copay.git",
+ "gitHubRepoBugs": "https://github.com/bitpay/copay/issues",
"disclaimerUrl": "https://copay.io/disclaimer",
"url": "https://copay.io",
"appDescription": "Copay Bitcoin Wallet",
diff --git a/app-template/copay/img/favicon.ico b/app-template/copay/img/favicon.ico
new file mode 100644
index 000000000..e2f92139d
Binary files /dev/null and b/app-template/copay/img/favicon.ico differ
diff --git a/app-template/copay/img/icon-128.png b/app-template/copay/img/icon-128.png
new file mode 100644
index 000000000..8624a0189
Binary files /dev/null and b/app-template/copay/img/icon-128.png differ
diff --git a/app-template/package.json b/app-template/package.json
index d62d1ff5d..6f535b9d5 100644
--- a/app-template/package.json
+++ b/app-template/package.json
@@ -14,14 +14,14 @@
"main": "www/index.html",
"window": {
"title": "*USERVISIBLENAME* - *PURPOSELINE*",
- "icon": "./www/img/icons/icon-256.png",
+ "icon": "www/img/icon-128.png",
"toolbar": false,
"show": true,
"visible": true,
"resizable": true,
"frame": true,
"width": 400,
- "height": 600,
+ "height": 650,
"position": "center",
"fullscreen": false
},
@@ -32,25 +32,27 @@
},
"dom_storage_quota": 200,
"id": "jid1-x7bV5evAaI1P9Q",
- "homepage": "https://github.com/bitpay/copay",
+ "homepage": "*URL*",
"license": "MIT",
"repository": {
- "url": "git://github.com/bitpay/copay.git",
+ "url": "*GITHUBREPOURL*",
"type": "git"
},
"bugs": {
- "url": "https://github.com/bitpay/copay/issues"
+ "url": "*GITHUBREPOBUGS*"
},
"dependencies": {
"adm-zip": "^0.4.7",
"angular": "1.4.6",
"angular-mocks": "1.4.10",
+ "bezier-easing": "^2.0.3",
"bhttp": "^1.2.1",
- "bitcore-wallet-client": "4.2.1",
+ "bitauth": "^0.3.2",
+ "bitcore-wallet-client": "4.3.1",
"bower": "^1.7.9",
"chai": "^3.5.0",
- "cordova": "5.4.1",
"cordova-android": "5.1.1",
+ "cordova-custom-config": "^3.0.5",
"cordova-plugin-qrscanner": "^2.3.1",
"coveralls": "^2.11.9",
"express": "^4.11.2",
@@ -80,24 +82,40 @@
"karma-sinon": "^1.0.5",
"load-grunt-tasks": "^3.5.0",
"mocha": "^2.4.5",
- "pbkdf2": "^3.0.4",
"phantomjs-prebuilt": "^2.1.7",
- "shelljs": "^0.3.0",
- "xcode": "^0.8.2"
+ "shelljs": "^0.3.0"
},
"scripts": {
- "preinstall": "bower install && npm i fs-extra",
- "build": "grunt",
- "apply:copay": "cd app-template && node apply.js",
- "apply:bitpay-wallet": "cd app-template && node apply.js bitpay-wallet",
- "start": "npm run build && node app.js",
- "watch": "grunt watch",
- "test": "./node_modules/.bin/grunt test-coveralls",
- "clean": "git clean -dfx",
- "start:ios": "npm run build && cd cordova && trash project-ios && make ios && open project-ios/platforms/ios/BitPay\\ Wallet.xcodeproj",
- "start:android": "npm run build && cd cordova && trash project-android && make android && open -a /Applications/Android\\ Studio.app project-android/platforms/android"
+ "preinstall": "bower install && npm i fs-extra",
+ "postinstall": "npm run apply:bitpay && cordova prepare",
+ "start": "npm run build:www && ionic serve --nolivereload --nogulp -s",
+ "start:ios": "npm run build:www && npm run build:ios && npm run open:ios",
+ "start:android": "npm run build:www && npm run build:android && npm run run:android",
+ "watch": "grunt watch",
+ "build:www": "grunt",
+ "build:www-release": "grunt prod",
+ "build:ios": "cordova prepare ios && cordova build ios --debug",
+ "build:android": "cordova prepare android && cordova build android --debug",
+ "build:ios-release": "cordova prepare ios && cordova build ios --release",
+ "build:android-release": "cordova prepare android && cordova build android --release",
+ "open:ios": "open platforms/ios/*.xcodeproj",
+ "open:android": "open -a open -a /Applications/Android\\ Studio.app platforms/android",
+ "final:www": "npm run clean-all && 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 run:android",
+ "run:android": "cordova run android --device",
+ "log:android": "adb logcat | grep chromium",
+ "apply:copay": "cd app-template && node apply.js copay",
+ "apply:bitpay": "cd app-template && node apply.js bitpay",
+ "test": "./node_modules/.bin/grunt test-coveralls",
+ "clean": "trash platforms && trash plugins && npm run postinstall",
+ "clean-all": "git clean -dfx && npm install"
},
"devDependencies": {
- "trash-cli": "^1.4.0"
+ "cordova": "^6.3.1",
+ "grunt": "^1.0.1",
+ "ionic": "^2.1.0",
+ "trash-cli": "^1.4.0",
+ "lodash": "^4.3.0"
}
}
diff --git a/app-template/setup-win.iss b/app-template/setup-win.iss
index d9f6eaa30..d2443afef 100755
--- a/app-template/setup-win.iss
+++ b/app-template/setup-win.iss
@@ -8,7 +8,7 @@
#define MyAppExeName "*PACKAGENAME.exe"
[Setup]
-AppId={{804636ee-b017-4cad-8719-e58ac97ffa5c}
+AppId={804636ee-b017-4cad-8719-e58ac97ffa5c}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
diff --git a/package.json b/package.json
index c690d4989..fd30b3f2e 100644
--- a/package.json
+++ b/package.json
@@ -1,4 +1,9 @@
-{
+ {
+ "//":"PLEASE! Do not edit this file directly",
+ "//":" Modify it at app-template/",
+
+ "name": "bitpay",
+ "description": "Secure Bitcoin Wallet",
"author": "BitPay",
"version": "0.14.0",
"keywords": [
@@ -9,14 +14,35 @@
"multisignature",
"bitcore"
],
- "homepage": "https://github.com/bitpay/copay",
+ "main": "www/index.html",
+ "window": {
+ "title": "BitPay - Secure Bitcoin Wallet",
+ "icon": "www/img/icon-128.png",
+ "toolbar": false,
+ "show": true,
+ "visible": true,
+ "resizable": true,
+ "frame": true,
+ "width": 400,
+ "height": 650,
+ "position": "center",
+ "fullscreen": false
+ },
+ "webkit": {
+ "page-cache": false,
+ "java": false,
+ "plugin": false
+ },
+ "dom_storage_quota": 200,
+ "id": "jid1-x7bV5evAaI1P9Q",
+ "homepage": "https://bitpay.com",
"license": "MIT",
"repository": {
- "url": "git://github.com/bitpay/copay.git",
+ "url": "git://github.com/bitpay/bitpay-wallet.git",
"type": "git"
},
"bugs": {
- "url": "https://github.com/bitpay/copay/issues"
+ "url": "https://github.com/bitpay/bitpay-wallet/issues"
},
"dependencies": {
"adm-zip": "^0.4.7",
@@ -24,6 +50,7 @@
"angular-mocks": "1.4.10",
"bezier-easing": "^2.0.3",
"bhttp": "^1.2.1",
+ "bitauth": "^0.3.2",
"bitcore-wallet-client": "4.3.1",
"bower": "^1.7.9",
"chai": "^3.5.0",
@@ -58,7 +85,6 @@
"karma-sinon": "^1.0.5",
"load-grunt-tasks": "^3.5.0",
"mocha": "^2.4.5",
- "pbkdf2": "^3.0.4",
"phantomjs-prebuilt": "^2.1.7",
"shelljs": "^0.3.0"
},
diff --git a/public/views/bitpayCardIntro.html b/public/views/bitpayCardIntro.html
new file mode 100644
index 000000000..7b42f3611
--- /dev/null
+++ b/public/views/bitpayCardIntro.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+ Turn bitcoin into dollars, swipe anywhere Visa® is accepted.
+
+
+
+
+ Get local cash anywhere you go, from any Visa®-compatible ATM.
+
+ *ATM bank fees may apply
+
+
+
+
+
+ Pay 0% fees to turn bitcoin into dollars.
+
+
+
+
+
+
+
+
+
diff --git a/src/js/app.js b/src/js/app.js
index 91466a757..784745fdd 100644
--- a/src/js/app.js
+++ b/src/js/app.js
@@ -12,7 +12,7 @@ var modules = [
'ngCsv',
'angular-md5',
'bwcModule',
- 'pbkdf2Module',
+ 'bitauthModule',
'copayApp.filters',
'copayApp.services',
'copayApp.controllers',
diff --git a/src/js/controllers/amount.js b/src/js/controllers/amount.js
index dd8623cfa..0f18ebcfc 100644
--- a/src/js/controllers/amount.js
+++ b/src/js/controllers/amount.js
@@ -17,13 +17,13 @@ angular.module('copayApp.controllers').controller('amountController', function($
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.isWallet = data.stateParams.isWallet;
- $scope.isCard = data.stateParams.isCard;
+ $scope.cardId = data.stateParams.cardId;
$scope.toAddress = data.stateParams.toAddress;
$scope.toName = data.stateParams.toName;
$scope.toEmail = data.stateParams.toEmail;
- $scope.showAlternativeAmount = !!$scope.isCard;
+ $scope.showAlternativeAmount = !!$scope.cardId;
- if (!$scope.isCard && !$stateParams.toAddress) {
+ if (!$scope.cardId && !$stateParams.toAddress) {
$log.error('Bad params at amount')
throw ('bad params');
}
@@ -189,7 +189,7 @@ angular.module('copayApp.controllers').controller('amountController', function($
$scope.finish = function() {
var _amount = evaluate(format($scope.amount));
- if ($scope.isCard) {
+ if ($scope.cardId) {
var amountUSD = $scope.showAlternativeAmount ? _amount : $filter('formatFiatAmount')(toFiat(_amount));
var dataSrc = {
@@ -199,7 +199,7 @@ angular.module('copayApp.controllers').controller('amountController', function($
ongoingProcess.set('Processing Transaction...', true);
$timeout(function() {
- bitpayCardService.topUp(dataSrc, function(err, invoiceId) {
+ bitpayCardService.topUp($scope.cardId, dataSrc, function(err, invoiceId) {
if (err) {
ongoingProcess.set('Processing Transaction...', false);
popupService.showAlert(gettextCatalog.getString('Error'), bwcError.msg(err));
@@ -215,7 +215,7 @@ angular.module('copayApp.controllers').controller('amountController', function($
var payProUrl = data.paymentUrls.BIP73;
$state.transitionTo('tabs.bitpayCard.confirm', {
- isCard: $scope.isCard,
+ cardId: $scope.cardId,
toName: $scope.toName,
paypro: payProUrl
});
diff --git a/src/js/controllers/bitpayCard.js b/src/js/controllers/bitpayCard.js
index 54a9c09a5..ef5364b0b 100644
--- a/src/js/controllers/bitpayCard.js
+++ b/src/js/controllers/bitpayCard.js
@@ -1,39 +1,19 @@
'use strict';
-angular.module('copayApp.controllers').controller('bitpayCardController', function($scope, $timeout, $log, lodash, bitpayCardService, configService, profileService, walletService, ongoingProcess, pbkdf2Service, moment, popupService, gettextCatalog, bwcError) {
+angular.module('copayApp.controllers').controller('bitpayCardController', function($scope, $timeout, $log, $state, lodash, bitpayCardService, moment, popupService, gettextCatalog, $ionicHistory) {
var self = this;
- $scope.dateRange = 'last30Days';
+ $scope.dateRange = { value: 'last30Days'};
$scope.network = bitpayCardService.getEnvironment();
- bitpayCardService.getCacheData(function(err, data) {
- if (err || lodash.isEmpty(data)) return;
- $scope.bitpayCardCached = true;
- self.bitpayCardTransactionHistory = data.transactions;
- self.bitpayCardCurrentBalance = data.balance;
- });
-
- var processTransactions = function(invoices, history) {
- for (var i = 0; i < invoices.length; i++) {
- var matched = false;
- for (var j = 0; j < history.length; j++) {
- if (history[j].description[0].indexOf(invoices[i].id) > -1) {
- matched = true;
- }
- }
- if (!matched && ['paid', 'confirmed', 'complete'].indexOf(invoices[i].status) > -1) {
-
- history.unshift({
- timestamp: invoices[i].invoiceTime,
- description: invoices[i].itemDesc,
- amount: invoices[i].price,
- type: '00611 = Client Funded Deposit',
- pending: true,
- status: invoices[i].status
- });
- }
- }
- return history;
+ var getFromCache = function(cb) {
+ bitpayCardService.getBitpayDebitCardsHistory($scope.cardId, function(err, data) {
+ if (err || lodash.isEmpty(data)) return cb();
+ $scope.historyCached = true;
+ self.bitpayCardTransactionHistory = data.transactions;
+ self.bitpayCardCurrentBalance = data.balance;
+ return cb();
+ });
};
var setDateRange = function(preset) {
@@ -62,41 +42,35 @@ angular.module('copayApp.controllers').controller('bitpayCardController', functi
};
this.update = function() {
- var dateRange = setDateRange($scope.dateRange);
- self.loadingSession = true;
- bitpayCardService.isAuthenticated(function(err, bpSession) {
- self.loadingSession = false;
+ var dateRange = setDateRange($scope.dateRange.value);
+
+ $scope.loadingHistory = true;
+ bitpayCardService.getHistory($scope.cardId, dateRange, function(err, history) {
+ $scope.loadingHistory = false;
if (err) {
+ $log.error(err);
+ $scope.error = gettextCatalog.getString('Could not get transactions');
return;
}
- self.bitpayCardAuthenticated = bpSession.isAuthenticated;
- self.bitpayCardTwoFactorPending = bpSession.twoFactorPending ? true : false;
+ var txs = lodash.clone(history.txs);
+ for (var i = 0; i < txs.length; i++) {
+ txs[i] = _getMerchantInfo(txs[i]);
+ txs[i].icon = _getIconName(txs[i]);
+ txs[i].desc = _processDescription(txs[i]);
+ }
+ self.bitpayCardTransactionHistory = txs;
+ self.bitpayCardCurrentBalance = history.currentCardBalance;
- if (self.bitpayCardTwoFactorPending) return;
-
- if (self.bitpayCardAuthenticated) {
- $scope.loadingHistory = true;
- bitpayCardService.invoiceHistory(function(err, invoices) {
+ if ($scope.dateRange.value == 'last30Days') {
+ $log.debug('BitPay Card: store cache history');
+ var cacheHistory = {
+ balance: history.currentCardBalance,
+ transactions: history.txs
+ };
+ bitpayCardService.setBitpayDebitCardsHistory($scope.cardId, cacheHistory, {}, function(err) {
if (err) $log.error(err);
- bitpayCardService.transactionHistory(dateRange, function(err, history) {
- $scope.loadingHistory = false;
- if (err) {
- popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Could not get transactions'));
- return;
- }
-
- self.bitpayCardTransactionHistory = processTransactions(invoices, history.transactionList);
- self.bitpayCardCurrentBalance = history.currentCardBalance;
-
- var cacheData = {
- balance: self.bitpayCardCurrentBalance,
- transactions: self.bitpayCardTransactionHistory
- };
- bitpayCardService.setCacheData(cacheData, function(err) {
- if (err) $log.error(err);
- });
- });
+ $scope.historyCached = true;
});
}
$timeout(function() {
@@ -105,76 +79,43 @@ angular.module('copayApp.controllers').controller('bitpayCardController', functi
});
};
- this.authenticate = function(email, password) {
-
- var data = {
- emailAddress : email,
- hashedPassword : pbkdf2Service.pbkdf2Sync(password, '..............', 200, 64).toString('hex')
- };
-
- // POST /authenticate
- // emailAddress:
- // hashedPassword:
- self.authenticating = true;
- bitpayCardService.authenticate(data, function(err, auth) {
- self.authenticating = false;
- if (err && err.data && err.data.error && !err.data.error.twoFactorPending) {
- popupService.showAlert(gettextCatalog.getString('Error'), err.statusText || err.data.error || 'Authentiation error');
- return;
- }
-
- self.update();
- $timeout(function() {
- $scope.$apply();
- }, 100);
- });
- };
-
- this.authenticate2FA = function(twoFactorCode) {
-
- var data = {
- twoFactorCode : twoFactorCode
- };
-
- self.authenticating = true;
- bitpayCardService.authenticate2FA(data, function(err, auth) {
- self.authenticating = false;
- if (err) {
- popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Authentiation error'));
- return;
- }
-
- self.update();
- $timeout(function() {
- $scope.$apply();
- }, 100);
- });
- };
-
- this.getMerchantInfo = function(tx) {
+ var _getMerchantInfo = function(tx) {
var bpTranCodes = bitpayCardService.bpTranCodes;
lodash.keys(bpTranCodes).forEach(function(code) {
if (tx.type.indexOf(code) === 0) {
lodash.assign(tx, bpTranCodes[code]);
}
});
+ return tx;
};
- this.getIconName = function(tx) {
+ var _getIconName = function(tx) {
var icon = tx.mcc || tx.category || null;
if (!icon) return 'default';
return bitpayCardService.iconMap[icon];
};
- this.processDescription = function(tx) {
+ var _processDescription = function(tx) {
if (lodash.isArray(tx.description)) {
return tx.description[0];
}
return tx.description;
};
- $scope.$on("$ionicView.beforeEnter", function(event, data){
- self.update();
+ $scope.$on("$ionicView.beforeEnter", function(event, data) {
+ $scope.cardId = data.stateParams.id;
+ if (!$scope.cardId) {
+ var msg = gettextCatalog.getString('Bad param');
+ $ionicHistory.nextViewOptions({
+ disableAnimate: true
+ });
+ $state.go('tabs.home');
+ popupService.showAlert(null, msg);
+ } else {
+ getFromCache(function() {
+ self.update();
+ });
+ }
});
});
diff --git a/src/js/controllers/bitpayCardIntro.js b/src/js/controllers/bitpayCardIntro.js
new file mode 100644
index 000000000..95d5cbfb2
--- /dev/null
+++ b/src/js/controllers/bitpayCardIntro.js
@@ -0,0 +1,72 @@
+'use strict';
+angular.module('copayApp.controllers').controller('bitpayCardIntroController', function($scope, $log, $state, $ionicHistory, storageService, externalLinkService, bitpayCardService, gettextCatalog, popupService) {
+
+ var checkOtp = function(obj, cb) {
+ if (obj.otp) {
+ var msg = gettextCatalog.getString('Enter Two Factor for BitPay Cards');
+ popupService.showPrompt(null, msg, null, function(res) {
+ cb(res);
+ });
+ } else {
+ cb();
+ }
+ };
+
+ $scope.$on("$ionicView.beforeEnter", function(event, data) {
+
+ if (data.stateParams && data.stateParams.secret) {
+ var obj = {
+ secret: data.stateParams.secret,
+ email: data.stateParams.email,
+ otp: data.stateParams.otp
+ };
+ checkOtp(obj, function(otp) {
+ obj.otp = otp;
+ bitpayCardService.bitAuthPair(obj, function(err, data) {
+ if (err) {
+ popupService.showAlert(null, err);
+ return;
+ }
+ var title = gettextCatalog.getString('Add BitPay Cards?');
+ var msg = gettextCatalog.getString('Would you like to add this account ({{email}}) to your wallet?', {email: obj.email});
+ var ok = gettextCatalog.getString('Add cards');
+ var cancel = gettextCatalog.getString('Go back');
+ popupService.showConfirm(title, msg, ok, cancel, function(res) {
+ if (res) {
+ // Set flag for nextStep
+ storageService.setNextStep('BitpayCard', true, function(err) {});
+ // Save data
+ bitpayCardService.setBitpayDebitCards(data, function(err) {
+ if (err) return;
+ $ionicHistory.nextViewOptions({
+ disableAnimate: true
+ });
+ $state.go('tabs.home').then(function() {
+ if (data.cards[0]) {
+ $state.transitionTo('tabs.bitpayCard', {id: data.cards[0].id});
+ }
+ });
+ });
+ }
+ });
+ });
+ });
+ } else {
+ bitpayCardService.getCredentials(function(err, credentials) {
+ if (err) popupService.showAlert(null, err);
+ else $log.info('BitPay Debit Card Credentials: Ok.');
+ });
+ }
+ });
+
+ $scope.orderBitPayCard = function() {
+ var url = 'https://bitpay.com/visa/';
+ externalLinkService.open(url);
+ };
+
+ $scope.connectBitPayCard = function() {
+ var url = 'https://bitpay.com/visa/login';
+ externalLinkService.open(url);
+ };
+});
+
diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js
index 465257e7c..0b8949f3a 100644
--- a/src/js/controllers/confirm.js
+++ b/src/js/controllers/confirm.js
@@ -8,7 +8,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.isWallet = data.stateParams.isWallet;
- $scope.isCard = data.stateParams.isCard;
+ $scope.cardId = data.stateParams.cardId;
$scope.toAmount = data.stateParams.toAmount;
$scope.toAddress = data.stateParams.toAddress;
$scope.toName = data.stateParams.toName;
@@ -374,11 +374,22 @@ angular.module('copayApp.controllers').controller('confirmController', function(
};
$scope.onSuccessConfirm = function() {
+ var previousView = $ionicHistory.viewHistory().backView && $ionicHistory.viewHistory().backView.stateName;
+ var fromBitPayCard = previousView.match(/tabs.bitpayCard/) ? true : false;
+
$ionicHistory.nextViewOptions({
disableAnimate: true
});
+ $ionicHistory.removeBackView();
$scope.sendStatus = '';
- $state.go('tabs.send');
+
+ if (fromBitPayCard) {
+ $timeout(function() {
+ $state.transitionTo('tabs.bitpayCard', {id: $stateParams.cardId});
+ }, 100);
+ } else {
+ $state.go('tabs.send');
+ }
};
function publishAndSign(wallet, txp, onSendStatusChange) {
diff --git a/src/js/controllers/preferencesBitpayCard.js b/src/js/controllers/preferencesBitpayCard.js
index 2abf6a8c4..0fb74d228 100644
--- a/src/js/controllers/preferencesBitpayCard.js
+++ b/src/js/controllers/preferencesBitpayCard.js
@@ -1,17 +1,17 @@
'use strict';
angular.module('copayApp.controllers').controller('preferencesBitpayCardController',
- function($scope, $state, $timeout, $ionicHistory, bitpayCardService, popupService) {
+ function($scope, $state, $timeout, $ionicHistory, bitpayCardService, popupService, gettextCatalog) {
- $scope.logout = function() {
- var title = 'Are you sure you would like to log out of your Bitpay Card account?';
- popupService.showConfirm(title, null, null, null, function(res) {
- if (res) logout();
+ $scope.remove = function() {
+ var msg = gettextCatalog.getString('Are you sure you would like to remove your BitPay Card account from this device?');
+ popupService.showConfirm(null, msg, null, null, function(res) {
+ if (res) remove();
});
};
- var logout = function() {
- bitpayCardService.logout(function() {
+ var remove = function() {
+ bitpayCardService.remove(function() {
$ionicHistory.removeBackView();
$timeout(function() {
$state.go('tabs.home');
@@ -19,4 +19,11 @@ angular.module('copayApp.controllers').controller('preferencesBitpayCardControll
});
};
+ $scope.$on("$ionicView.beforeEnter", function(event, data) {
+ bitpayCardService.getBitpayDebitCards(function(err, data) {
+ if (err) return;
+ $scope.bitpayCards = data.cards;
+ });
+ });
+
});
diff --git a/src/js/controllers/tab-home.js b/src/js/controllers/tab-home.js
index c4fa9b106..3d67a56f4 100644
--- a/src/js/controllers/tab-home.js
+++ b/src/js/controllers/tab-home.js
@@ -6,7 +6,6 @@ angular.module('copayApp.controllers').controller('tabHomeController',
var listeners = [];
var notifications = [];
$scope.externalServices = {};
- $scope.bitpayCardEnabled = true; // TODO
$scope.openTxpModal = txpModalService.open;
$scope.version = $window.version;
$scope.name = $window.appConfig.nameCase;
@@ -203,9 +202,21 @@ angular.module('copayApp.controllers').controller('tabHomeController',
};
var bitpayCardCache = function() {
- bitpayCardService.getCacheData(function(err, data) {
- if (err || lodash.isEmpty(data)) return;
- $scope.bitpayCard = data;
+ bitpayCardService.getBitpayDebitCards(function(err, data) {
+ if (err) return;
+ if (lodash.isEmpty(data)) {
+ $scope.bitpayCards = null;
+ return;
+ }
+ $scope.bitpayCards = data.cards;
+ });
+ bitpayCardService.getBitpayDebitCardsHistory(null, function(err, data) {
+ if (err) return;
+ if (lodash.isEmpty(data)) {
+ $scope.cardsHistory = null;
+ return;
+ }
+ $scope.cardsHistory = data;
});
};
@@ -215,7 +226,6 @@ angular.module('copayApp.controllers').controller('tabHomeController',
};
$scope.$on("$ionicView.enter", function(event, data) {
- $scope.bitpayCard = null;
nextStep();
updateAllWallets();
diff --git a/src/js/controllers/tabsController.js b/src/js/controllers/tabsController.js
index 3e93df45d..642948ab6 100644
--- a/src/js/controllers/tabsController.js
+++ b/src/js/controllers/tabsController.js
@@ -35,6 +35,7 @@ angular.module('copayApp.controllers').controller('tabsController', function($ro
'tabs.receive.backup',
'tabs.bitpayCard.amount',
'tabs.bitpayCard.confirm',
+ 'tabs.bitpayCardIntro'
];
$rootScope.$on('$ionicView.beforeEnter', function() {
diff --git a/src/js/routes.js b/src/js/routes.js
index caa3df17f..b4c68d926 100644
--- a/src/js/routes.js
+++ b/src/js/routes.js
@@ -846,8 +846,17 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
*
*/
- .state('tabs.bitpayCard', {
- url: '/bitpay-card',
+ .state('tabs.bitpayCardIntro', {
+ url: '/bitpay-card-intro/:secret/:email/:otp',
+ views: {
+ 'tab-home@tabs': {
+ controller: 'bitpayCardIntroController',
+ templateUrl: 'views/bitpayCardIntro.html'
+ }
+ }
+ })
+ .state('tabs.bitpayCard', {
+ url: '/bitpay-card/:id',
views: {
'tab-home@tabs': {
controller: 'bitpayCardController',
@@ -857,7 +866,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}
})
.state('tabs.bitpayCard.amount', {
- url: '/amount/:isCard/:toName',
+ url: '/amount/:cardId/:toName',
views: {
'tab-home@tabs': {
controller: 'amountController',
@@ -866,7 +875,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
}
})
.state('tabs.bitpayCard.confirm', {
- url: '/confirm/:isCard/:toAddress/:toName/:toAmount/:toEmail/:description/:paypro',
+ url: '/confirm/:cardId/:toAddress/:toName/:toAmount/:toEmail/:description/:paypro',
views: {
'tab-home@tabs': {
controller: 'confirmController',
@@ -878,6 +887,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
url: '/preferences',
views: {
'tab-home@tabs': {
+ controller: 'preferencesBitpayCardController',
templateUrl: 'views/preferencesBitpayCard.html'
}
}
diff --git a/src/js/services/bitpayCardService.js b/src/js/services/bitpayCardService.js
index c49bc5ffa..884b57cbe 100644
--- a/src/js/services/bitpayCardService.js
+++ b/src/js/services/bitpayCardService.js
@@ -1,195 +1,236 @@
'use strict';
-angular.module('copayApp.services').factory('bitpayCardService', function($http, $log, lodash, storageService) {
+angular.module('copayApp.services').factory('bitpayCardService', function($http, $log, lodash, storageService, bitauthService, platformInfo, moment) {
var root = {};
- var credentials = {};
- var bpSession = {};
+ var BITPAY_CARD_NETWORK = 'livenet';
+ var BITPAY_CARD_API_URL = BITPAY_CARD_NETWORK == 'livenet' ? 'https://bitpay.com' : 'https://test.bitpay.com';
- var _setCredentials = function() {
- /*
- * Development: 'testnet'
- * Production: 'livenet'
- */
- credentials.NETWORK = 'livenet';
- if (credentials.NETWORK == 'testnet') {
- credentials.BITPAY_API_URL = 'https://test.bitpay.com';
- }
- else {
- credentials.BITPAY_API_URL = 'https://bitpay.com';
- };
+ var _getCredentials = function(cb) {
+ var pubkey, sin, isNew;
+ storageService.getBitpayCardCredentials(BITPAY_CARD_NETWORK, function(err, data) {
+ if (err) return cb(err);
+ if (lodash.isString(data)) {
+ data = JSON.parse(data);
+ }
+ var credentials = data || {};
+ if (lodash.isEmpty(credentials) || (credentials && !credentials.priv)) {
+ isNew = true;
+ credentials = bitauthService.generateSin();
+ }
+ try {
+ pubkey = bitauthService.getPublicKeyFromPrivateKey(credentials.priv);
+ sin = bitauthService.getSinFromPublicKey(pubkey);
+ if (isNew)
+ storageService.setBitpayCardCredentials(BITPAY_CARD_NETWORK, JSON.stringify(credentials), function(err) {});
+ }
+ catch (e) {
+ $log.error(e);
+ return cb(e);
+ };
+ return cb(null, credentials);
+ });
};
var _setError = function(msg, e) {
$log.error(msg);
- return e;
+ var error = e.data ? e.data.error : msg;
+ return error;
};
- var _getUser = function(cb) {
- _setCredentials();
- storageService.getBitpayCard(credentials.NETWORK, function(err, user) {
- if (err) return cb(err);
- if (lodash.isString(user)) {
- user = JSON.parse(user);
- }
- return cb(null, user);
- });
- };
-
- var _setUser = function(user, cb) {
- _setCredentials();
- user = JSON.stringify(user);
- storageService.setBitpayCard(credentials.NETWORK, user, function(err) {
- return cb(err);
- });
- // Show pending task from the UI
- storageService.setNextStep('BitpayCard', true, function(err) {});
- };
-
- var _getSession = function(cb) {
- _setCredentials();
- $http({
+ var _get = function(endpoint) {
+ return {
method: 'GET',
- url: credentials.BITPAY_API_URL + '/visa-api/session',
+ url: BITPAY_CARD_API_URL + endpoint,
headers: {
'content-type': 'application/json'
}
- }).then(function(data) {
- $log.info('BitPay Get Session: SUCCESS');
- bpSession = data.data.data;
- return cb(null, bpSession);
+ };
+ };
+
+ var _post = function(endpoint, json, credentials) {
+ var dataToSign = BITPAY_CARD_API_URL + endpoint + JSON.stringify(json);
+ var signedData = bitauthService.sign(dataToSign, credentials.priv);
+
+ return {
+ method: 'POST',
+ url: BITPAY_CARD_API_URL + endpoint,
+ headers: {
+ 'content-type': 'application/json',
+ 'x-identity': credentials.pub,
+ 'x-signature': signedData
+ },
+ data: json
+ };
+ };
+
+ var _postAuth = function(endpoint, json, credentials) {
+ json['params'].signature = bitauthService.sign(JSON.stringify(json.params), credentials.priv);
+ json['params'].pubkey = credentials.pub;
+ json['params'] = JSON.stringify(json.params);
+
+ return {
+ method: 'POST',
+ url: BITPAY_CARD_API_URL + endpoint,
+ headers: {
+ 'content-type': 'application/json'
+ },
+ data: json
+ };
+ };
+
+ var _afterBitAuthSuccess = function(token, obj, credentials, cb) {
+ var json = {
+ method: 'getDebitCards'
+ };
+ // Get Debit Cards
+ $http(_post('/api/v2/' + token, json, credentials)).then(function(data) {
+ if (data && data.data.error) return cb(data.data.error);
+ $log.info('BitPay Get Debit Cards: SUCCESS');
+ return cb(data.data.error, {token: token, cards: data.data.data, email: obj.email});
}, function(data) {
- return cb(_setError('BitPay Card Error: Get Session', data));
+ return cb(_setError('BitPay Card Error: Get Debit Cards', data));
});
};
- var _getBitPay = function(endpoint) {
- _setCredentials();
- return {
- method: 'GET',
- url: credentials.BITPAY_API_URL + endpoint,
- headers: {
- 'content-type': 'application/json',
- 'x-csrf-token': bpSession.csrfToken
+ var _processTransactions = function(invoices, history) {
+ invoices = invoices || [];
+ for (var i = 0; i < invoices.length; i++) {
+ var matched = false;
+ for (var j = 0; j < history.length; j++) {
+ if (history[j].description[0].indexOf(invoices[i].id) > -1) {
+ matched = true;
+ }
}
- };
- };
+ var isInvoiceLessThanOneDayOld = moment() < moment(new Date(invoices[i].invoiceTime)).add(1, 'day');
+ if (!matched && isInvoiceLessThanOneDayOld) {
+ var isInvoiceUnderpaid = invoices[i].exceptionStatus === 'paidPartial';
- var _postBitPay = function(endpoint, data) {
- _setCredentials();
- return {
- method: 'POST',
- url: credentials.BITPAY_API_URL + endpoint,
- headers: {
- 'Content-Type': 'application/json',
- 'x-csrf-token': bpSession.csrfToken
- },
- data: data
- };
+ if(['paid', 'confirmed', 'complete'].indexOf(invoices[i].status) >= 0
+ || (invoices[i].status === 'invalid' || isInvoiceUnderpaid)) {
+
+ history.unshift({
+ timestamp: new Date(invoices[i].invoiceTime),
+ description: invoices[i].itemDesc,
+ amount: invoices[i].price,
+ type: '00611 = Client Funded Deposit',
+ pending: true,
+ status: invoices[i].status
+ });
+ }
+ }
+ }
+ return history;
};
root.getEnvironment = function() {
- _setCredentials();
- return credentials.NETWORK;
+ return BITPAY_CARD_NETWORK;
};
- root.topUp = function(data, cb) {
- var dataSrc = {
- amount: data.amount,
- currency: data.currency
- };
- $http(_postBitPay('/visa-api/topUp', dataSrc)).then(function(data) {
- $log.info('BitPay TopUp: SUCCESS');
- return cb(null, data.data.data.invoice);
- }, function(data) {
- return cb(_setError('BitPay Card Error: TopUp', data));
+ root.getCredentials = function(cb) {
+ _getCredentials(function(err, credentials) {
+ return cb(err, credentials);
});
};
- root.transactionHistory = function(dateRange, cb) {
- var params;
- if (!dateRange.startDate) {
- params = '';
- } else {
- params = '/?startDate=' + dateRange.startDate + '&endDate=' + dateRange.endDate;
+ root.bitAuthPair = function(obj, cb) {
+ var deviceName = 'Unknow device';
+ if (platformInfo.isNW) {
+ deviceName = require('os').platform();
+ } else if (platformInfo.isCordova) {
+ deviceName = device.model;
}
- $http(_getBitPay('/visa-api/transactionHistory' + params)).then(function(data) {
- $log.info('BitPay Get Transaction History: SUCCESS');
- return cb(null, data.data.data);
- }, function(data) {
- return cb(_setError('BitPay Card Error: Get Transaction History', data));
+ var json = {
+ method: 'createToken',
+ params: {
+ secret: obj.secret,
+ version: 2,
+ deviceName: deviceName,
+ code: obj.otp
+ }
+ };
+ _getCredentials(function(err, credentials) {
+ if (err) return cb(err);
+ $http(_postAuth('/api/v2/', json, credentials)).then(function(data) {
+ if (data && data.data.error) return cb(data.data.error);
+ $log.info('BitPay Card BitAuth Create Token: SUCCESS');
+ _afterBitAuthSuccess(data.data.data, obj, credentials, cb);
+ }, function(data) {
+ return cb(_setError('BitPay Card Error Create Token: BitAuth', data));
+ });
});
};
- root.invoiceHistory = function(cb) {
- $http(_getBitPay('/visa-api/invoiceHistory')).then(function(data) {
- $log.info('BitPay Get Invoice History: SUCCESS');
- return cb(null, data.data.data);
- }, function(data) {
- return cb(_setError('BitPay Card Error: Get Invoice History', data));
+ root.getHistory = function(cardId, params, cb) {
+ var invoices, transactions;
+ params = params || {};
+ var json = {
+ method: 'getInvoiceHistory',
+ params: JSON.stringify(params)
+ };
+ _getCredentials(function(err, credentials) {
+ if (err) return cb(err);
+ root.getBitpayDebitCards(function(err, data) {
+ if (err) return cb(err);
+ var card = lodash.find(data.cards, {id : cardId});
+ if (!card) return cb(_setError('Not card found'));
+ // Get invoices
+ $http(_post('/api/v2/' + card.token, json, credentials)).then(function(data) {
+ $log.info('BitPay Get Invoices: SUCCESS');
+ invoices = data.data.data || [];
+ if (lodash.isEmpty(invoices)) $log.info('No invoices');
+ json = {
+ method: 'getTransactionHistory',
+ params: JSON.stringify(params)
+ };
+ // Get transactions list
+ $http(_post('/api/v2/' + card.token, json, credentials)).then(function(data) {
+ $log.info('BitPay Get Transactions: SUCCESS');
+ transactions = data.data.data || {};
+ transactions['txs'] = _processTransactions(invoices, transactions.transactionList);
+ return cb(data.data.error, transactions);
+ }, function(data) {
+ return cb(_setError('BitPay Card Error: Get Transactions', data));
+ });
+ }, function(data) {
+ return cb(_setError('BitPay Card Error: Get Invoices', data));
+ });
+ });
+ });
+ };
+
+ root.topUp = function(cardId, params, cb) {
+ params = params || {};
+ var json = {
+ method: 'generateTopUpInvoice',
+ params: JSON.stringify(params)
+ };
+ _getCredentials(function(err, credentials) {
+ if (err) return cb(err);
+ root.getBitpayDebitCards(function(err, data) {
+ if (err) return cb(err);
+ var card = lodash.find(data.cards, {id : cardId});
+ if (!card) return cb(_setError('Not card found'));
+ $http(_post('/api/v2/' + card.token, json, credentials)).then(function(data) {
+ $log.info('BitPay TopUp: SUCCESS');
+ return cb(data.data.error, data.data.data.invoice);
+ }, function(data) {
+ return cb(_setError('BitPay Card Error: TopUp', data));
+ });
+ });
});
};
root.getInvoice = function(id, cb) {
- $http(_getBitPay('/invoices/' + id)).then(function(data) {
+ $http(_get('/invoices/' + id)).then(function(data) {
$log.info('BitPay Get Invoice: SUCCESS');
- return cb(null, data.data.data);
+ return cb(data.data.error, data.data.data);
}, function(data) {
return cb(_setError('BitPay Card Error: Get Invoice', data));
});
};
- root.authenticate = function(userData, cb) {
- _setUser(userData, function(err) {
- $http(_postBitPay('/visa-api/authenticate', userData)).then(function(data) {
- $log.info('BitPay Authenticate: SUCCESS');
- _getSession(function(err, session) {
- if (err) return cb(err);
- return cb(null, session);
- });
- }, function(data) {
- if (data && data.data && data.data.error.twoFactorPending) {
- $log.error('BitPay Card needs 2FA Authentication');
- _getSession(function(err, session) {
- if (err) return cb(err);
- return cb(null, session);
- });
- } else {
- return cb(data);
- }
- });
- });
- };
-
- root.authenticate2FA = function(userData, cb) {
- $http(_postBitPay('/visa-api/verify-two-factor', userData)).then(function(data) {
- $log.info('BitPay 2FA: SUCCESS');
- return cb(null, data);
- }, function(data) {
- return cb(_setError('BitPay Card Error: 2FA', data));
- });
- };
-
- root.isAuthenticated = function(cb) {
- _getSession(function(err, session) {
- if (err) return cb(err);
- if (!session.isAuthenticated) {
- _getUser(function(err, user) {
- if (err) return cb(err);
- if (lodash.isEmpty(user)) return cb(null, session);
- root.authenticate(user, function(err, session) {
- if (err) return cb(err);
- return cb(null, session);
- });
- });
- } else {
- return cb(null, session);
- }
- });
- };
-
- root.getCacheData = function(cb) {
- _setCredentials();
- storageService.getBitpayCardCache(credentials.NETWORK, function(err, data) {
+ root.getBitpayDebitCards = function(cb) {
+ storageService.getBitpayDebitCards(BITPAY_CARD_NETWORK, function(err, data) {
if (err) return cb(err);
if (lodash.isString(data)) {
data = JSON.parse(data);
@@ -199,32 +240,54 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
});
};
- root.setCacheData = function(data, cb) {
- _setCredentials();
+ root.setBitpayDebitCards = function(data, cb) {
data = JSON.stringify(data);
- storageService.setBitpayCardCache(credentials.NETWORK, data, function(err) {
+ storageService.setBitpayDebitCards(BITPAY_CARD_NETWORK, data, function(err) {
if (err) return cb(err);
return cb();
});
};
- root.removeCacheData = function(cb) {
- _setCredentials();
- storageService.removeBitpayCardCache(credentials.NETWORK, function(err) {
+ root.getBitpayDebitCardsHistory = function(cardId, cb) {
+ storageService.getBitpayDebitCardsHistory(BITPAY_CARD_NETWORK, function(err, data) {
if (err) return cb(err);
- return cb();
+ if (lodash.isString(data)) {
+ data = JSON.parse(data);
+ }
+ data = data || {};
+ if (cardId) data = data[cardId];
+ return cb(null, data);
});
};
- root.logout = function(cb) {
- _setCredentials();
- root.removeCacheData(function() {});
- storageService.removeBitpayCard(credentials.NETWORK, function(err) {
- $http(_getBitPay('/visa-api/logout')).then(function(data) {
- $log.info('BitPay Logout: SUCCESS');
- return cb(data);
- }, function(data) {
- return cb(_setError('BitPay Card Error: Logout ', data));
+ root.setBitpayDebitCardsHistory = function(cardId, data, opts, cb) {
+ storageService.getBitpayDebitCardsHistory(BITPAY_CARD_NETWORK, function(err, oldData) {
+ if (lodash.isString(oldData)) {
+ oldData = JSON.parse(oldData);
+ }
+ if (lodash.isString(data)) {
+ data = JSON.parse(data);
+ }
+ var inv = oldData || {};
+ inv[cardId] = data;
+ if (opts && opts.remove) {
+ delete(inv[cardId]);
+ }
+ inv = JSON.stringify(inv);
+
+ storageService.setBitpayDebitCardsHistory(BITPAY_CARD_NETWORK, inv, function(err) {
+ return cb(err);
+ });
+ });
+ };
+
+ root.remove = function(cb) {
+ storageService.removeBitpayCardCredentials(BITPAY_CARD_NETWORK, function(err) {
+ storageService.removeBitpayDebitCards(BITPAY_CARD_NETWORK, function(err) {
+ storageService.removeBitpayDebitCardsHistory(BITPAY_CARD_NETWORK, function(err) {
+ $log.info('BitPay Debit Cards Removed: SUCCESS');
+ return cb();
+ });
});
});
};
diff --git a/src/js/services/incomingData.js b/src/js/services/incomingData.js
index fc363590c..b157704b8 100644
--- a/src/js/services/incomingData.js
+++ b/src/js/services/incomingData.js
@@ -1,6 +1,6 @@
'use strict';
-angular.module('copayApp.services').factory('incomingData', function($log, $ionicModal, $state, $window, $timeout, bitcore) {
+angular.module('copayApp.services').factory('incomingData', function($log, $state, $window, bitcore, lodash) {
var root = {};
@@ -23,17 +23,25 @@ angular.module('copayApp.services').factory('incomingData', function($log, $ioni
return newUri;
};
+ function getParameterByName(name, url) {
+ if (!url) return;
+ name = name.replace(/[\[\]]/g, "\\$&");
+ var regex = new RegExp("[?&]" + name + "(=([^]*)|&|#|$)"),
+ results = regex.exec(url);
+ if (!results) return null;
+ if (!results[2]) return '';
+ return decodeURIComponent(results[2].replace(/\+/g, " "));
+ }
+
// data extensions for Payment Protocol with non-backwards-compatible request
if ((/^bitcoin:\?r=[\w+]/).exec(data)) {
data = decodeURIComponent(data.replace('bitcoin:?r=', ''));
- $state.go('tabs.send');
- $timeout(function() {
+ $state.go('tabs.send').then(function() {
$state.transitionTo('tabs.send.confirm', {paypro: data});
- }, 100);
+ });
return true;
}
-
data = sanitizeUri(data);
// BIP21
@@ -45,8 +53,7 @@ angular.module('copayApp.services').factory('incomingData', function($log, $ioni
var amount = parsed.amount ? parsed.amount : '';
- $state.go('tabs.send');
- $timeout(function() {
+ $state.go('tabs.send').then(function() {
if (parsed.r) {
$state.transitionTo('tabs.send.confirm', {paypro: parsed.r});
} else {
@@ -56,29 +63,26 @@ angular.module('copayApp.services').factory('incomingData', function($log, $ioni
$state.transitionTo('tabs.send.amount', {toAddress: addr});
}
}
- }, 100);
+ });
return true;
// Plain URL
} else if (/^https?:\/\//.test(data)) {
- $state.go('tabs.send');
- $timeout(function() {
+ $state.go('tabs.send').then(function() {
$state.transitionTo('tabs.send.confirm', {paypro: data});
- }, 100);
+ });
return true;
// Plain Address
} else if (bitcore.Address.isValid(data, 'livenet')) {
- $state.go('tabs.send');
- $timeout(function() {
+ $state.go('tabs.send').then(function() {
$state.transitionTo('tabs.send.amount', {toAddress: data});
- }, 100);
+ });
return true;
} else if (bitcore.Address.isValid(data, 'testnet')) {
- $state.go('tabs.send');
- $timeout(function() {
+ $state.go('tabs.send').then(function() {
$state.transitionTo('tabs.send.amount', {toAddress: data});
- }, 100);
+ });
return true;
// Protocol
@@ -87,20 +91,32 @@ angular.module('copayApp.services').factory('incomingData', function($log, $ioni
} else if (data && data.indexOf($window.appConfig.name + '://coinbase')==0) {
return $state.go('uricoinbase', {url: data});
+ // BitPayCard Authentication
+ } else if (data && data.indexOf($window.appConfig.name + '://')==0) {
+ var secret = getParameterByName('secret', data);
+ var email = getParameterByName('email', data);
+ var otp = getParameterByName('otp', data);
+ $state.go('tabs.home').then(function() {
+ $state.transitionTo('tabs.bitpayCardIntro', {
+ secret: secret,
+ email: email,
+ otp: otp
+ });
+ });
+ return true;
+
// Join
} else if (data && data.match(/^copay:[0-9A-HJ-NP-Za-km-z]{70,80}$/)) {
- $state.go('tabs.home');
- $timeout(function() {
+ $state.go('tabs.home').then(function() {
$state.transitionTo('tabs.add.join', {url: data});
- }, 100);
+ });
return true;
// Old join
} else if (data && data.match(/^[0-9A-HJ-NP-Za-km-z]{70,80}$/)) {
- $state.go('tabs.home');
- $timeout(function() {
+ $state.go('tabs.home').then(function() {
$state.transitionTo('tabs.add.join', {url: data});
- }, 100);
+ });
return true;
}
diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js
index a0e0f6503..60f01a3c8 100644
--- a/src/js/services/storageService.js
+++ b/src/js/services/storageService.js
@@ -325,28 +325,40 @@ angular.module('copayApp.services')
storage.remove('coinbaseTxs-' + network, cb);
};
- root.setBitpayCard = function(network, data, cb) {
- storage.set('bitpayCard-' + network, data, cb);
+ root.setBitpayDebitCardsHistory = function(network, data, cb) {
+ storage.set('bitpayDebitCardsHistory-' + network, data, cb);
};
- root.getBitpayCard = function(network, cb) {
- storage.get('bitpayCard-' + network, cb);
+ root.getBitpayDebitCardsHistory = function(network, cb) {
+ storage.get('bitpayDebitCardsHistory-' + network, cb);
};
- root.removeBitpayCard = function(network, cb) {
- storage.remove('bitpayCard-' + network, cb);
+ root.removeBitpayDebitCardsHistory = function(network, cb) {
+ storage.remove('bitpayDebitCardsHistory-' + network, cb);
};
- root.setBitpayCardCache = function(network, data, cb) {
- storage.set('bitpayCardCache-' + network, data, cb);
+ root.setBitpayDebitCards = function(network, data, cb) {
+ storage.set('bitpayDebitCards-' + network, data, cb);
};
- root.getBitpayCardCache = function(network, cb) {
- storage.get('bitpayCardCache-' + network, cb);
+ root.getBitpayDebitCards = function(network, cb) {
+ storage.get('bitpayDebitCards-' + network, cb);
};
- root.removeBitpayCardCache = function(network, cb) {
- storage.remove('bitpayCardCache-' + network, cb);
+ root.removeBitpayDebitCards = function(network, cb) {
+ storage.remove('bitpayDebitCards-' + network, cb);
+ };
+
+ root.setBitpayCardCredentials = function(network, data, cb) {
+ storage.set('bitpayCardCredentials-' + network, data, cb);
+ };
+
+ root.getBitpayCardCredentials = function(network, cb) {
+ storage.get('bitpayCardCredentials-' + network, cb);
+ };
+
+ root.removeBitpayCardCredentials = function(network, cb) {
+ storage.remove('bitpayCardCredentials-' + network, cb);
};
root.removeAllWalletData = function(walletId, cb) {
diff --git a/src/sass/views/bitpayCard.scss b/src/sass/views/bitpayCard.scss
index 5d7b045b6..563554f15 100644
--- a/src/sass/views/bitpayCard.scss
+++ b/src/sass/views/bitpayCard.scss
@@ -3,12 +3,15 @@
width: 100%;
text-align: center;
padding: 2rem 1rem 1.5rem 1rem;
- min-height: 140px;
+ height: 140px;
border-color: #172565;
background-color: #1e3186;
background-image: linear-gradient(0deg, #172565, #172565 0%, transparent 0%);
color: #fff;
}
+ .wallet-details-wallet-info {
+ bottom: 5px;
+ }
strong {
line-height: 100%;
}
diff --git a/src/sass/views/bitpayCardIntro.scss b/src/sass/views/bitpayCardIntro.scss
new file mode 100644
index 000000000..3ce232b0f
--- /dev/null
+++ b/src/sass/views/bitpayCardIntro.scss
@@ -0,0 +1,70 @@
+#bitpayCard-intro {
+ .slider-pager .slider-pager-page {
+ color: #fff;
+ }
+ .cta-button{
+ text-align: center;
+ position: absolute;
+ bottom: 55px;
+ padding: 0 1.5rem;
+ width: 100%;
+ }
+ background: rgba(30, 49, 134, 1);
+ background: -moz-linear-gradient(top, rgba(30, 49, 134, 1) 0%, rgba(17, 27, 73, 1) 100%);
+ background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(30, 49, 134, 1)), color-stop(100%, rgba(17, 27, 73, 1)));
+ background: -webkit-linear-gradient(top, rgba(30, 49, 134, 1) 0%, rgba(17, 27, 73, 1) 100%);
+ background: -o-linear-gradient(top, rgba(30, 49, 134, 1) 0%, rgba(17, 27, 73, 1) 100%);
+ background: -ms-linear-gradient(top, rgba(30, 49, 134, 1) 0%, rgba(17, 27, 73, 1) 100%);
+ background: linear-gradient(to bottom, rgba(30, 49, 134, 1) 0%, rgba(17, 27, 73, 1) 100%);
+ color: #fff;
+ height: 100%;
+ .bar.bar-header {
+ background: rgb(30, 49, 134);
+ color: #fff;
+ button {
+ color: #fff;
+ }
+ .secondary-buttons {
+ button {
+ color: rgba(255, 255, 255, .5);
+ }
+ }
+ }
+ .bar.bar-stable{
+ border-color: transparent;
+ border:none;
+ }
+ .button-transparent{
+ background: none !important;
+ }
+ .button-translucent{
+ background: rgba(215, 215, 215, 0.1)
+ }
+ .button-primary{
+ background: rgb(100, 124, 232) !important;
+ color:#fff;
+ }
+ .light-blue{
+ color:rgb(100, 124, 232);
+ }
+ .text-white{
+ color: #ffffff;
+ }
+ ion-content {
+ background: url(../img/onboarding-welcome-bg.png);
+ background-position: top center;
+ background-size: contain;
+ background-repeat: repeat-x;
+ height: 100%;
+ .scroll{
+ height: 100%;
+ }
+ color: #fff;
+ p {
+ text-align: center;
+ margin: 40px 20px;
+ font-size: 1.2rem;
+ color: rgba(255, 255, 255, .5);
+ }
+ }
+}
diff --git a/src/sass/views/views.scss b/src/sass/views/views.scss
index 0112476f3..de6ee8d30 100644
--- a/src/sass/views/views.scss
+++ b/src/sass/views/views.scss
@@ -12,6 +12,7 @@
@import "walletDetails";
@import "advancedSettings";
@import "bitpayCard";
+@import "bitpayCardIntro";
@import "address-book";
@import "wallet-backup-phrase";
@import "zero-state";
diff --git a/webkitbuilds/setup-win.iss b/webkitbuilds/setup-win.iss
index 8ae2a631f..f495bd8db 100755
--- a/webkitbuilds/setup-win.iss
+++ b/webkitbuilds/setup-win.iss
@@ -8,7 +8,7 @@
#define MyAppExeName "*PACKAGENAME.exe"
[Setup]
-AppId={{804636ee-b017-4cad-8719-e58ac97ffa5c}
+AppId={804636ee-b017-4cad-8719-e58ac97ffa5c}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
diff --git a/www/img/favicon.ico b/www/img/favicon.ico
index e2f92139d..166c0bcaf 100644
Binary files a/www/img/favicon.ico and b/www/img/favicon.ico differ
diff --git a/www/img/icon-128.png b/www/img/icon-128.png
new file mode 100644
index 000000000..6958667cd
Binary files /dev/null and b/www/img/icon-128.png differ
diff --git a/www/views/amount.html b/www/views/amount.html
index 8e961d3b7..9754e8867 100644
--- a/www/views/amount.html
+++ b/www/views/amount.html
@@ -12,15 +12,15 @@
Recipient
-
+
-
-
+
+
-
{{toName || toAddress}}
+
{{toName || toAddress}}
diff --git a/www/views/bitpayCard.html b/www/views/bitpayCard.html
index ab8457b30..557b06869 100644
--- a/www/views/bitpayCard.html
+++ b/www/views/bitpayCard.html
@@ -2,9 +2,9 @@
- BitPay Card
-
-
-
- Loading...
-
-
-
-
-

+
+
+
-
- Login to your account
- 2-Step Verification
-
-
-
-
-
- Enter the verification code generated by the authenticator app on your phone.
-
-
-
-
-
-
-
-
+
+

+
+
+
+ {{error}}
+
+
+
+
+
Get started
+ Your BitPay Card is ready. Add funds to your card to start using your card at stores and ATMs worldwide.
+
+
+
+
+
+
-
-
Get started
- Your BitPay Card is ready. Add funds to your card to start using your card at stores and ATMs worldwide.
-
-
-
-
-
+ ng-repeat="tx in bitpayCard.bitpayCardTransactionHistory | orderBy: ['pending','-timestamp']"
+ class="item row">
+
+
-
-
-
![]()
-
-
-
- {{tx.merchant.name}}
-
-
- {{tx.merchant.city}}, {{tx.merchant.state}}
-
+
+
+ {{tx.merchant.name}}
-
- {{desc}}
+
+ {{tx.merchant.city}}, {{tx.merchant.state}}
-
-
![]()
-
![]()
-
-
-
- {{tx.amount | currency:'$':2 }}
-
-
+
+
+ {{tx.desc}}
+
+
+
![]()
+
![]()
+
+
+
+ {{tx.amount | currency:'$':2 }}
+
+
Pending
diff --git a/www/views/bitpayCardIntro.html b/www/views/bitpayCardIntro.html
new file mode 100644
index 000000000..262a5f710
--- /dev/null
+++ b/www/views/bitpayCardIntro.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+ Turn bitcoin into dollars, swipe anywhere Visa® is accepted.
+
+
+
+
+ Get local cash anywhere you go, from any Visa®-compatible ATM.
+
+ *ATM bank fees may apply
+
+
+
+
+
+ Pay 0% fees to turn bitcoin into dollars.
+
+
+
+
+
+ Order the BitPay Card
+
+
+ Connect my BitPay Card
+
+
+
+
diff --git a/www/views/confirm.html b/www/views/confirm.html
index 953dc89fb..49c70ce85 100644
--- a/www/views/confirm.html
+++ b/www/views/confirm.html
@@ -23,8 +23,15 @@
@@ -138,7 +148,7 @@