security(C1): remove private key from get-config IPC response
Move atmPrivateKey and adminToken out of the general get-config IPC handler into a dedicated one-shot get-atm-secrets handler that returns secrets only once per app lifecycle. Subsequent calls return empty strings. This prevents XSS or DevTools from repeatedly querying getConfig() to steal the ATM's Nostr private key. TODO: Move signing/encryption to main process entirely (Phase 2) so the private key never crosses the IPC boundary. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d8841f7fe9
commit
2273303b13
4 changed files with 56 additions and 10 deletions
|
|
@ -100,16 +100,17 @@ ipcMain.handle('get-version', () => {
|
|||
/**
|
||||
* Get runtime configuration from environment variables
|
||||
* This allows configuration to be set at runtime (not baked in at build time)
|
||||
*
|
||||
* SECURITY: Secrets (private key, admin token) are NOT included here.
|
||||
* Use 'get-atm-secrets' for secrets — it's a one-shot handler.
|
||||
*/
|
||||
ipcMain.handle('get-config', () => {
|
||||
return {
|
||||
// Lightning.Pub connection
|
||||
// Lightning.Pub connection (public info only)
|
||||
relayUrl: process.env.VITE_RELAY_URL || 'ws://localhost:7777',
|
||||
lightningPubPubkey: process.env.VITE_LIGHTNING_PUB_PUBKEY || '',
|
||||
lightningPubApiUrl: process.env.VITE_LIGHTNING_PUB_API_URL || 'http://localhost:1776',
|
||||
extensionApiUrl: process.env.VITE_EXTENSION_API_URL || 'http://localhost:1777',
|
||||
atmPrivateKey: process.env.VITE_ATM_PRIVATE_KEY || '',
|
||||
adminToken: process.env.VITE_ADMIN_TOKEN || '',
|
||||
appId: process.env.VITE_APP_ID || '',
|
||||
|
||||
// Hardware configuration
|
||||
|
|
@ -122,6 +123,29 @@ ipcMain.handle('get-config', () => {
|
|||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* One-shot secrets handler.
|
||||
*
|
||||
* Returns ATM private key and admin token ONCE during initialization,
|
||||
* then refuses all subsequent calls. This limits the window for XSS
|
||||
* or compromised dependencies to steal secrets via IPC.
|
||||
*
|
||||
* TODO: Move signing/encryption to main process entirely (Phase 2)
|
||||
* so the private key never crosses the IPC boundary.
|
||||
*/
|
||||
let secretsConsumed = false
|
||||
ipcMain.handle('get-atm-secrets', () => {
|
||||
if (secretsConsumed) {
|
||||
console.warn('[Electron] SECURITY: get-atm-secrets called after secrets already consumed')
|
||||
return { atmPrivateKey: '', adminToken: '' }
|
||||
}
|
||||
secretsConsumed = true
|
||||
return {
|
||||
atmPrivateKey: process.env.VITE_ATM_PRIVATE_KEY || '',
|
||||
adminToken: process.env.VITE_ADMIN_TOKEN || '',
|
||||
}
|
||||
})
|
||||
|
||||
// State persistence IPC handlers
|
||||
ipcMain.handle('state:load-cassettes', () => loadCassettes())
|
||||
ipcMain.handle('state:set-cassettes', (_event, cassettes) => setCassettes(cassettes))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue