Browse Source

ADD: Biometrics

FIX: Added FaceID Usage description

ADD: Use Biometrics for Show balance.

ADD: Unlock With Boot Screen

FIX: Allow the use of Biometrics after decrypt

FIX: Build system revert.

FIX: Remove biometric from receive address.

ADD: Biometric for export

FIX: Use RNSecureKeyStore for biometrics

FIX: Realign views

Update biometrics.js
bip70fix
Marcos Rodriguez 5 years ago
parent
commit
29ce0271f8
  1. 10
      BlueComponents.js
  2. 97
      UnlockWith.js
  3. 2
      android/app/build.gradle
  4. 51
      class/biometrics.js
  5. BIN
      img/faceid.png
  6. BIN
      img/fingerprint.png
  7. 13
      index.js
  8. 18
      ios/BlueWallet.xcodeproj/project.pbxproj
  9. 22
      ios/BlueWallet.xcodeproj/xcshareddata/xcschemes/BlueWallet.xcscheme
  10. 8
      ios/BlueWallet.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
  11. 4
      ios/BlueWallet/Info.plist
  12. 2
      ios/BlueWalletWatch Extension/Info.plist
  13. 2
      ios/BlueWalletWatch/Info.plist
  14. 6
      ios/Podfile.lock
  15. 9
      package-lock.json
  16. 3
      package.json
  17. 9
      screen/lnd/scanLndInvoice.js
  18. 24
      screen/send/confirm.js
  19. 26
      screen/settings/settings.js
  20. 9
      screen/wallets/details.js
  21. 14
      screen/wallets/export.js
  22. 1
      screen/wallets/walletMigrate.js
  23. 14
      screen/wallets/xpub.js

10
BlueComponents.js

@ -33,6 +33,7 @@ import ToolTip from 'react-native-tooltip';
import { BlurView } from '@react-native-community/blur';
import showPopupMenu from 'react-native-popup-menu-android';
import NetworkTransactionFees, { NetworkTransactionFeeType } from './models/networkTransactionFees';
import Biometric from './class/biometrics';
let loc = require('./loc/');
/** @type {AppStorage} */
let BlueApp = require('./BlueApp');
@ -179,6 +180,15 @@ export class BlueWalletNavigationHeader extends Component {
handleBalanceVisibility = async _item => {
const wallet = this.state.wallet;
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled && wallet.hideBalance) {
if (!(await Biometric.unlockWithBiometrics())) {
return this.props.navigation.goBack();
}
}
wallet.hideBalance = !wallet.hideBalance;
this.setState({ wallet });
await BlueApp.saveToDisk();

97
UnlockWith.js

@ -0,0 +1,97 @@
import React, { Component } from 'react';
import { View, Image, TouchableOpacity } from 'react-native';
import { Icon } from 'react-native-elements';
import Biometric from './class/biometrics';
import PropTypes from 'prop-types';
import Biometrics from 'react-native-biometrics';
import { SafeAreaView } from 'react-navigation';
/** @type {AppStorage} */
const BlueApp = require('./BlueApp');
export default class UnlockWith extends Component {
state = { biometricType: false, isStorageEncrypted: false, isAuthenticating: false };
async componentDidMount() {
let biometricType = false;
const isStorageEncrypted = await BlueApp.storageIsEncrypted();
if ((await Biometric.isBiometricUseCapableAndEnabled()) && !isStorageEncrypted) {
biometricType = await Biometric.biometricType();
}
this.setState({ biometricType, isStorageEncrypted }, async () => {
if (!biometricType) {
await BlueApp.startAndDecrypt();
this.props.onSuccessfullyAuthenticated();
} else if (biometricType !== false && !isStorageEncrypted) this.unlockWithBiometrics();
});
}
successfullyAuthenticated = () => {
this.props.onSuccessfullyAuthenticated();
};
unlockWithBiometrics = () => {
this.setState({ isAuthenticating: true }, async () => {
if (await Biometric.unlockWithBiometrics()) {
await BlueApp.startAndDecrypt();
return this.props.onSuccessfullyAuthenticated();
}
this.setState({ isAuthenticating: false });
});
};
render() {
if (!this.state.biometricType && !this.state.isStorageEncrypted) {
return <View />;
}
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 2, justifyContent: 'space-between', alignItems: 'center' }}>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Image source={require('./img/qr-code.png')} style={{ width: 120, height: 120 }} />
</View>
<View style={{ flex: 0.1, justifyContent: 'flex-end', marginBottom: 64 }}>
<View style={{ justifyContent: 'center', flexDirection: 'row' }}>
{this.state.biometricType === Biometrics.TouchID && (
<>
<TouchableOpacity disabled={this.state.isAuthenticating} onPress={this.unlockWithBiometrics}>
<Image source={require('./img/fingerprint.png')} style={{ width: 64, height: 64 }} />
</TouchableOpacity>
</>
)}
{this.state.biometricType === Biometrics.FaceID && (
<>
<TouchableOpacity disabled={this.state.isAuthenticating} onPress={this.unlockWithBiometrics}>
<Image source={require('./img/faceid.png')} style={{ width: 64, height: 64 }} />
</TouchableOpacity>
</>
)}
{this.state.biometricType !== false && this.state.isStorageEncrypted && (
<View style={{ backgroundColor: 'gray', width: 0.5, height: 20, marginHorizontal: 16 }} />
)}
{this.state.isStorageEncrypted && (
<>
<TouchableOpacity
disabled={this.state.isAuthenticating}
onPress={() => {
this.setState({ isAuthenticating: true }, async () => {
await BlueApp.startAndDecrypt();
this.props.onSuccessfullyAuthenticated();
});
}}
>
<Icon name="key" size={64} type="font-awesome" />
</TouchableOpacity>
</>
)}
</View>
</View>
</View>
</SafeAreaView>
);
}
}
UnlockWith.propTypes = {
onSuccessfullyAuthenticated: PropTypes.func,
};

2
android/app/build.gradle

@ -118,7 +118,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "4.5.0"
versionName "4.5.1"
multiDexEnabled true
missingDimensionStrategy 'react-native-camera', 'general'
}

51
class/biometrics.js

@ -0,0 +1,51 @@
import Biometrics from 'react-native-biometrics';
const BlueApp = require('../BlueApp');
export default class Biometric {
static STORAGEKEY = 'Biometrics';
static async isDeviceBiometricCapable() {
if ((await Biometrics.isSensorAvailable()) !== null) {
return true;
}
Biometric.setBiometricUseEnabled(false);
return false;
}
static async biometricType() {
return Biometrics.isSensorAvailable();
}
static async isBiometricUseEnabled() {
try {
const enabledBiometrics = await BlueApp.getItem(Biometric.STORAGEKEY);
return !!enabledBiometrics;
} catch (_e) {
await BlueApp.setItem(Biometric.STORAGEKEY, '');
return !!'';
}
}
static async isBiometricUseCapableAndEnabled() {
const isBiometricUseEnabled = await Biometric.isBiometricUseEnabled();
const isDeviceBiometricCapable = await Biometric.isDeviceBiometricCapable();
return !!isBiometricUseEnabled && isDeviceBiometricCapable;
}
static async setBiometricUseEnabled(value) {
await BlueApp.setItem(Biometric.STORAGEKEY, value === true ? '1' : '');
}
static async unlockWithBiometrics() {
const isDeviceBiometricCapable = await Biometric.isDeviceBiometricCapable();
if (isDeviceBiometricCapable) {
try {
await Biometrics.simplePrompt('Please confirm your identity.');
return true;
} catch (_e) {
return false;
}
}
return false;
}
}

BIN
img/faceid.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
img/fingerprint.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

13
index.js

@ -2,15 +2,15 @@ import 'intl';
import 'intl/locale-data/jsonp/en';
import React from 'react';
import './shim.js';
import App from './App';
import { Sentry } from 'react-native-sentry';
import { AppRegistry } from 'react-native';
import WalletMigrate from './screen/wallets/walletMigrate';
import { name as appName } from './app.json';
import App from './App';
import LottieView from 'lottie-react-native';
import UnlockWith from './UnlockWith.js';
/** @type {AppStorage} */
const BlueApp = require('./BlueApp');
let A = require('./analytics');
if (process.env.NODE_ENV !== 'development') {
Sentry.config('https://23377936131848ca8003448a893cb622@sentry.io/1295736').install();
@ -24,7 +24,7 @@ if (!Error.captureStackTrace) {
class BlueAppComponent extends React.Component {
constructor(props) {
super(props);
this.state = { isMigratingData: true, onAnimationFinished: false };
this.state = { isMigratingData: true, onAnimationFinished: false, successfullyAuthenticated: false };
}
componentDidMount() {
@ -33,7 +33,6 @@ class BlueAppComponent extends React.Component {
}
setIsMigratingData = async () => {
await BlueApp.startAndDecrypt();
A(A.ENUM.INIT);
this.setState({ isMigratingData: false });
};
@ -46,6 +45,10 @@ class BlueAppComponent extends React.Component {
}
};
onSuccessfullyAuthenticated = () => {
this.setState({ successfullyAuthenticated: true })
}
render() {
if (this.state.isMigratingData) {
return (
@ -59,7 +62,7 @@ class BlueAppComponent extends React.Component {
);
} else {
if (this.state.onAnimationFinished) {
return <App />;
return this.state.successfullyAuthenticated ? <App /> : <UnlockWith onSuccessfullyAuthenticated={this.onSuccessfullyAuthenticated} />;
} else {
return (
<LottieView

18
ios/BlueWallet.xcodeproj/project.pbxproj

@ -630,7 +630,7 @@
13B07F861A680F5B00A75B9A = {
DevelopmentTeam = A7W54YZ4WU;
LastSwiftMigration = 1030;
ProvisioningStyle = Manual;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.Keychain = {
enabled = 0;
@ -1132,11 +1132,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = A7W54YZ4WU;
DEVELOPMENT_TEAM = "";
HEADER_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = BlueWallet/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
@ -1152,7 +1152,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet;
PRODUCT_NAME = BlueWallet;
PROVISIONING_PROFILE_SPECIFIER = "io.bluewallet.bluewallet AppStore";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "BlueWallet-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.2;
@ -1167,10 +1167,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = A7W54YZ4WU;
DEVELOPMENT_TEAM = "";
HEADER_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = BlueWallet/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
@ -1186,7 +1186,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet;
PRODUCT_NAME = BlueWallet;
PROVISIONING_PROFILE_SPECIFIER = "io.bluewallet.bluewallet AppStore";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "BlueWallet-Bridging-Header.h";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";

22
ios/BlueWallet.xcodeproj/xcshareddata/xcschemes/BlueWallet.xcscheme

@ -27,6 +27,15 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "BlueWallet.app"
BlueprintName = "BlueWallet"
ReferencedContainer = "container:BlueWallet.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
@ -39,17 +48,6 @@
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "BlueWallet.app"
BlueprintName = "BlueWallet"
ReferencedContainer = "container:BlueWallet.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@ -71,8 +69,6 @@
ReferencedContainer = "container:BlueWallet.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

8
ios/BlueWallet.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

4
ios/BlueWallet/Info.plist

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>4.5.0</string>
<string>4.5.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
@ -56,6 +56,8 @@
</dict>
<key>NSAppleMusicUsageDescription</key>
<string>This alert should not show up as we do not require this data</string>
<key>NSFaceIDUsageDescription</key>
<string>In order to confirm your identity, we need your permission to use FaceID.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This alert should not show up as we do not require this data</string>
<key>NSCalendarsUsageDescription</key>

2
ios/BlueWalletWatch Extension/Info.plist

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>4.5.0</string>
<string>4.5.1</string>
<key>CFBundleVersion</key>
<string>239</string>
<key>CLKComplicationPrincipalClass</key>

2
ios/BlueWalletWatch/Info.plist

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>4.5.0</string>
<string>4.5.1</string>
<key>CFBundleVersion</key>
<string>239</string>
<key>UISupportedInterfaceOrientations</key>

6
ios/Podfile.lock

@ -84,6 +84,8 @@ PODS:
- React-cxxreact (= 0.60.5)
- React-jsi (= 0.60.5)
- React-jsinspector (0.60.5)
- react-native-biometrics (1.6.1):
- React
- react-native-blur (0.8.0):
- React
- react-native-camera (3.4.0):
@ -178,6 +180,7 @@ DEPENDENCIES:
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- react-native-biometrics (from `../node_modules/react-native-biometrics`)
- "react-native-blur (from `../node_modules/@react-native-community/blur`)"
- react-native-camera (from `../node_modules/react-native-camera`)
- react-native-haptic-feedback (from `../node_modules/react-native-haptic-feedback`)
@ -253,6 +256,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
React-jsinspector:
:path: "../node_modules/react-native/ReactCommon/jsinspector"
react-native-biometrics:
:path: "../node_modules/react-native-biometrics"
react-native-blur:
:path: "../node_modules/@react-native-community/blur"
react-native-camera:
@ -338,6 +343,7 @@ SPEC CHECKSUMS:
React-jsi: 4d8c9efb6312a9725b18d6fc818ffc103f60fec2
React-jsiexecutor: 90ad2f9db09513fc763bc757fdc3c4ff8bde2a30
React-jsinspector: e08662d1bf5b129a3d556eb9ea343a3f40353ae4
react-native-biometrics: 4aaf49f9f8bd28c6aa3ec53534ca1b6b00486f6a
react-native-blur: cad4d93b364f91e7b7931b3fa935455487e5c33c
react-native-camera: 203091b4bf99d48b788a0682ad573e8718724893
react-native-haptic-feedback: 22c9dc85fd8059f83bf9edd9212ac4bd4ae6074d

9
package-lock.json

@ -1,6 +1,6 @@
{
"name": "BlueWallet",
"version": "4.5.0",
"version": "4.5.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -10686,6 +10686,11 @@
"prop-types": "^15.5.10"
}
},
"react-native-biometrics": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/react-native-biometrics/-/react-native-biometrics-1.6.1.tgz",
"integrity": "sha512-WYdZ6k3Miyl/+lEdhq6y4B6wz16d+PomO/xjR1hScYKeQWj1jaugPy0Ep+EjoWpJkPYLvnxasmIYR9v8OvWNHg=="
},
"react-native-camera": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-3.4.0.tgz",
@ -13293,4 +13298,4 @@
}
}
}
}
}

3
package.json

@ -1,6 +1,6 @@
{
"name": "BlueWallet",
"version": "4.5.0",
"version": "4.5.1",
"devDependencies": {
"@babel/core": "^7.5.0",
"@babel/runtime": "^7.5.1",
@ -84,6 +84,7 @@
"react": "16.8.6",
"react-localization": "1.0.13",
"react-native": "0.60.5",
"react-native-biometrics": "^1.6.1",
"react-native-camera": "3.4.0",
"react-native-device-info": "2.2.2",
"react-native-elements": "0.19.0",

9
screen/lnd/scanLndInvoice.js

@ -15,6 +15,7 @@ import { LightningCustodianWallet } from '../../class/lightning-custodian-wallet
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
import { Icon } from 'react-native-elements';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import Biometric from '../../class/biometrics';
/** @type {AppStorage} */
let BlueApp = require('../../BlueApp');
let EV = require('../../events');
@ -143,6 +144,14 @@ export default class ScanLndInvoice extends React.Component {
return null;
}
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) {
if (!(await Biometric.unlockWithBiometrics())) {
return;
}
}
this.setState(
{
isLoading: true,

24
screen/send/confirm.js

@ -6,6 +6,7 @@ import { BlueButton, BlueText, SafeBlueArea, BlueCard, BlueSpacing40, BlueNaviga
import { BitcoinUnit } from '../../models/bitcoinUnits';
import PropTypes from 'prop-types';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import Biometric from '../../class/biometrics';
let loc = require('../../loc');
let EV = require('../../events');
let currency = require('../../currency');
@ -46,6 +47,15 @@ export default class Confirm extends Component {
try {
await BlueElectrum.ping();
await BlueElectrum.waitTillConnected();
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) {
if (!(await Biometric.unlockWithBiometrics())) {
return;
}
}
let result = await this.state.fromWallet.broadcastTx(this.state.tx);
if (result && result.code) {
if (result.code === 1) {
@ -163,7 +173,15 @@ export default class Confirm extends Component {
<TouchableOpacity
style={{ marginVertical: 24 }}
onPress={() =>
onPress={async () => {
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) {
if (!(await Biometric.unlockWithBiometrics())) {
return;
}
}
this.props.navigation.navigate('CreateTransaction', {
fee: this.state.fee,
recipients: this.state.recipients,
@ -172,8 +190,8 @@ export default class Confirm extends Component {
satoshiPerByte: this.state.satoshiPerByte,
wallet: this.state.fromWallet,
feeSatoshi: this.state.feeSatoshi,
})
}
});
}}
>
<Text style={{ color: '#0c2550', fontSize: 15, fontWeight: '500', alignSelf: 'center' }}>
{loc.transactions.details.transaction_details}

26
screen/settings/settings.js

@ -12,6 +12,7 @@ import {
import AsyncStorage from '@react-native-community/async-storage';
import PropTypes from 'prop-types';
import { AppStorage } from '../../class';
import Biometric from '../../class/biometrics';
let loc = require('../../loc');
export default class Settings extends Component {
@ -24,14 +25,19 @@ export default class Settings extends Component {
this.state = {
isLoading: true,
language: loc.getLanguage(),
biometrics: { isDeviceBiometricCapable: false, isBiometricsEnabled: false },
};
}
async componentDidMount() {
let advancedModeEnabled = !!(await AsyncStorage.getItem(AppStorage.ADVANCED_MODE_ENABLED));
const advancedModeEnabled = !!(await AsyncStorage.getItem(AppStorage.ADVANCED_MODE_ENABLED));
const isBiometricsEnabled = await Biometric.isBiometricUseEnabled();
const isDeviceBiometricCapable = await Biometric.isDeviceBiometricCapable();
const biometricsType = (await Biometric.biometricType()) || 'biometrics';
this.setState({
isLoading: false,
advancedModeEnabled,
biometrics: { isBiometricsEnabled, isDeviceBiometricCapable, biometricsType },
});
}
@ -44,6 +50,15 @@ export default class Settings extends Component {
this.setState({ advancedModeEnabled: value });
}
onUseBiometricSwitch = async value => {
let isBiometricsEnabled = this.state.biometrics;
if (await Biometric.unlockWithBiometrics()) {
isBiometricsEnabled.isBiometricsEnabled = value;
await Biometric.setBiometricUseEnabled(value);
this.setState({ biometrics: isBiometricsEnabled });
}
};
render() {
if (this.state.isLoading) {
return <BlueLoading />;
@ -56,6 +71,15 @@ export default class Settings extends Component {
<TouchableOpacity onPress={() => this.props.navigation.navigate('EncryptStorage')}>
<BlueListItem title={loc.settings.encrypt_storage} />
</TouchableOpacity>
{this.state.biometrics.isDeviceBiometricCapable && (
<BlueListItem
hideChevron
title={`Use ${this.state.biometrics.biometricsType}`}
switchButton
onSwitch={this.onUseBiometricSwitch}
switched={this.state.biometrics.isBiometricsEnabled}
/>
)}
<TouchableOpacity onPress={() => this.props.navigation.navigate('LightningSettings')}>
<BlueListItem title={loc.settings.lightning_settings} />
</TouchableOpacity>

9
screen/wallets/details.js

@ -9,6 +9,7 @@ import { HDLegacyP2PKHWallet } from '../../class/hd-legacy-p2pkh-wallet';
import { HDSegwitP2SHWallet } from '../../class/hd-segwit-p2sh-wallet';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import { HDSegwitBech32Wallet } from '../../class';
import Biometric from '../../class/biometrics';
let EV = require('../../events');
let prompt = require('../../prompt');
/** @type {AppStorage} */
@ -75,6 +76,14 @@ export default class WalletDetails extends Component {
'plain-text',
);
if (Number(walletBalanceConfirmation) === this.state.wallet.getBalance()) {
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) {
if (!(await Biometric.unlockWithBiometrics())) {
return;
}
}
this.props.navigation.setParams({ isLoading: true });
this.setState({ isLoading: true }, async () => {
BlueApp.deleteWallet(this.state.wallet);

14
screen/wallets/export.js

@ -5,6 +5,7 @@ import { BlueSpacing20, SafeBlueArea, BlueNavigationStyle, BlueText } from '../.
import PropTypes from 'prop-types';
import Privacy from '../../Privacy';
import SystemSetting from 'react-native-system-setting';
import Biometric from '../../class/biometrics';
/** @type {AppStorage} */
let BlueApp = require('../../BlueApp');
let loc = require('../../loc');
@ -39,11 +40,20 @@ export default class WalletExport extends Component {
async componentDidMount() {
Privacy.enableBlur();
await SystemSetting.saveBrightness();
await SystemSetting.setAppBrightness(1.0);
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) {
if (!(await Biometric.unlockWithBiometrics())) {
return this.props.navigation.goBack();
}
}
this.setState({
isLoading: false,
});
await SystemSetting.saveBrightness();
await SystemSetting.setAppBrightness(1.0);
}
async componentWillUnmount() {

1
screen/wallets/walletMigrate.js

@ -85,6 +85,7 @@ export default class WalletMigrate {
const data = await AsyncStorage.getItem('data');
if (data) {
const isEncrypted = (await AsyncStorage.getItem('data_encrypted')) || '';
await RNSecureKeyStore.set('Biometrics', '', { accessible: ACCESSIBLE.WHEN_UNLOCKED });
await RNSecureKeyStore.set('data', data, { accessible: ACCESSIBLE.WHEN_UNLOCKED });
await RNSecureKeyStore.set('data_encrypted', isEncrypted, {
accessible: ACCESSIBLE.WHEN_UNLOCKED,

14
screen/wallets/xpub.js

@ -5,6 +5,7 @@ import { BlueSpacing20, SafeBlueArea, BlueText, BlueNavigationStyle, BlueCopyTex
import PropTypes from 'prop-types';
import Privacy from '../../Privacy';
import SystemSetting from 'react-native-system-setting';
import Biometric from '../../class/biometrics';
/** @type {AppStorage} */
let BlueApp = require('../../BlueApp');
let loc = require('../../loc');
@ -41,11 +42,20 @@ export default class WalletXpub extends Component {
async componentDidMount() {
Privacy.enableBlur();
await SystemSetting.saveBrightness();
await SystemSetting.setAppBrightness(1.0);
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) {
if (!(await Biometric.unlockWithBiometrics())) {
return this.props.navigation.goBack();
}
}
this.setState({
isLoading: false,
});
await SystemSetting.saveBrightness();
await SystemSetting.setAppBrightness(1.0);
}
async componentWillUnmount() {

Loading…
Cancel
Save