export private key on devmode

This commit is contained in:
PhilReact 2025-05-09 01:20:59 +03:00
parent eeb66f4fa5
commit ce9988dd73
5 changed files with 152 additions and 5 deletions

View File

@ -26,6 +26,9 @@
"peers": "connected peers",
"version": "core version"
},
"ui": {
"version": "UI version"
},
"count": {
"none": "none",
"one": "one"

View File

@ -3570,7 +3570,11 @@ function App() {
</Dialog>
)}
{isSettingsOpen && (
<Settings open={isSettingsOpen} setOpen={setIsSettingsOpen} />
<Settings
open={isSettingsOpen}
setOpen={setIsSettingsOpen}
rawWallet={rawWallet}
/>
)}
<CustomizedSnackbars
open={openSnack}

View File

@ -33,7 +33,7 @@ import { useTranslation } from 'react-i18next';
import LanguageSelector from '../components/Language/LanguageSelector';
import { MyContext } from '../App';
const manifestData = {
export const manifestData = {
version: '0.5.4',
};

View File

@ -6,6 +6,7 @@ import { getBaseApiReact } from '../App';
import '../styles/CoreSyncStatus.css';
import { useTheme } from '@mui/material';
import { useTranslation } from 'react-i18next';
import { manifestData } from '../ExtStates/NotAuthenticated';
export const CoreSyncStatus = () => {
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()}
</span>
</h4>
<h4 className="lineHeight">
{t('core:ui.version')}:{' '}
<span style={{ color: '#03a9f4' }}>{manifestData.version}</span>
</h4>
</div>
</div>
);

View File

@ -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 <Slide direction="up" ref={ref} {...props} />;
});
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 && <ExportPrivateKey rawWallet={rawWallet} />}
<ThemeManager />
</Box>
</Dialog>
</Fragment>
);
};
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 (
<>
<Button
variant="contained"
sx={{
width: '200px',
}}
onClick={() => setIsOpen(true)}
>
Export private key
</Button>
<Dialog
open={isOpen}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Export password</DialogTitle>
<DialogContent
sx={{
flexDirection: 'column',
display: 'flex',
gap: '10px',
}}
>
<DialogContentText id="alert-dialog-description">
Keep your private key in a secure place. Do not share!
</DialogContentText>
<Spacer height="20px" />
<TextField
autoFocus
type="password"
value={password}
autoComplete="off"
onChange={(e) => setPassword(e.target.value)}
/>
{privateKey && (
<Button
variant="outlined"
onClick={() => {
navigator.clipboard.writeText(privateKey);
setInfoSnackCustom({
type: 'success',
message: 'Copied privated key',
});
setOpenSnackGlobal(true);
}}
>
{`Copy private key `}
<ContentCopyIcon color="primary" />
</Button>
)}
</DialogContent>
<DialogActions>
<Button
variant="contained"
onClick={() => {
setIsOpen(false);
setPassword('');
setPrivateKey('');
}}
>
Cancel
</Button>
<Button variant="contained" onClick={exportPrivateKeyFunc}>
Decrypt
</Button>
</DialogActions>
</Dialog>
</>
);
};