Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ import AboutGroup, {
import SecurityGroup, {
SecurityGroupParamList,
} from './navigation/tabs/settings/security/SecurityGroup';
import AuthGroup, {AuthGroupParamList} from './navigation/auth/AuthGroup';
import AuthGroup, {
AuthGroupParamList,
AuthScreens,
} from './navigation/auth/AuthGroup';
import BuyCryptoGroup, {
BuyCryptoGroupParamList,
} from './navigation/services/buy-crypto/BuyCryptoGroup';
Expand Down Expand Up @@ -332,6 +335,11 @@ export default () => {
WalletScreens.ACCOUNT_DETAILS,
WalletScreens.TRANSACTION_PROPOSAL_NOTIFICATIONS,
WalletScreens.WALLET_DETAILS,
WalletScreens.VERIFY_PHRASE,
WalletScreens.EXTENDED_PRIVATE_KEY,
AuthScreens.LOGIN,
AuthScreens.CREATE_ACCOUNT,
AuthScreens.SECURE_ACCOUNT,
];

const debouncedOnStateChange = useMemo(
Expand Down
18 changes: 16 additions & 2 deletions src/components/form/BoxInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import React, {useState} from 'react';
import {KeyboardTypeOptions, TextInput, TextInputProps} from 'react-native';
import React, {useEffect, useState} from 'react';
import {
AppState,
KeyboardTypeOptions,
TextInput,
TextInputProps,
} from 'react-native';
import TextInputMask, {TextInputMaskProps} from 'react-native-text-input-mask';
import styled, {css} from 'styled-components/native';
import ObfuscationHide from '../../../assets/img/obfuscation-hide.svg';
Expand Down Expand Up @@ -219,6 +224,15 @@ const BoxInput = React.forwardRef<
);
}

useEffect(() => {
const sub = AppState.addEventListener('change', state => {
if (isPassword && (state === 'inactive' || state === 'background')) {
props.onChangeText?.('');
}
});
return () => sub.remove();
}, [isPassword, props]);

return (
<>
{label ? <Label>{label}</Label> : null}
Expand Down
8 changes: 7 additions & 1 deletion src/navigation/auth/screens/CreateAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import yup from '../../../lib/yup';
import {navigationRef} from '../../../Root';
import {AppActions} from '../../../store/app';
import {BitPayIdActions, BitPayIdEffects} from '../../../store/bitpay-id';
import {useAppDispatch, useAppSelector} from '../../../utils/hooks';
import {
useAppDispatch,
useAppSelector,
useSensitiveRefClear,
} from '../../../utils/hooks';
import {AuthScreens, AuthGroupParamList} from '../AuthGroup';
import AuthFormContainer, {
AuthActionRow,
Expand Down Expand Up @@ -64,6 +68,7 @@ const CreateAccountScreen: React.FC<CreateAccountScreenProps> = ({
const dispatch = useAppDispatch();
const [isRecaptchaVisible, setRecaptchaVisible] = useState(false);
const captchaRef = useRef<CaptchaRef>(null);
const {clearSensitive} = useSensitiveRefClear([passwordRef]);

const schema = yup.object().shape({
givenName: yup.string().required().trim(),
Expand Down Expand Up @@ -168,6 +173,7 @@ const CreateAccountScreen: React.FC<CreateAccountScreenProps> = ({
agreedToMarketingCommunications,
}),
);
clearSensitive();
},
() => {
Keyboard.dismiss();
Expand Down
9 changes: 8 additions & 1 deletion src/navigation/auth/screens/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ import {navigationRef, RootStacks} from '../../../Root';
import {AppActions} from '../../../store/app';
import {BitPayIdActions, BitPayIdEffects} from '../../../store/bitpay-id';
import {sleep} from '../../../utils/helper-methods';
import {useAppDispatch, useAppSelector} from '../../../utils/hooks';
import {
useAppDispatch,
useAppSelector,
useSensitiveRefClear,
} from '../../../utils/hooks';
import {BitpayIdScreens} from '../../bitpay-id/BitpayIdGroup';
import {AuthScreens, AuthGroupParamList} from '../AuthGroup';
import AuthFormContainer, {
Expand Down Expand Up @@ -115,6 +119,8 @@ const LoginScreen: React.FC<LoginScreenProps> = ({navigation, route}) => {
const captchaRef = useRef<CaptchaRef>(null);
const {onLoginSuccess} = route.params || {};

const {clearSensitive} = useSensitiveRefClear([passwordRef]);

useEffect(() => {
dispatch(BitPayIdEffects.startFetchSession());
}, [dispatch]);
Expand Down Expand Up @@ -197,6 +203,7 @@ const LoginScreen: React.FC<LoginScreenProps> = ({navigation, route}) => {
const onSubmit = handleSubmit(
async ({email, password}) => {
Keyboard.dismiss();
clearSensitive();
if (session.captchaDisabled) {
dispatch(BitPayIdEffects.startLogin({email, password}));
} else {
Expand Down
23 changes: 20 additions & 3 deletions src/navigation/wallet/components/FileOrText.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, {useEffect, useRef} from 'react';
import {
ImportTextInput,
HeaderContainer,
Expand Down Expand Up @@ -30,9 +30,13 @@ import {startUpdateAllWalletStatusForKey} from '../../../store/wallet/effects/st
import {updatePortfolioBalance} from '../../../store/wallet/wallet.actions';
import {useTranslation} from 'react-i18next';
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
import {ScrollView, Keyboard} from 'react-native';
import {ScrollView, Keyboard, TextInput, AppState} from 'react-native';
import {Analytics} from '../../../store/analytics/analytics.effects';
import {useAppDispatch, useAppSelector} from '../../../utils/hooks';
import {
useAppDispatch,
useAppSelector,
useSensitiveRefClear,
} from '../../../utils/hooks';
import {useOngoingProcess} from '../../../contexts';

const BWCProvider = BwcProvider.getInstance();
Expand Down Expand Up @@ -76,6 +80,8 @@ const FileOrText = () => {
const walletTermsAccepted = useAppSelector(
({WALLET}: RootState) => WALLET.walletTermsAccepted,
);
const plainTextRef = useRef<TextInput>(null);
const {clearSensitive} = useSensitiveRefClear([plainTextRef]);

const {
control,
Expand Down Expand Up @@ -157,6 +163,7 @@ const FileOrText = () => {

const onSubmit = handleSubmit(formData => {
const {text, password} = formData;
clearSensitive();

Keyboard.dismiss();

Expand All @@ -175,6 +182,15 @@ const FileOrText = () => {
importWallet(decryptBackupText, opts);
});

useEffect(() => {
const sub = AppState.addEventListener('change', state => {
if (state === 'inactive' || state === 'background') {
clearSensitive();
}
});
return () => sub.remove();
}, [clearSensitive]);

return (
<ScrollViewContainer
accessibilityLabel="file-or-text-view"
Expand All @@ -189,6 +205,7 @@ const FileOrText = () => {
control={control}
render={({field: {onChange, onBlur, value}}) => (
<ImportTextInput
ref={plainTextRef}
accessibilityLabel="import-text-input"
multiline
numberOfLines={5}
Expand Down
23 changes: 20 additions & 3 deletions src/navigation/wallet/components/RecoveryPhrase.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useCallback, useEffect, useState} from 'react';
import React, {useCallback, useEffect, useRef, useState} from 'react';
import styled from 'styled-components/native';
import {
Caution,
Expand Down Expand Up @@ -74,7 +74,7 @@ import {CurrencyImage} from '../../../components/currency-image/CurrencyImage';
import {SupportedCurrencyOptions} from '../../../constants/SupportedCurrencyOptions';
import Icons from '../components/WalletIcons';
import SheetModal from '../../../components/modal/base/sheet/SheetModal';
import {FlatList, View} from 'react-native';
import {AppState, FlatList, TextInput, View} from 'react-native';
import CurrencySelectionRow from '../../../components/list/CurrencySelectionRow';
import {updatePortfolioBalance} from '../../../store/wallet/wallet.actions';
import {
Expand All @@ -85,7 +85,11 @@ import {useTranslation} from 'react-i18next';
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
import {Analytics} from '../../../store/analytics/analytics.effects';
import {IS_ANDROID, IS_IOS} from '../../../constants';
import {useAppDispatch, useAppSelector} from '../../../utils/hooks';
import {
useAppDispatch,
useAppSelector,
useSensitiveRefClear,
} from '../../../utils/hooks';
import {TouchableOpacity} from '@components/base/TouchableOpacity';
import {useOngoingProcess} from '../../../contexts';

Expand Down Expand Up @@ -206,6 +210,8 @@ const RecoveryPhrase = () => {
passphrase: undefined as string | undefined,
isMultisig: false,
});
const wordsRef = useRef<TextInput>(null);
const {clearSensitive} = useSensitiveRefClear([wordsRef]);

const {
control,
Expand Down Expand Up @@ -347,6 +353,7 @@ const RecoveryPhrase = () => {

const onSubmit = (formData: {text: string}) => {
const {text} = formData;
clearSensitive();

let keyOpts: Partial<KeyOptions> = {};

Expand Down Expand Up @@ -573,6 +580,15 @@ const RecoveryPhrase = () => {
}
}, []);

useEffect(() => {
const sub = AppState.addEventListener('change', state => {
if (state === 'inactive' || state === 'background') {
clearSensitive();
}
});
return () => sub.remove();
}, [clearSensitive]);

return (
<ScrollViewContainer
accessibilityLabel="recovery-phrase-view"
Expand Down Expand Up @@ -611,6 +627,7 @@ const RecoveryPhrase = () => {
control={control}
render={({field: {onChange, onBlur, value}}) => (
<ImportTextInput
ref={wordsRef}
accessibilityLabel="import-text-input"
multiline
autoCapitalize={'none'}
Expand Down
1 change: 0 additions & 1 deletion src/navigation/wallet/screens/Import.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {WalletGroupParamList, WalletScreens} from '../WalletGroup';
import {NativeStackScreenProps} from '@react-navigation/native-stack';
import {useTranslation} from 'react-i18next';
import CustomTabBar from '../../../components/custom-tab-bar/CustomTabBar';
import {Platform} from 'react-native';

type ImportScreenProps = NativeStackScreenProps<
WalletGroupParamList,
Expand Down
1 change: 1 addition & 0 deletions src/utils/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './useDeeplinks';
export * from './useLogger';
export * from './useMount';
export * from './useRequestTrackingPermissionHandler';
export * from './useSensitiveRefClear';
25 changes: 25 additions & 0 deletions src/utils/hooks/useSensitiveRefClear.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, {useCallback} from 'react';
import {TextInput} from 'react-native';

function clearInputRef(ref: React.RefObject<TextInput | null>) {
const node: any = ref.current;
if (!node) return;

if (typeof node.clear === 'function') {
node.clear();
node.blur?.();
return;
}

node.setNativeProps?.({text: ''});
node.blur?.();
}

export function useSensitiveRefClear(
refs: Array<React.RefObject<TextInput | null>>,
) {
const clearSensitive = useCallback(() => {
refs.forEach(ref => clearInputRef(ref));
}, [refs]);
return {clearSensitive};
}