diff --git a/src/containers/Settings/ProfileSettings/DisplaySeed/DisplaySeed.js b/src/containers/DisplaySeed/DisplaySeed.js
similarity index 69%
rename from src/containers/Settings/ProfileSettings/DisplaySeed/DisplaySeed.js
rename to src/containers/DisplaySeed/DisplaySeed.js
index 1f8ce2ad..dd36a480 100644
--- a/src/containers/Settings/ProfileSettings/DisplaySeed/DisplaySeed.js
+++ b/src/containers/DisplaySeed/DisplaySeed.js
@@ -12,14 +12,14 @@ import {
import { NavigationActions } from '@react-navigation/compat';
import { connect } from 'react-redux';
import QRCode from 'react-native-qrcode-svg';
-import Styles from '../../../../styles/index'
-import Colors from "../../../../globals/colors";
+import Styles from '../../styles/index'
+import Colors from "../../globals/colors";
import { CommonActions } from '@react-navigation/native';
-import { DLIGHT_PRIVATE, ELECTRUM, ETH, WYRE_SERVICE } from "../../../../utils/constants/intervalConstants";
+import { DLIGHT_PRIVATE, ELECTRUM, ETH, WYRE_SERVICE } from "../../utils/constants/intervalConstants";
import { Card, Paragraph, Title, Button } from 'react-native-paper'
-import { deriveKeyPair, dlightSeedToBytes, isSeedPhrase } from "../../../../utils/keys";
-import { createAlert } from "../../../../actions/actions/alert/dispatchers/alert";
-import { coinsList } from "../../../../utils/CoinData/CoinsList";
+import { deriveKeyPair, dlightSeedToBytes, isSeedPhrase } from "../../utils/keys";
+import { createAlert } from "../../actions/actions/alert/dispatchers/alert";
+import { coinsList } from "../../utils/CoinData/CoinsList";
class DisplaySeed extends Component {
constructor() {
@@ -31,7 +31,8 @@ class DisplaySeed extends Component {
dualSameSeed: false,
derivedKeys: {},
toggleDerivedKey: {},
- fetchingDerivedKey: {}
+ fetchingDerivedKey: {},
+ completeOnBack: false,
};
this.SEED_NAMES = {
@@ -65,6 +66,15 @@ class DisplaySeed extends Component {
.fromDeleteAccount,
});
}
+
+ if (
+ data &&
+ data.completeOnBack
+ ) {
+ this.setState({
+ completeOnBack: data.completeOnBack,
+ });
+ }
}
resetToScreen = () => {
@@ -114,8 +124,9 @@ class DisplaySeed extends Component {
}
}
- // Method to derive the key from seed. Replace this with your actual implementation
deriveKeyFromSeed = async (seed, key, coinObj) => {
+ const { data } = this.props.route.params;
+
switch (key) {
case DLIGHT_PRIVATE:
return Buffer.from(await dlightSeedToBytes(seed)).toString('hex');
@@ -124,14 +135,14 @@ class DisplaySeed extends Component {
seed,
coinsList.ETH,
key,
- this.props.activeAccount.keyDerivationVersion,
+ data.keyDerivationVersion,
)).privKey;
case ELECTRUM:
return (await deriveKeyPair(
seed,
coinObj,
key,
- this.props.activeAccount.keyDerivationVersion,
+ data.keyDerivationVersion,
)).privKey;
default:
return seed
@@ -139,7 +150,8 @@ class DisplaySeed extends Component {
}
render() {
- const { seeds, toggleDerivedKey, fetchingDerivedKey, derivedKeys } = this.state;
+ const { seeds, toggleDerivedKey, fetchingDerivedKey, derivedKeys, completeOnBack } = this.state;
+ const { data } = this.props.route.params;
return (
@@ -163,28 +175,30 @@ class DisplaySeed extends Component {
- {
- ((key === DLIGHT_PRIVATE && isSeedPhrase(seeds[key])) ||
- key === ETH ||
- key === ELECTRUM) && (
-
- )
- }
- {
- !isToggleOn && !fetchingDerivedKey[key] && key === ELECTRUM && (
-
- )
- }
+ {data.showDerivedKeys && <>
+ {
+ ((key === DLIGHT_PRIVATE && isSeedPhrase(seeds[key])) ||
+ key === ETH ||
+ key === ELECTRUM) && (
+
+ )
+ }
+ {
+ !isToggleOn && !fetchingDerivedKey[key] && key === ELECTRUM && (
+
+ )
+ }
+ >}
@@ -194,12 +208,16 @@ class DisplaySeed extends Component {
-
-
diff --git a/src/containers/Login/Login.js b/src/containers/Login/Login.js
index 6ed17a24..0fd05681 100644
--- a/src/containers/Login/Login.js
+++ b/src/containers/Login/Login.js
@@ -22,6 +22,7 @@ import {
} from '../../utils/constants/sendModal';
import {useSelector} from 'react-redux';
import TallButton from '../../components/LargerButton';
+import SignedOutDropdown from '../SignedOutDropdown/SignedOutDropdown';
const {height} = Dimensions.get('window');
@@ -32,6 +33,9 @@ const Login = props => {
const authModalUsed = useSelector(
state => state.authentication.authModalUsed,
);
+ const modalVisible = useSelector(
+ state => state.sendModal.visible,
+ );
const accounts = useSelector(state => state.authentication.accounts);
openAuthModal = ignoreDefault => {
@@ -67,12 +71,22 @@ const Login = props => {
props.navigation.navigate('CreateProfile');
};
+ handleRecoverSeed = () => {
+ props.navigation.navigate("RecoverSeeds");
+ };
+
return (
+
+ {!modalVisible && handleRecoverSeed()}
+ hasAccount={true}
+ />}
+
{
+ const accounts = useSelector(state => state.authentication.accounts);
+ const [numSeeds, setNumSeeds] = useState({});
+ const [passwordDialogOpen, setPasswordDialogOpen] = useState(false);
+ const [passwordDialogTitle, setPasswordDialogTitle] = useState('');
+ const [passwordDialogAccount, setPasswordDialogAccount] = useState(null);
+
+ useEffect(() => {
+ for (let account of accounts) {
+ setNumSeeds(prevState => ({
+ ...prevState,
+ [account.accountHash]: Object.values(account.encryptedKeys).filter(x => x != null).length,
+ }));
+ }
+ }, [accounts]);
+
+ const handleCardPress = async (account) => {
+ if (await canShowSeed()) {
+ setPasswordDialogAccount(account);
+ setPasswordDialogOpen(true);
+ setPasswordDialogTitle(`Enter your password for "${account.id}"`);
+ }
+ };
+
+ const onPasswordResult = async (result) => {
+ if (result.valid) {
+ setPasswordDialogOpen(false);
+
+ try {
+ const seeds = await checkPinForUser(result.password, passwordDialogAccount.id);
+
+ navigation.dispatch(CommonActions.reset({
+ index: 0,
+ routes: [{ name: 'DisplaySeed', params: { data: { seeds, showDerivedKeys: true, keyDerivationVersion: passwordDialogAccount.keyDerivationVersion, completeOnBack: true } } }],
+ }));
+ } catch(e) {
+ createAlert("Error", "Failed to retrieve seeds");
+ }
+ } else {
+ createAlert("Authentication Error", "Incorrect password");
+ }
+ }
+
+ const renderAccountCards = () => {
+ return accounts.map(account => (
+
+ handleCardPress(account)}
+ key={account.accountHash}
+ style={{ backgroundColor: Colors.primaryColor }}
+ >
+ 1 ? 's' : ''}`}
+ left={() => }
+ descriptionStyle={{ color: Colors.secondaryColor }}
+ right={() => (
+
+ )}
+ />
+
+
+ ));
+ };
+
+ return (
+
+ {passwordDialogOpen &&
+ setPasswordDialogOpen(false)}
+ submit={(result) => onPasswordResult(result)}
+ visible={passwordDialogOpen}
+ title={passwordDialogTitle}
+ userName={passwordDialogAccount ? passwordDialogAccount.id : ''}
+ account={passwordDialogAccount}
+ allowBiometry={true}
+ />
+ }
+ {'Select a Profile'}
+
+ {renderAccountCards()}
+
+ navigation.goBack()}
+ mode="outlined"
+ style={{ marginHorizontal: 8 }}
+ >
+ {"Cancel"}
+
+
+ );
+};
+
+export default RecoverSeedsSelectAccount;
diff --git a/src/containers/RootStack/MainStackScreens/MainStackScreens.js b/src/containers/RootStack/MainStackScreens/MainStackScreens.js
index 4a2fe261..2374d222 100644
--- a/src/containers/RootStack/MainStackScreens/MainStackScreens.js
+++ b/src/containers/RootStack/MainStackScreens/MainStackScreens.js
@@ -3,7 +3,7 @@ import { createStackNavigator } from "@react-navigation/stack";
import { defaultHeaderOptions } from '../../../utils/navigation/header';
import AddCoin from '../../AddCoin/AddCoin'
import CoinDetails from '../../CoinDetails/CoinDetails'
-import DisplaySeed from '../../Settings/ProfileSettings/DisplaySeed/DisplaySeed'
+import DisplaySeed from '../../DisplaySeed/DisplaySeed'
import SettingsMenus from '../../Settings/SettingsMenus'
import CoinMenus from '../../Coin/CoinMenus'
import VerusPay from '../../VerusPay/VerusPay'
diff --git a/src/containers/RootStack/RecoverSeedsStackScreens/RecoverSeedsStackScreens.js b/src/containers/RootStack/RecoverSeedsStackScreens/RecoverSeedsStackScreens.js
new file mode 100644
index 00000000..c4c24098
--- /dev/null
+++ b/src/containers/RootStack/RecoverSeedsStackScreens/RecoverSeedsStackScreens.js
@@ -0,0 +1,38 @@
+import React, { useState } from 'react';
+import { createStackNavigator } from "@react-navigation/stack";
+import { defaultHeaderOptions } from '../../../utils/navigation/header';
+import RecoverSeedsSelectAccount from '../../RecoverSeeds/RecoverSeedsSelectAccount';
+import DisplaySeed from '../../DisplaySeed/DisplaySeed';
+
+const RecoverSeedsStack = createStackNavigator();
+
+const RecoverSeedsStackScreens = props => {
+ return (
+
+
+ {(_props) => (
+
+ )}
+
+
+
+
+ );
+};
+
+export default RecoverSeedsStackScreens;
\ No newline at end of file
diff --git a/src/containers/RootStack/SignedOutStackScreens/SignedOutStackScreens.js b/src/containers/RootStack/SignedOutStackScreens/SignedOutStackScreens.js
index fa6333ed..d790790c 100644
--- a/src/containers/RootStack/SignedOutStackScreens/SignedOutStackScreens.js
+++ b/src/containers/RootStack/SignedOutStackScreens/SignedOutStackScreens.js
@@ -1,6 +1,6 @@
import React, {useEffect, useState} from 'react';
import {createStackNavigator} from '@react-navigation/stack';
-import DisplaySeed from '../../Settings/ProfileSettings/DisplaySeed/DisplaySeed';
+import DisplaySeed from '../../DisplaySeed/DisplaySeed';
import RecoverSeed from '../../Settings/ProfileSettings/RecoverSeed/RecoverSeed';
import DeleteProfile from '../../Settings/ProfileSettings/DeleteProfile/DeleteProfile';
import SecureLoading from '../../SecureLoading/SecureLoading';
@@ -9,6 +9,7 @@ import SignUp from '../../SignUp/SignUp';
import {useDispatch, useSelector} from 'react-redux';
import {setDeeplinkUrl} from '../../../actions/actionCreators';
import CreateProfile from '../../Onboard/CreateProfile/CreateProfile';
+import RecoverSeedsStackScreens from '../RecoverSeedsStackScreens/RecoverSeedsStackScreens';
const SignedOutStack = createStackNavigator();
@@ -84,6 +85,14 @@ const SignedOutStackScreens = props => {
headerShown: false,
}}
/>
+
+
);
};
diff --git a/src/containers/Settings/ProfileSettings/ProfileSettings.js b/src/containers/Settings/ProfileSettings/ProfileSettings.js
index 1a4ffc66..bd259000 100644
--- a/src/containers/Settings/ProfileSettings/ProfileSettings.js
+++ b/src/containers/Settings/ProfileSettings/ProfileSettings.js
@@ -276,7 +276,7 @@ class ProfileSettings extends Component {
.then((seeds) => {
this.setState({ password: null }, () => {
this.props.navigation.navigate("DisplaySeed", {
- data: { seeds },
+ data: { seeds, showDerivedKeys: true, keyDerivationVersion: this.props.activeAccount.keyDerivationVersion },
});
});
})
diff --git a/src/containers/SignedOutDropdown/SignedOutDropdown.js b/src/containers/SignedOutDropdown/SignedOutDropdown.js
new file mode 100644
index 00000000..c0bd91e6
--- /dev/null
+++ b/src/containers/SignedOutDropdown/SignedOutDropdown.js
@@ -0,0 +1,58 @@
+import * as React from 'react';
+import { Divider, FAB, Menu, Portal, Button, IconButton } from 'react-native-paper';
+import { SafeAreaView, View } from 'react-native'
+import Colors from '../../globals/colors';
+
+const SignedOutDropdown = (props) => {
+ const {
+ handleRecoverSeed,
+ hasAccount
+ } = props;
+ const [visible, setVisible] = React.useState(false);
+
+ const openMenu = () => setVisible(true);
+
+ const closeMenu = () => setVisible(false);
+
+ const actions = !hasAccount
+ ? []
+ : [
+ {
+ label: 'Recover account seeds',
+ onPress: handleRecoverSeed,
+ }
+ ];
+
+ return (
+
+
+ }>
+ {
+ actions.map((action, index) => {
+ return (
+ {
+ closeMenu();
+ action.onPress(props);
+ }} title={action.label} />
+ );
+ })
+ }
+
+
+ );
+};
+
+export default SignedOutDropdown;
\ No newline at end of file