Improved bitpay account pairing and management of paired state and data.
This commit is contained in:
parent
15d12823ab
commit
63bc3d8f63
23 changed files with 691 additions and 208 deletions
206
src/js/services/bitpayAccountService.js
Normal file
206
src/js/services/bitpayAccountService.js
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('bitpayAccountService', function($log, lodash, platformInfo, appIdentityService, bitpayService, bitpayCardService, storageService, gettextCatalog, popupService) {
|
||||
var root = {};
|
||||
|
||||
/*
|
||||
* Pair this app with the bitpay server using the specified pairing data.
|
||||
* An app identity will be created if one does not already exist.
|
||||
* Pairing data is provided by an input URI provided by the bitpay server.
|
||||
*
|
||||
* pairData - data needed to complete the pairing process
|
||||
* {
|
||||
* secret: shared pairing secret
|
||||
* email: email address associated with bitpay account
|
||||
* otp: two-factor one-time use password
|
||||
* }
|
||||
*
|
||||
* pairingReason - text string to be embedded into popup message. If `null` then the reason
|
||||
* message is not shown to the UI.
|
||||
* "To {{reason}} you must pair this app with your BitPay account ({{email}})."
|
||||
*
|
||||
* cb - callback after completion
|
||||
* callback(err, paired, apiContext)
|
||||
*
|
||||
* err - something unexpected happened which prevented the pairing
|
||||
*
|
||||
* paired - boolean indicating whether the pairing was compledted by the user
|
||||
*
|
||||
* apiContext - the context needed for making future api calls
|
||||
* {
|
||||
* token: api token for use in future calls
|
||||
* pairData: the input pair data
|
||||
* appIdentity: the identity of this app
|
||||
* }
|
||||
*/
|
||||
root.pair = function(pairData, pairingReason, cb) {
|
||||
checkOtp(pairData, function(otp) {
|
||||
pairData.otp = otp;
|
||||
var deviceName = 'Unknown device';
|
||||
if (platformInfo.isNW) {
|
||||
deviceName = require('os').platform();
|
||||
} else if (platformInfo.isCordova) {
|
||||
deviceName = device.model;
|
||||
}
|
||||
var json = {
|
||||
method: 'createToken',
|
||||
params: {
|
||||
secret: pairData.secret,
|
||||
version: 2,
|
||||
deviceName: deviceName,
|
||||
code: pairData.otp
|
||||
}
|
||||
};
|
||||
|
||||
bitpayService.postAuth(json, function(data) {
|
||||
if (data && data.data.error) {
|
||||
return cb(data.data.error);
|
||||
}
|
||||
var apiContext = {
|
||||
token: data.data.data,
|
||||
pairData: pairData,
|
||||
appIdentity: data.appIdentity
|
||||
};
|
||||
$log.info('BitPay service BitAuth create token: SUCCESS');
|
||||
|
||||
fetchBasicInfo(apiContext, function(err, basicInfo) {
|
||||
if (err) return cb(err);
|
||||
var title = gettextCatalog.getString('Add BitPay Account?');
|
||||
var msgDetail = 'Add this BitPay account ({{email}})?';
|
||||
if (pairingReason) {
|
||||
msgDetail = 'To {{reason}} you must first add your BitPay account.<br/><br/>{{email}}';
|
||||
}
|
||||
var msg = gettextCatalog.getString(msgDetail, {
|
||||
reason: pairingReason,
|
||||
email: pairData.email
|
||||
});
|
||||
var ok = gettextCatalog.getString('Add Account');
|
||||
var cancel = gettextCatalog.getString('Go back');
|
||||
popupService.showConfirm(title, msg, ok, cancel, function(res) {
|
||||
if (res) {
|
||||
var acctData = {
|
||||
token: apiContext.token,
|
||||
email: pairData.email,
|
||||
givenName: basicInfo.givenName,
|
||||
familyName: basicInfo.familyName
|
||||
};
|
||||
setBitpayAccount(acctData, function(err) {
|
||||
return cb(err, true, apiContext);
|
||||
});
|
||||
} else {
|
||||
$log.info('User cancelled BitPay pairing process');
|
||||
return cb(null, false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}, function(data) {
|
||||
return cb(_setError('BitPay service BitAuth create token: ERROR ', data));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var checkOtp = function(pairData, cb) {
|
||||
if (pairData.otp) {
|
||||
var msg = gettextCatalog.getString('Enter Two Factor for your BitPay account');
|
||||
popupService.showPrompt(null, msg, null, function(res) {
|
||||
cb(res);
|
||||
});
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
};
|
||||
|
||||
var fetchBasicInfo = function(apiContext, cb) {
|
||||
var json = {
|
||||
method: 'getBasicInfo'
|
||||
};
|
||||
// Get basic account information
|
||||
bitpayService.post('/api/v2/' + apiContext.token, json, function(data) {
|
||||
if (data && data.data.error) return cb(data.data.error);
|
||||
$log.info('BitPay Account Get Basic Info: SUCCESS');
|
||||
return cb(null, data.data.data);
|
||||
}, function(data) {
|
||||
return cb(_setError('BitPay Account Error: Get Basic Info', data));
|
||||
});
|
||||
};
|
||||
|
||||
// Returns account objects as stored.
|
||||
root.getAccountsAsStored = function(cb) {
|
||||
storageService.getBitpayAccounts(bitpayService.getEnvironment().network, cb);
|
||||
};
|
||||
|
||||
// Returns an array where each element represents an account including all information required for fetching data
|
||||
// from the server for each account (apiContext).
|
||||
root.getAccounts = function(cb) {
|
||||
root.getAccountsAsStored(function(err, accounts) {
|
||||
if (err || !accounts) {
|
||||
return cb(err, []);
|
||||
}
|
||||
appIdentityService.getIdentity(bitpayService.getEnvironment().network, function(err, appIdentity) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
var accountsArray = [];
|
||||
lodash.forEach(Object.keys(accounts), function(key) {
|
||||
accounts[key].bitpayDebitCards = accounts[key]['bitpayDebitCards-' + bitpayService.getEnvironment().network];
|
||||
accounts[key].email = key;
|
||||
accounts[key].firstName = accounts[key]['basicInfo-' + bitpayService.getEnvironment().network].givenName;
|
||||
accounts[key].lastName = accounts[key]['basicInfo-' + bitpayService.getEnvironment().network].familyName;
|
||||
accounts[key].apiContext = {
|
||||
token: accounts[key]['bitpayApi-' + bitpayService.getEnvironment().network].token,
|
||||
pairData: {
|
||||
email: key
|
||||
},
|
||||
appIdentity: appIdentity
|
||||
};
|
||||
|
||||
// Remove environment keyed attributes.
|
||||
delete accounts[key]['bitpayApi-' + bitpayService.getEnvironment().network];
|
||||
delete accounts[key]['bitpayDebitCards-' + bitpayService.getEnvironment().network];
|
||||
|
||||
accountsArray.push(accounts[key]);
|
||||
});
|
||||
return cb(null, accountsArray);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var setBitpayAccount = function(account, cb) {
|
||||
var data = JSON.stringify(account);
|
||||
storageService.setBitpayAccount(bitpayService.getEnvironment().network, data, function(err) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb();
|
||||
});
|
||||
};
|
||||
|
||||
root.removeAccount = function(account, cb) {
|
||||
storageService.removeBitpayAccount(bitpayService.getEnvironment().network, account, function(err) {
|
||||
if (err) {
|
||||
$log.error('Error removing BitPay account: ' + err);
|
||||
// Continue, try to remove next step if necessary
|
||||
}
|
||||
storageService.getBitpayDebitCards(bitpayService.getEnvironment().network, function(err, cards) {
|
||||
if (err) {
|
||||
$log.error('Error attempting to get BitPay debit cards after account removal: ' + err);
|
||||
}
|
||||
if (cards.length == 0) {
|
||||
storageService.removeNextStep('BitpayCard', cb);
|
||||
} else {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var _setError = function(msg, e) {
|
||||
$log.error(msg);
|
||||
var error = (e && e.data && e.data.error) ? e.data.error : msg;
|
||||
return error;
|
||||
};
|
||||
|
||||
return root;
|
||||
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue