Merge pull request #6893 from Gamboster/feat/walletService

Feat: Wallet service v4
This commit is contained in:
Gustavo Maximiliano Cortez 2017-10-16 09:34:59 -03:00 committed by GitHub
commit 4521286bf4
11 changed files with 1425 additions and 234 deletions

View File

@ -83,7 +83,7 @@
"angular2-template-loader": "0.6.2", "angular2-template-loader": "0.6.2",
"codecov": "2.2.0", "codecov": "2.2.0",
"html-loader": "0.4.5", "html-loader": "0.4.5",
"ionic": "3.12.0", "ionic": "3.13.0",
"jasmine-core": "2.6.4", "jasmine-core": "2.6.4",
"jasmine-spec-reporter": "4.1.1", "jasmine-spec-reporter": "4.1.1",
"karma": "1.7.0", "karma": "1.7.0",

View File

@ -61,20 +61,22 @@ import { CustomAmountPage } from '../pages/receive/custom-amount/custom-amount';
/* Providers */ /* Providers */
import { AppProvider } from '../providers/app/app'; import { AppProvider } from '../providers/app/app';
import { BwcProvider } from '../providers/bwc/bwc'; import { BwcProvider } from '../providers/bwc/bwc';
import { BwcErrorProvider } from '../providers/bwc-error/bwc-error';
import { ConfigProvider } from '../providers/config/config'; import { ConfigProvider } from '../providers/config/config';
import { DerivationPathHelperProvider } from '../providers/derivationPathHelper/derivationPathHelper';
import { FilterProvider } from '../providers/filter/filter'; import { FilterProvider } from '../providers/filter/filter';
import { LanguageProvider } from '../providers/language/language'; import { LanguageProvider } from '../providers/language/language';
import { OnGoingProcessProvider } from '../providers/on-going-process/on-going-process';
import { PersistenceProvider, persistenceProviderFactory } from '../providers/persistence/persistence'; import { PersistenceProvider, persistenceProviderFactory } from '../providers/persistence/persistence';
import { PlatformProvider } from '../providers/platform/platform'; import { PlatformProvider } from '../providers/platform/platform';
import { PopupProvider } from '../providers/popup/popup'; import { PopupProvider } from '../providers/popup/popup';
import { ProfileProvider } from '../providers/profile/profile'; import { ProfileProvider } from '../providers/profile/profile';
import { RateProvider } from '../providers/rate/rate'; import { RateProvider } from '../providers/rate/rate';
import { ReleaseProvider } from '../providers/release/release';
import { ScanProvider } from '../providers/scan/scan'; import { ScanProvider } from '../providers/scan/scan';
import { TouchIdProvider } from '../providers/touchid/touchid'; import { TouchIdProvider } from '../providers/touchid/touchid';
import { TxFormatProvider } from '../providers/tx-format/tx-format'; import { TxFormatProvider } from '../providers/tx-format/tx-format';
import { WalletProvider } from '../providers/wallet/wallet'; import { WalletProvider } from '../providers/wallet/wallet';
import { ReleaseProvider } from '../providers/release/release';
import { DerivationPathHelperProvider } from '../providers/derivationPathHelper/derivationPathHelper';
export function createTranslateLoader(http: Http) { export function createTranslateLoader(http: Http) {
return new TranslatePoHttpLoader(http, 'assets/i18n', '.po'); return new TranslatePoHttpLoader(http, 'assets/i18n', '.po');
@ -113,15 +115,19 @@ let providers: any = [
AndroidFingerprintAuth, AndroidFingerprintAuth,
AppProvider, AppProvider,
BwcProvider, BwcProvider,
BwcErrorProvider,
ConfigProvider, ConfigProvider,
Clipboard, Clipboard,
DerivationPathHelperProvider,
FilterProvider, FilterProvider,
LanguageProvider, LanguageProvider,
OnGoingProcessProvider,
PlatformProvider, PlatformProvider,
ProfileProvider, ProfileProvider,
PopupProvider, PopupProvider,
QRScanner, QRScanner,
RateProvider, RateProvider,
ReleaseProvider,
StatusBar, StatusBar,
SplashScreen, SplashScreen,
ScanProvider, ScanProvider,
@ -131,8 +137,6 @@ let providers: any = [
TouchIdProvider, TouchIdProvider,
TxFormatProvider, TxFormatProvider,
WalletProvider, WalletProvider,
ReleaseProvider,
DerivationPathHelperProvider,
{ {
provide: ErrorHandler, provide: ErrorHandler,
useClass: IonicErrorHandler useClass: IonicErrorHandler

View File

@ -115,35 +115,6 @@ export class CreateWalletPage implements OnInit{
this.formData.selectedSeed = { this.formData.selectedSeed = {
id: this.seedOptions[0].id id: this.seedOptions[0].id
}; };
/* Disable Hardware Wallets for BitPay distribution */
var opts = [];
if (this.appName == 'copay') {
// if (n > 1 && walletService.externalSource.ledger.supported)
// opts.push({
// id: walletService.externalSource.ledger.id,
// label: walletService.externalSource.ledger.longName,
// supportsTestnet: walletService.externalSource.ledger.supportsTestnet
// });
// if (walletService.externalSource.trezor.supported) {
// opts.push({
// id: walletService.externalSource.trezor.id,
// label: walletService.externalSource.trezor.longName,
// supportsTestnet: walletService.externalSource.trezor.supportsTestnet
// });
// }
// if (walletService.externalSource.intelTEE.supported) {
// opts.push({
// id: walletService.externalSource.intelTEE.id,
// label: walletService.externalSource.intelTEE.longName,
// supportsTestnet: walletService.externalSource.intelTEE.supportsTestnet
// });
// }
}
this.seedOptions = this.seedOptions.concat(opts);
}; };
seedOptionsChange(seed: any) { seedOptionsChange(seed: any) {

View File

@ -0,0 +1,19 @@
import { Injectable } from '@angular/core';
@Injectable()
export class BwcErrorProvider {
constructor() {
console.log('Hello BwcErrorProvider Provider');
}
//TODO
msg(err: any, prefix?: string){
return "TODO: bwcError msg(err, prefix)";
}
cb(err: string, prefix?: string): Promise<any> {
return new Promise((resolve, reject)=> {
resolve(this.msg(err, prefix));
});
};
}

View File

@ -0,0 +1,14 @@
import { Injectable } from '@angular/core';
@Injectable()
export class OnGoingProcessProvider {
constructor() {
console.log('Hello OnGoingProcessProvider Provider');
}
public set (processName: string, isOn: boolean, customHandler?: any) {
console.log('TODO: OnGoingProcessProvider set()...');
}
}

View File

@ -12,12 +12,7 @@ export class PlatformProvider {
isNW: boolean; isNW: boolean;
ua: string; ua: string;
isMobile: boolean; isMobile: boolean;
isChromeApp: boolean;
isDevel: boolean; isDevel: boolean;
supportsLedger: boolean;
supportsTrezor: boolean;
versionIntelTEE: string;
supportsIntelTEE: boolean;
constructor(private platform: Platform, private log: Logger) { constructor(private platform: Platform, private log: Logger) {
let chrome: any; let chrome: any;
@ -38,12 +33,7 @@ export class PlatformProvider {
this.isCordova = platform.is('cordova'); this.isCordova = platform.is('cordova');
this.isNW = this.isNodeWebkit(); this.isNW = this.isNodeWebkit();
this.isMobile = platform.is('mobile'); this.isMobile = platform.is('mobile');
this.isChromeApp = this.getBrowserName() == 'chrome' && chrome && chrome.runtime && chrome.runtime.id && !this.isNW; this.isDevel = !this.isMobile && !this.isNW;
this.isDevel = !this.isMobile && !this.isChromeApp && !this.isNW;
this.supportsLedger = this.isChromeApp;
this.supportsTrezor = this.isChromeApp || this.isDevel;
this.versionIntelTEE = this.getVersionIntelTee();
this.supportsIntelTEE = this.versionIntelTEE.length > 0;
} }
getBrowserName(): string { getBrowserName(): string {
@ -70,26 +60,4 @@ export class PlatformProvider {
} }
} }
} }
getVersionIntelTee(): string {
let v = '';
let isWindows = navigator.platform.indexOf('Win') > -1;
if (!this.isNodeWebkit() || !isWindows) {
return v;
}
try {
var IntelWallet = require('intelWalletCon');
if (IntelWallet.getVersion) {
v = IntelWallet.getVersion();
} else {
v = 'Alpha';
}
if (v.length > 0) {
this.log.info('Intel TEE library ' + v);
}
} catch (e) { }
return v;
}
} }

View File

@ -6,7 +6,7 @@ export class PopupProvider {
constructor(public alertCtrl: AlertController) { constructor(public alertCtrl: AlertController) {
} }
ionicAlert(title, subTitle, okText): void { ionicAlert(title: string, subTitle?: string, okText?: string): void {
let alert = this.alertCtrl.create({ let alert = this.alertCtrl.create({
title: title, title: title,
subTitle: subTitle, subTitle: subTitle,
@ -37,32 +37,35 @@ export class PopupProvider {
confirm.present(); confirm.present();
}; };
ionicPrompt(title, message, okText, cancelText, opts) { ionicPrompt(title: string, message: string, okText?: string, cancelText?: string): Promise<any> {
opts = opts || {}; return new Promise((resolve, reject) => {
let prompt = this.alertCtrl.create({ let prompt = this.alertCtrl.create({
title: title, title: title,
message: message, message: message,
inputs: [ inputs: [
{ {
name: 'title', name: 'title',
placeholder: 'Title' placeholder: 'Title'
}, },
], ],
buttons: [ buttons: [
{ {
text: cancelText, text: cancelText,
handler: data => { handler: data => {
console.log('Cancel clicked'); console.log('Cancel clicked');
reject(data);
}
},
{
text: okText,
handler: data => {
console.log('Saved clicked');
resolve(data);
}
} }
}, ]
{ });
text: okText, prompt.present();
handler: data => {
console.log('Saved clicked');
}
}
]
}); });
prompt.present();
} }
} }

View File

@ -72,9 +72,9 @@ export class ProfileProvider {
if (!l) return wallets; if (!l) return wallets;
let credentials = this.profile.credentials; let credentials = this.profile.credentials;
_.each(credentials, (credential) => { /*_.each(credentials, (credential) => {
wallets.push(this.wallet.bind(credential)); wallets.push(this.wallet.bind(credential));
}); }); */
return wallets; return wallets;
} }

View File

@ -12,10 +12,11 @@ export class RateProvider {
private _ratesBCH: Object; private _ratesBCH: Object;
private SAT_TO_BTC: any; private SAT_TO_BTC: any;
private BTC_TO_SAT: any; private BTC_TO_SAT: any;
private _isAvailable: boolean = false;
private rateServiceUrl = 'https://bitpay.com/api/rates'; private rateServiceUrl = 'https://bitpay.com/api/rates';
private bchRateServiceUrl = 'https://api.kraken.com/0/public/Ticker?pair=BCHUSD,BCHEUR'; private bchRateServiceUrl = 'https://api.kraken.com/0/public/Ticker?pair=BCHUSD,BCHEUR';
constructor(public http: Http) { constructor(public http: Http) {
console.log('Hello RateProvider Provider'); console.log('Hello RateProvider Provider');
this._rates = {}; this._rates = {};
@ -48,6 +49,7 @@ export class RateProvider {
self._ratesBCH[code] = rate; self._ratesBCH[code] = rate;
}); });
this._isAvailable = true;
resolve(); resolve();
}) })
.catch((errorBCH) => { .catch((errorBCH) => {
@ -112,4 +114,17 @@ export class RateProvider {
return _.uniqBy(alternatives, 'isoCode'); return _.uniqBy(alternatives, 'isoCode');
}; };
//TODO IMPROVE WHEN AVAILABLE
whenAvailable() {
return new Promise((resolve, reject)=> {
if (this._isAvailable) resolve();
else {
this.updateRates().then(()=>{
resolve();
});
}
});
}
} }

View File

@ -1,5 +1,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { PlatformProvider } from '../platform/platform'; import { PlatformProvider } from '../platform/platform';
import { ConfigProvider } from '../config/config';
import { TouchID } from '@ionic-native/touch-id'; import { TouchID } from '@ionic-native/touch-id';
import { AndroidFingerprintAuth } from '@ionic-native/android-fingerprint-auth'; import { AndroidFingerprintAuth } from '@ionic-native/android-fingerprint-auth';
@ -7,95 +8,114 @@ import { AndroidFingerprintAuth } from '@ionic-native/android-fingerprint-auth';
@Injectable() @Injectable()
export class TouchIdProvider { export class TouchIdProvider {
private _isAvailable: boolean = false; private _isAvailable: boolean = false;
constructor( constructor(
private touchId: TouchID, private touchId: TouchID,
private androidFingerprintAuth: AndroidFingerprintAuth, private androidFingerprintAuth: AndroidFingerprintAuth,
private platform: PlatformProvider private platform: PlatformProvider,
) { } private config: ConfigProvider
) { }
init() { init() {
if (this.platform.isAndroid) this.checkAndroid(); if (this.platform.isAndroid) this.checkAndroid();
if (this.platform.isIOS) this.checkIOS(); if (this.platform.isIOS) this.checkIOS();
} }
checkIOS() { checkIOS() {
this.touchId.isAvailable() this.touchId.isAvailable()
.then( .then(
res => this._isAvailable = true, res => this._isAvailable = true,
err => console.log("Fingerprint is not available") err => console.log("Fingerprint is not available")
); );
} }
checkAndroid() { checkAndroid() {
this.androidFingerprintAuth.isAvailable() this.androidFingerprintAuth.isAvailable()
.then( .then(
res => { res => {
if (res.isAvailable) this._isAvailable = true if (res.isAvailable) this._isAvailable = true
else console.log("Fingerprint is not available") else console.log("Fingerprint is not available")
}); });
} }
verifyIOSFingerprint(): Promise<any> { verifyIOSFingerprint(): Promise<any> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.touchId.verifyFingerprint('Scan your fingerprint please') this.touchId.verifyFingerprint('Scan your fingerprint please')
.then( .then(
res => resolve(), res => resolve(),
err => reject() err => reject()
); );
});
}
verifyAndroidFingerprint(): Promise<any> {
return new Promise((resolve, reject) => {
this.androidFingerprintAuth.encrypt({ clientId: 'Copay' })
.then(result => {
if (result.withFingerprint) {
console.log('Successfully authenticated with fingerprint.');
resolve();
} else if (result.withBackup) {
console.log('Successfully authenticated with backup password!');
resolve();
} else console.log('Didn\'t authenticate!');
}).catch(error => {
if (error === this.androidFingerprintAuth.ERRORS.FINGERPRINT_CANCELLED) {
console.log('Fingerprint authentication cancelled');
reject();
} else {
console.error(error);
resolve();
};
}); });
} });
}
verifyAndroidFingerprint(): Promise<any> { isAvailable() {
return new Promise((resolve, reject) => { return this._isAvailable;
this.androidFingerprintAuth.encrypt({ clientId: 'Copay' }) }
.then(result => {
if (result.withFingerprint) { check(): Promise<any> {
console.log('Successfully authenticated with fingerprint.'); return new Promise((resolve, reject) => {
resolve(); if (!this.isAvailable()) reject();
} else if (result.withBackup) { if (this.platform.isIOS) {
console.log('Successfully authenticated with backup password!'); this.verifyIOSFingerprint()
resolve(); .then(() => {
} else console.log('Didn\'t authenticate!'); resolve();
}) })
.catch(error => { .catch(() => {
if (error === this.androidFingerprintAuth.ERRORS.FINGERPRINT_CANCELLED) { reject();
console.log('Fingerprint authentication cancelled'); });
reject(); };
} else { if (this.platform.isAndroid) {
console.error(error); this.verifyAndroidFingerprint()
resolve(); .then(() => {
} resolve();
}); })
.catch(() => {
reject();
});
};
});
}
isNeeded(wallet: any) {
let config: any = this.config.get();
config.touchIdFor = config.touchIdFor || {};
return config.touchIdFor[wallet.credentials.walletId];
}
checkWallet(wallet: any): Promise<any> {
return new Promise((resolve, reject) => {
if (!this.isAvailable()) reject();
if (this.isNeeded(wallet)) {
this.check().then(() => {
resolve();
}).catch(() => {
reject();
}); });
} };
});
isAvailable() { }
return this._isAvailable;
}
check(): Promise<any> {
return new Promise((resolve, reject) => {
if (!this.isAvailable()) reject();
if (this.platform.isIOS) {
this.verifyIOSFingerprint()
.then(() => {
resolve();
})
.catch(() => {
reject();
});
}
if (this.platform.isAndroid) {
this.verifyAndroidFingerprint()
.then(() => {
resolve();
})
.catch(() => {
reject();
});
}
});
}
} }

File diff suppressed because it is too large Load Diff