From ce9988dd7389631126e682ac0057bf1e6d9ef9dc Mon Sep 17 00:00:00 2001 From: PhilReact Date: Fri, 9 May 2025 01:20:59 +0300 Subject: [PATCH] export private key on devmode --- public/locales/en/core.json | 3 + src/App.tsx | 6 +- src/ExtStates/NotAuthenticated.tsx | 2 +- src/components/CoreSyncStatus.tsx | 9 +- src/components/Group/Settings.tsx | 137 ++++++++++++++++++++++++++++- 5 files changed, 152 insertions(+), 5 deletions(-) diff --git a/public/locales/en/core.json b/public/locales/en/core.json index 5ba27e8..33755f1 100644 --- a/public/locales/en/core.json +++ b/public/locales/en/core.json @@ -26,6 +26,9 @@ "peers": "connected peers", "version": "core version" }, + "ui": { + "version": "UI version" + }, "count": { "none": "none", "one": "one" diff --git a/src/App.tsx b/src/App.tsx index 4ab0d28..d24a4ae 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3570,7 +3570,11 @@ function App() { )} {isSettingsOpen && ( - + )} { const [nodeInfos, setNodeInfos] = useState({}); @@ -75,7 +76,9 @@ export const CoreSyncStatus = () => { : ''; let imagePath = syncingImg; - let message = t('core:status.synchronizing', { postProcess: 'capitalize' }); + let message = t('core:message.status.synchronizing', { + postProcess: 'capitalize', + }); if (isMintingPossible && !isUsingGateway) { imagePath = syncedMintingImg; @@ -140,6 +143,10 @@ export const CoreSyncStatus = () => { {isUsingGateway?.toString()} +

+ {t('core:ui.version')}:{' '} + {manifestData.version} +

); diff --git a/src/components/Group/Settings.tsx b/src/components/Group/Settings.tsx index 0279d2b..930a366 100644 --- a/src/components/Group/Settings.tsx +++ b/src/components/Group/Settings.tsx @@ -4,6 +4,7 @@ import { Fragment, ReactElement, Ref, + useContext, useEffect, useState, } from 'react'; @@ -15,11 +16,31 @@ import Typography from '@mui/material/Typography'; import CloseIcon from '@mui/icons-material/Close'; import Slide from '@mui/material/Slide'; import { TransitionProps } from '@mui/material/transitions'; -import { Box, FormControlLabel, Switch, styled, useTheme } from '@mui/material'; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import { + Box, + Button, + ButtonBase, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, + FormControlLabel, + Switch, + TextField, + styled, + useTheme, +} from '@mui/material'; import { enabledDevModeAtom } from '../../atoms/global'; import ThemeManager from '../Theme/ThemeManager'; import { useAtom } from 'jotai'; +import { decryptStoredWallet } from '../../utils/decryptWallet'; +import { Spacer } from '../../common/Spacer'; +import PhraseWallet from '../../utils/generateWallet/phrase-wallet'; +import { walletVersion } from '../../background'; +import Base58 from '../../deps/Base58'; +import { MyContext } from '../../App'; const LocalNodeSwitch = styled(Switch)(({ theme }) => ({ padding: 8, @@ -63,7 +84,7 @@ const Transition = forwardRef(function Transition( return ; }); -export const Settings = ({ address, open, setOpen }) => { +export const Settings = ({ open, setOpen, rawWallet }) => { const [checked, setChecked] = useState(false); const [isEnabledDevMode, setIsEnabledDevMode] = useAtom(enabledDevModeAtom); @@ -187,9 +208,121 @@ export const Settings = ({ address, open, setOpen }) => { label="Enable dev mode" /> )} + {isEnabledDevMode && } ); }; + +const ExportPrivateKey = ({ rawWallet }) => { + const [password, setPassword] = useState(''); + const [privateKey, setPrivateKey] = useState(''); + const [isOpen, setIsOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const { setOpenSnackGlobal, setInfoSnackCustom } = useContext(MyContext); + const exportPrivateKeyFunc = async () => { + try { + setInfoSnackCustom({ + type: 'info', + message: 'Decrypting wallet...', + }); + + setOpenSnackGlobal(true); + const wallet = structuredClone(rawWallet); + + const res = await decryptStoredWallet(password, wallet); + const wallet2 = new PhraseWallet(res, wallet?.version || walletVersion); + + const keyPair = Base58.encode(wallet2._addresses[0].keyPair.privateKey); + setPrivateKey(keyPair); + setInfoSnackCustom({ + type: '', + message: '', + }); + + setOpenSnackGlobal(false); + } catch (error) { + setInfoSnackCustom({ + type: 'error', + message: error?.message + ? `Error decrypting wallet: ${error?.message}` + : 'Error decrypting wallet', + }); + + setOpenSnackGlobal(true); + } + }; + return ( + <> + + + Export password + + + Keep your private key in a secure place. Do not share! + + + setPassword(e.target.value)} + /> + {privateKey && ( + + )} + + + + + + + + ); +};