mirror of https://github.com/BTCPrivate/copay.git
Merge pull request #6893 from Gamboster/feat/walletService
Feat: Wallet service v4
This commit is contained in:
commit
4521286bf4
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
|
@ -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()...');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ 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';
|
||||||
|
@ -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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
Loading…
Reference in New Issue