diff --git a/frontend/electron/main.cjs b/frontend/electron/main.cjs index 3a6b308..80644f1 100644 --- a/frontend/electron/main.cjs +++ b/frontend/electron/main.cjs @@ -52,6 +52,7 @@ ipcMain.handle('p2pkh', (_, args) => callPython('p2pkh', args)) ipcMain.handle('p2sh', (_, args) => callPython('p2sh', args)) ipcMain.handle('p2wpkh', (_, args) => callPython('p2wpkh', args)) ipcMain.handle('p2tr', (_, args) => callPython('p2tr', args)) +ipcMain.handle('single-encrypt', (_, args) => callPython('single_encrypt', args)) ipcMain.handle('save-wallet', (_, { filename, data }) => { ensureWalletDir() diff --git a/frontend/electron/preload.cjs b/frontend/electron/preload.cjs index 09d8cc1..d33fc31 100644 --- a/frontend/electron/preload.cjs +++ b/frontend/electron/preload.cjs @@ -9,6 +9,7 @@ contextBridge.exposeInMainWorld('electronAPI', { p2sh: (args) => ipcRenderer.invoke('p2sh', args), p2wpkh: (args) => ipcRenderer.invoke('p2wpkh', args), p2tr: (args) => ipcRenderer.invoke('p2tr', args), + singleEncrypt:(args) => ipcRenderer.invoke('single-encrypt', args), saveWallet: (filename, data) => ipcRenderer.invoke('save-wallet', { filename, data }), getWalletDir: () => ipcRenderer.invoke('get-wallet-dir'), }) diff --git a/frontend/src/components/SingleAddress.jsx b/frontend/src/components/SingleAddress.jsx index 0f7a3dd..5a7e8c5 100644 --- a/frontend/src/components/SingleAddress.jsx +++ b/frontend/src/components/SingleAddress.jsx @@ -2,11 +2,11 @@ import { useState } from 'react' import CopyButton from './CopyButton' const TABS = [ + { id: 'p2pk', label: 'P2PK', desc: 'Pay-to-PubKey (no address)' }, { id: 'p2pkh', label: 'P2PKH', desc: 'Legacy · starts with 1 / m' }, + { id: 'p2sh', label: 'P2SH', desc: 'Multisig · starts with 3 / 2' }, { id: 'p2wpkh', label: 'P2WPKH', desc: 'Native SegWit · bc1q / tb1q' }, { id: 'p2tr', label: 'P2TR', desc: 'Taproot · bc1p / tb1p' }, - { id: 'p2pk', label: 'P2PK', desc: 'Pay-to-PubKey (no address)' }, - { id: 'p2sh', label: 'P2SH', desc: 'Multisig · starts with 3 / 2' }, ] export default function SingleAddress({ initialTab = 'p2pkh' }) { @@ -19,6 +19,7 @@ export default function SingleAddress({ initialTab = 'p2pkh' }) { const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const [filename, setFilename] = useState('') + const [savePassword, setSavePassword] = useState('') const [saving, setSaving] = useState(false) const [saveMsg, setSaveMsg] = useState(null) @@ -35,7 +36,8 @@ export default function SingleAddress({ initialTab = 'p2pkh' }) { const fn = window.electronAPI[tab] const data = await fn(args) setResult(data) - setFilename(`${tab}_${network}_${Date.now()}`) + setFilename('') + setSavePassword('') } catch (e) { setError(e.message) } finally { @@ -45,12 +47,21 @@ export default function SingleAddress({ initialTab = 'p2pkh' }) { const save = async () => { if (!result) return + if (!filename.trim()) { + setSaveMsg('Error: Filename is required.') + return + } + setSaving(true) setSaveMsg(null) try { - const name = (filename.trim() || `${tab}_${network}`) + '.json' - const savedPath = await window.electronAPI.saveWallet(name, result) - setSaveMsg(`Saved: ${savedPath}`) + let data = result + if (savePassword.trim()) { + data = await window.electronAPI.singleEncrypt({ wallet: result, password: savePassword }) + } + const name = filename.trim().endsWith('.json') ? filename.trim() : `${filename.trim()}.json` + const savedPath = await window.electronAPI.saveWallet(name, data) + setSaveMsg(savePassword.trim() ? `Saved (encrypted): ${savedPath}` : `Saved: ${savedPath}`) } catch (e) { setSaveMsg('Error: ' + e.message) } finally { @@ -67,7 +78,7 @@ export default function SingleAddress({ initialTab = 'p2pkh' }) {
{TABS.map(t => ( - ))} @@ -126,12 +137,23 @@ export default function SingleAddress({ initialTab = 'p2pkh' }) { setFilename(e.target.value)} /> .json · saved to ~/.wallet-generator/wallet/
+
+ + setSavePassword(e.target.value)} + /> + Encrypts private keys in JSON +