ADD: Keychain clear if password is lost

This commit is contained in:
Marcos Rodriguez Vélez 2020-07-20 10:58:35 -04:00 committed by GitHub
parent e38753c86d
commit 0792add3a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 95 additions and 4 deletions

View file

@ -3,14 +3,17 @@
*/
import { AppStorage } from './class';
import DeviceQuickActions from './class/quick-actions';
import Biometric from './class/biometrics';
import { Platform } from 'react-native';
import loc from './loc';
const prompt = require('./blue_modules/prompt');
const EV = require('./blue_modules/events');
const currency = require('./blue_modules/currency');
const BlueElectrum = require('./blue_modules/BlueElectrum'); // eslint-disable-line no-unused-vars
/** @type {AppStorage} */
const BlueApp = new AppStorage();
// If attempt reaches 10, a wipe keychain option will be provided to the user.
let unlockAttempt = 0;
async function startAndDecrypt(retry) {
console.log('startAndDecrypt');
@ -58,11 +61,24 @@ async function startAndDecrypt(retry) {
if (hadToRefresh && noErr) {
await BlueApp.saveToDisk(); // caching
} */
// We want to return true to let the UnlockWith screen that its ok to proceed.
return true;
}
if (!success && password) {
// we had password and yet could not load/decrypt
return startAndDecrypt(true);
unlockAttempt++;
if (unlockAttempt < 10 || Platform.OS !== 'ios') {
return startAndDecrypt(true);
} else {
unlockAttempt = 0;
Biometric.showKeychainWipeAlert();
// We want to return false to let the UnlockWith screen that it is NOT ok to proceed.
return false;
}
} else {
// Return true because there was no wallet data in keychain. Proceed.
return true;
}
}

View file

@ -96,8 +96,11 @@ export default class UnlockWith extends Component {
unlockWithKey = () => {
this.setState({ isAuthenticating: true }, async () => {
await BlueApp.startAndDecrypt();
this.successfullyAuthenticated();
if (await BlueApp.startAndDecrypt()) {
this.successfullyAuthenticated();
} else {
this.setState({ isAuthenticating: false });
}
});
};

View file

@ -1,5 +1,12 @@
/* global alert */
import Biometrics from 'react-native-biometrics';
import { Platform, Alert } from 'react-native';
import PasscodeAuth from 'react-native-passcode-auth';
import * as NavigationService from '../NavigationService';
import { StackActions } from '@react-navigation/native';
import RNSecureKeyStore from 'react-native-secure-key-store';
const BlueApp = require('../BlueApp');
const loc = require('../loc');
export default class Biometric {
static STORAGEKEY = 'Biometrics';
@ -58,4 +65,58 @@ export default class Biometric {
}
return false;
}
static async clearKeychain() {
await RNSecureKeyStore.remove('data');
await RNSecureKeyStore.remove('data_encrypted');
await BlueApp.setResetOnAppUninstallTo(true);
NavigationService.dispatch(StackActions.replace('WalletsRoot'));
}
static async requestDevicePasscode() {
let isDevicePasscodeSupported = false;
try {
isDevicePasscodeSupported = await PasscodeAuth.isSupported();
if (isDevicePasscodeSupported) {
const isAuthenticated = await PasscodeAuth.authenticate();
if (isAuthenticated) {
Alert.alert(
'Storage',
`All your wallets will be removed and your storage will be decrypted. Are you sure you want to proceed?`,
[
{ text: loc.send.details.cancel, style: 'cancel' },
{
text: loc._.ok,
onPress: () => Biometric.clearKeychain(),
},
],
{ cancelable: false },
);
}
}
} catch {
isDevicePasscodeSupported = undefined;
}
if (isDevicePasscodeSupported === false) {
alert('Your device does not have a passcode. In order to proceed, please configure a passcode in the Settings app.');
}
}
static showKeychainWipeAlert() {
if (Platform.OS === 'ios') {
Alert.alert(
'Storage',
`You have attempted to enter your password 10 times. Would you like to reset your storage? This will remove all wallets and decrypt your storage.`,
[
{ text: loc.send.details.cancel, onPress: () => {}, style: 'cancel' },
{
text: loc._.ok,
onPress: () => Biometric.requestDevicePasscode(),
style: 'default',
},
],
{ cancelable: false },
);
}
}
}

View file

@ -78,6 +78,8 @@ PODS:
- OpenSSL-Universal (1.0.2.19):
- OpenSSL-Universal/Static (= 1.0.2.19)
- OpenSSL-Universal/Static (1.0.2.19)
- PasscodeAuth (1.0.0):
- React
- RCTRequired (0.62.2)
- RCTTypeSafety (0.62.2):
- FBLazyVector (= 0.62.2)
@ -413,6 +415,7 @@ DEPENDENCIES:
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- lottie-ios (from `../node_modules/lottie-ios`)
- lottie-react-native (from `../node_modules/lottie-react-native`)
- PasscodeAuth (from `../node_modules/react-native-passcode-auth`)
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
- React (from `../node_modules/react-native/`)
@ -506,6 +509,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/lottie-ios"
lottie-react-native:
:path: "../node_modules/lottie-react-native"
PasscodeAuth:
:path: "../node_modules/react-native-passcode-auth"
RCTRequired:
:path: "../node_modules/react-native/Libraries/RCTRequired"
RCTTypeSafety:
@ -636,6 +641,7 @@ SPEC CHECKSUMS:
lottie-ios: 48fac6be217c76937e36e340e2d09cf7b10b7f5f
lottie-react-native: a664f59f1f298c2696dd0ae07b15cbdfc433cb02
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
PasscodeAuth: 1cc99b13d8e4de4716d7e2b4069af2f1a9de30b2
RCTRequired: cec6a34b3ac8a9915c37e7e4ad3aa74726ce4035
RCTTypeSafety: 93006131180074cffa227a1075802c89a49dd4ce
React: 29a8b1a02bd764fb7644ef04019270849b9a7ac3

4
package-lock.json generated
View file

@ -14963,6 +14963,10 @@
"resolved": "https://registry.npmjs.org/react-native-obscure/-/react-native-obscure-1.2.1.tgz",
"integrity": "sha512-zepY31U2HAWrxPP+uGhDFFa1yGdbIa06iviCYRQJcEN2K4gtcEYBCtsk+PdClaiwIREZOQ7YKscxCIlZyR1m6w=="
},
"react-native-passcode-auth": {
"version": "git+https://github.com/BlueWallet/react-native-passcode-auth.git#a2ff977ba92b36f8d0a5567f59c05cc608e8bd12",
"from": "git+https://github.com/BlueWallet/react-native-passcode-auth.git#a2ff977ba92b36f8d0a5567f59c05cc608e8bd12"
},
"react-native-popup-menu-android": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/react-native-popup-menu-android/-/react-native-popup-menu-android-1.0.3.tgz",

View file

@ -126,6 +126,7 @@
"react-native-localize": " 1.4.0",
"react-native-modal": "11.5.6",
"react-native-obscure": "1.2.1",
"react-native-passcode-auth": "git+https://github.com/BlueWallet/react-native-passcode-auth.git#a2ff977ba92b36f8d0a5567f59c05cc608e8bd12",
"react-native-popup-menu-android": "1.0.3",
"react-native-privacy-snapshot": "git+https://github.com/BlueWallet/react-native-privacy-snapshot.git",
"react-native-prompt-android": "git+https://github.com/BlueWallet/react-native-prompt-android.git#2073b07f64bf5dc95807f64d79f37bdb111e6951",