diff --git a/lamassu-next/apps/machine/.env.example b/lamassu-next/apps/machine/.env.example new file mode 100644 index 0000000..28f8fc8 --- /dev/null +++ b/lamassu-next/apps/machine/.env.example @@ -0,0 +1,49 @@ +# Lamassu ATM Configuration +# Copy this file to .env and fill in your values + +# ============================================================================= +# Hardware Configuration +# ============================================================================= + +# Machine model preset (sintra, gaia, or custom) +VITE_LAMASSU_MACHINE_MODEL=sintra + +# Fiat currency code (ISO 4217) +VITE_LAMASSU_FIAT_CODE=USD + +# Custom device paths (optional - uses preset defaults if not set) +# VITE_LAMASSU_VALIDATOR_DEVICE=/dev/ttyJ5 +# VITE_LAMASSU_DISPENSER_DEVICE=/dev/ttyJ7 + +# Cassette configuration (optional - JSON array) +# VITE_LAMASSU_CASSETTES='[{"denomination":20,"count":100}]' + +# ============================================================================= +# Lightning.Pub Connection (Required) +# ============================================================================= + +# Nostr relay WebSocket URL +VITE_RELAY_URL=ws://localhost:7777 + +# Lightning.Pub's Nostr public key (required!) +# Get from: docker logs lamassu-lightning-pub | grep pubkey +VITE_LIGHTNING_PUB_PUBKEY= + +# Lightning.Pub HTTP API URL (optional) +VITE_LIGHTNING_PUB_API_URL=http://localhost:1776 + +# ============================================================================= +# ATM Identity +# ============================================================================= + +# ATM's Nostr private key (hex format, 64 characters) +# Generate with: npx @lamassu/nostr-client generate-keypair +# If not set, generates ephemeral identity on each restart +VITE_ATM_PRIVATE_KEY= + +# ============================================================================= +# Development Only +# ============================================================================= + +# Lightning.Pub admin token (dev/testing only) +VITE_ADMIN_TOKEN=lamassu-dev-admin-token diff --git a/lamassu-next/apps/machine/electron/main.ts b/lamassu-next/apps/machine/electron/main.ts index c948e3e..e5df3e5 100644 --- a/lamassu-next/apps/machine/electron/main.ts +++ b/lamassu-next/apps/machine/electron/main.ts @@ -53,6 +53,28 @@ ipcMain.handle('get-version', () => { return app.getVersion() }) +/** + * Get runtime configuration from environment variables + * This allows configuration to be set at runtime (not baked in at build time) + */ +ipcMain.handle('get-config', () => { + return { + // Lightning.Pub connection + 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', + atmPrivateKey: process.env.VITE_ATM_PRIVATE_KEY || '', + adminToken: process.env.VITE_ADMIN_TOKEN || '', + + // Hardware configuration + machineModel: process.env.VITE_LAMASSU_MACHINE_MODEL || 'sintra', + fiatCode: process.env.VITE_LAMASSU_FIAT_CODE || 'USD', + validatorDevice: process.env.VITE_LAMASSU_VALIDATOR_DEVICE, + dispenserDevice: process.env.VITE_LAMASSU_DISPENSER_DEVICE, + cassettes: process.env.VITE_LAMASSU_CASSETTES, + } +}) + // App lifecycle app.whenReady().then(() => { createWindow() diff --git a/lamassu-next/apps/machine/electron/preload.ts b/lamassu-next/apps/machine/electron/preload.ts index 5abcb95..bcd7c62 100644 --- a/lamassu-next/apps/machine/electron/preload.ts +++ b/lamassu-next/apps/machine/electron/preload.ts @@ -7,11 +7,31 @@ import { contextBridge, ipcRenderer } from 'electron' +/** + * Runtime configuration interface + * These values are read from environment variables at runtime (not build time) + */ +export interface RuntimeConfig { + relayUrl: string + lightningPubPubkey: string + lightningPubApiUrl: string + atmPrivateKey: string + adminToken: string + machineModel: string + fiatCode: string + validatorDevice?: string + dispenserDevice?: string + cassettes?: string +} + // Expose protected methods to renderer contextBridge.exposeInMainWorld('electronAPI', { // Get app version getVersion: (): Promise => ipcRenderer.invoke('get-version'), + // Get runtime configuration (read from environment at runtime) + getConfig: (): Promise => ipcRenderer.invoke('get-config'), + // Platform info platform: process.platform, }) @@ -21,6 +41,7 @@ declare global { interface Window { electronAPI: { getVersion: () => Promise + getConfig: () => Promise platform: NodeJS.Platform } } diff --git a/lamassu-next/apps/machine/src/services/lightning.ts b/lamassu-next/apps/machine/src/services/lightning.ts index 18eb69e..487e257 100644 --- a/lamassu-next/apps/machine/src/services/lightning.ts +++ b/lamassu-next/apps/machine/src/services/lightning.ts @@ -30,22 +30,42 @@ import { import type { OfferRequest } from '@lamassu/clink' import type { ATMServices, ATMContext } from '@lamassu/state-machine' +// Import Electron types +import type {} from '@/types/electron' + // Check if we're in a browser environment const isBrowser = typeof window !== 'undefined' +// Check if we're running in Electron (electronAPI is exposed via preload) +const isElectron = typeof window !== 'undefined' && window.electronAPI !== undefined + /** - * Lightning configuration from environment variables + * Lightning configuration * - * Environment variables (prefix with VITE_ for Vite): + * In Electron: Read from environment at runtime via IPC + * In Browser (dev): Read from Vite's import.meta.env (build-time) + * + * Environment variables: * - VITE_RELAY_URL: Nostr relay WebSocket URL * - VITE_LIGHTNING_PUB_PUBKEY: Lightning.Pub's Nostr pubkey (hex or npub) * - VITE_LIGHTNING_PUB_API_URL: Lightning.Pub HTTP API URL * - VITE_ATM_PRIVATE_KEY: ATM's Nostr private key (hex or nsec) * - VITE_ADMIN_TOKEN: Lightning.Pub admin token (dev only) */ -function loadLightningConfig() { +interface LightningConfig { + relayUrl: string + lightningPubPubkey: string + lightningPubApiUrl: string + adminToken: string + atmPrivateKey: string +} + +/** + * Load configuration - async to support Electron IPC + */ +async function loadLightningConfig(): Promise { // Development defaults (local Docker infrastructure) - const defaults = { + const defaults: LightningConfig = { relayUrl: 'ws://localhost:7777', lightningPubPubkey: '', lightningPubApiUrl: 'http://localhost:1776', @@ -53,6 +73,23 @@ function loadLightningConfig() { atmPrivateKey: '', } + // In Electron, get runtime config from main process + if (isElectron && window.electronAPI) { + try { + const runtimeConfig = await window.electronAPI.getConfig() + return { + relayUrl: runtimeConfig.relayUrl || defaults.relayUrl, + lightningPubPubkey: runtimeConfig.lightningPubPubkey || defaults.lightningPubPubkey, + lightningPubApiUrl: runtimeConfig.lightningPubApiUrl || defaults.lightningPubApiUrl, + adminToken: runtimeConfig.adminToken || defaults.adminToken, + atmPrivateKey: runtimeConfig.atmPrivateKey || defaults.atmPrivateKey, + } + } catch (e) { + console.warn('[Lightning] Failed to get runtime config from Electron:', e) + } + } + + // Fallback: Vite build-time env vars (for browser dev mode) return { relayUrl: import.meta.env.VITE_RELAY_URL || defaults.relayUrl, lightningPubPubkey: import.meta.env.VITE_LIGHTNING_PUB_PUBKEY || defaults.lightningPubPubkey, @@ -62,7 +99,8 @@ function loadLightningConfig() { } } -const CONFIG = loadLightningConfig() +// Config is loaded async now - will be set in initializeLightningServices +let CONFIG: LightningConfig interface LightningServices { nostrClient: NostrClient @@ -87,6 +125,10 @@ type PaymentReceivedCallback = (preimage: string) => void */ export async function initializeLightningServices(): Promise { console.log('[Lightning] Initializing services...') + + // Load configuration (async for Electron runtime config) + CONFIG = await loadLightningConfig() + console.log('[Lightning] Relay URL:', CONFIG.relayUrl) console.log('[Lightning] Lightning.Pub pubkey:', CONFIG.lightningPubPubkey || '(not configured)') diff --git a/lamassu-next/apps/machine/src/types/electron.d.ts b/lamassu-next/apps/machine/src/types/electron.d.ts new file mode 100644 index 0000000..40b30e7 --- /dev/null +++ b/lamassu-next/apps/machine/src/types/electron.d.ts @@ -0,0 +1,28 @@ +/** + * Type declarations for Electron API exposed via preload + */ + +export interface RuntimeConfig { + relayUrl: string + lightningPubPubkey: string + lightningPubApiUrl: string + atmPrivateKey: string + adminToken: string + machineModel: string + fiatCode: string + validatorDevice?: string + dispenserDevice?: string + cassettes?: string +} + +declare global { + interface Window { + electronAPI?: { + getVersion: () => Promise + getConfig: () => Promise + platform: NodeJS.Platform + } + } +} + +export {}