copay-crown
Version:
A Secure Crown Wallet
215 lines (192 loc) • 7.24 kB
text/typescript
import { Injectable } from '@angular/core';
import { Logger } from '@nsalaun/ng-logger';
// providers
import { AppIdentityProvider } from '../app-identity/app-identity';
import { BitPayCardProvider } from '../bitpay-card/bitpay-card';
import { BitPayProvider } from '../bitpay/bitpay';
import { PersistenceProvider } from '../persistence/persistence';
import { PlatformProvider } from '../platform/platform';
import { PopupProvider } from '../popup/popup';
import * as _ from 'lodash';
()
export class BitPayAccountProvider {
/*
* 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
* }
*/
constructor(
private platformProvider: PlatformProvider,
private bitPayProvider: BitPayProvider,
private logger: Logger,
private popupProvider: PopupProvider,
private persistenceProvider: PersistenceProvider,
private appIdentityProvider: AppIdentityProvider,
private bitPayCardProvider: BitPayCardProvider
) {
}
public pair(pairData: any, pairingReason: string, cb: (err: string, paired?: boolean, apiContext?: any) => any) {
this.checkOtp(pairData, (otp) => {
pairData.otp = otp;
let deviceName = 'Unknown device';
if (this.platformProvider.isNW) {
deviceName = require('os').platform();
} else if (this.platformProvider.isCordova) {
// TODO deviceName = this.platformProvider.device.model;
deviceName = '';
}
let json = {
method: 'createToken',
params: {
secret: pairData.secret,
version: 2,
deviceName,
code: pairData.otp
}
};
this.bitPayProvider.postAuth(json, (data) => {
if (data && data.error) {
return cb(data.error);
}
let apiContext = {
token: data.data,
pairData,
appIdentity: data.appIdentity
};
this.logger.info('BitPay service BitAuth create token: SUCCESS');
this.fetchBasicInfo(apiContext, (err, basicInfo) => {
if (err) return cb(err);
let title = 'Add BitPay Account?'; // TODO gettextcatalog
let msg;
if (pairingReason) {
let reason = pairingReason;
let email = pairData.email;
msg = 'To ' + reason + ' you must first add your BitPay account - ' + email; // TODO gettextcatalog
} else {
let email = pairData.email;
msg = 'Add this BitPay account ' + '(' + email + ')?'; // TODO gettextcatalog
}
let ok = 'Add Account'; // TODO gettextcatalog
let cancel = 'Go back'; // TODO gettextcatalog
this.popupProvider.ionicConfirm(title, msg, ok, cancel).then((res) => {
if (res) {
let acctData = {
token: apiContext.token,
email: pairData.email,
givenName: basicInfo.givenName,
familyName: basicInfo.familyName
};
this.setBitpayAccount(acctData)
return cb(null, true, apiContext);
} else {
this.logger.info('User cancelled BitPay pairing process');
return cb(null, false);
}
});
});
}, (data) => {
return cb(this._setError('BitPay service BitAuth create token: ERROR ', data));
});
});
}
private checkOtp(pairData: any, cb: (otp?) => any) {
if (pairData.otp) {
let msg = 'Enter Two Factor for your BitPay account'; // TODO gettextcatalog
this.popupProvider.ionicPrompt(null, msg, null).then((res) => {
cb(res);
});
} else {
cb();
}
}
private fetchBasicInfo(apiContext: any, cb: (err, basicInfo?) => any) {
let json = {
method: 'getBasicInfo'
};
// Get basic account information
this.bitPayProvider.post('/api/v2/' + apiContext.token, json, (data) => {
if (data && data.error) return cb(data.error);
this.logger.info('BitPay Account Get Basic Info: SUCCESS');
return cb(null, data.data);
}, (data) => {
return cb(this._setError('BitPay Account Error: Get Basic Info', data));
});
};
// Returns account objects as stored.
public getAccountsAsStored(cb: (err, accounts) => any) {
this.persistenceProvider.getBitpayAccounts(this.bitPayProvider.getEnvironment().network).then((accounts) => {
return cb(null, accounts);
}).catch((err) => {
return cb(err, []);
});
};
// Returns an array where each element represents an account including all information required for fetching data
// from the server for each account (apiContext).
public getAccounts(cb: (err, accounts?) => any) {
this.getAccountsAsStored((err, accounts) => {
if (err || _.isEmpty(accounts)) {
return cb(err, []);
}
this.appIdentityProvider.getIdentity(this.bitPayProvider.getEnvironment().network, (err, appIdentity) => {
if (err) {
return cb(err);
}
let accountsArray = [];
_.forEach(Object.keys(accounts), (key) => {
accounts[key].cards = accounts[key].cards;
accounts[key].email = key;
accounts[key].givenName = accounts[key].givenName || '';
accounts[key].familyName = accounts[key].familyName || '';
accounts[key].apiContext = {
token: accounts[key].token,
pairData: {
email: key
},
appIdentity
};
accountsArray.push(accounts[key]);
});
return cb(null, accountsArray);
});
});
};
private setBitpayAccount(account: any) {
this.persistenceProvider.setBitpayAccount(this.bitPayProvider.getEnvironment().network, account);
};
public removeAccount(email: string, cb: () => any) {
this.persistenceProvider.removeBitpayAccount(this.bitPayProvider.getEnvironment().network, email).then(() => {
this.bitPayCardProvider.register();
return cb();
});
};
private _setError(msg: string, e: any): string {
this.logger.error(msg);
let error = (e && e.data && e.data.error) ? e.data.error : msg;
return error;
};
}