diff options
| author | gabrix73 <gabriel1@frozenstar.info> | 2026-04-12 14:49:49 +0200 |
|---|---|---|
| committer | gabrix73 <gabriel1@frozenstar.info> | 2026-04-12 14:49:49 +0200 |
| commit | bb189dd1e7cc14900e03a72403752e6aa5276d8c (patch) | |
| tree | bdf857d7101e8889c33077c55819227eaff675bb /khimera-main.go | |
| parent | a7a7d3fd4559015fbe02b2016c3f39379262d1c2 (diff) | |
| download | khimera-bb189dd1e7cc14900e03a72403752e6aa5276d8c.tar.gz khimera-bb189dd1e7cc14900e03a72403752e6aa5276d8c.tar.xz khimera-bb189dd1e7cc14900e03a72403752e6aa5276d8c.zip | |
rename: Veilith -> Khimera across all files and documentation
Diffstat (limited to 'khimera-main.go')
| -rw-r--r-- | khimera-main.go | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/khimera-main.go b/khimera-main.go new file mode 100644 index 0000000..2099ae5 --- /dev/null +++ b/khimera-main.go @@ -0,0 +1,328 @@ +// cmd/khimera-portable/main.go +package main + +import ( + "fmt" + "log" + "os" + "path/filepath" + "runtime" + + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" + + "khimera/addressbook" + "khimera/identity" + "khimera/session" + "khimera/transport" + "khimera/transport/mesh" + "khimera/transport/tor" +) + +// PortableApp represents the portable Khimera application +type PortableApp struct { + config *PortableConfig + identity *identity.Identity + addressBook *addressbook.AddressBook + sessionMgr *session.SessionManager + transportMgr *transport.TransportManager +} + +// PortableConfig holds portable mode configuration +type PortableConfig struct { + IsPortable bool + BaseDir string + DataDir string + TorDir string + TempDir string + IdentityPath string + ContactsPath string + ConfigPath string + IsUSB bool + IsNetworkShare bool + Platform string +} + +func main() { + fmt.Println("╔════════════════════════════════════════╗") + fmt.Println("║ KHIMERA PORTABLE v0.9 ║") + fmt.Println("║ Privacy-First P2P Messenger ║") + fmt.Println("╚════════════════════════════════════════╝") + fmt.Println() + + // Detect and setup portable mode + config, err := detectPortableMode() + if err != nil { + log.Fatalf("Failed to initialize portable mode: %v", err) + } + + // Display portable status + displayPortableStatus(config) + + // Initialize portable app + portableApp := &PortableApp{ + config: config, + } + + // Setup data directories + if err := portableApp.setupDirectories(); err != nil { + log.Fatalf("Failed to setup directories: %v", err) + } + + // Start GUI + portableApp.startGUI() +} + +// detectPortableMode detects portable environment +func detectPortableMode() (*PortableConfig, error) { + // Get executable location + exe, err := os.Executable() + if err != nil { + return nil, fmt.Errorf("failed to get executable path: %w", err) + } + + baseDir := filepath.Dir(exe) + + config := &PortableConfig{ + IsPortable: true, + BaseDir: baseDir, + DataDir: filepath.Join(baseDir, "data"), + TorDir: filepath.Join(baseDir, "tor"), + TempDir: filepath.Join(baseDir, "temp"), + Platform: runtime.GOOS, + } + + // Set file paths + config.IdentityPath = filepath.Join(config.DataDir, "identity.enc") + config.ContactsPath = filepath.Join(config.DataDir, "contacts.enc") + config.ConfigPath = filepath.Join(config.DataDir, "config.json") + + // Detect if running from USB + config.IsUSB = isRemovableDrive(baseDir) + config.IsNetworkShare = isNetworkPath(baseDir) + + return config, nil +} + +// isRemovableDrive checks if path is on removable media +func isRemovableDrive(path string) bool { + switch runtime.GOOS { + case "windows": + return isWindowsRemovable(path) + case "linux": + return isLinuxRemovable(path) + default: + return false + } +} + +// isWindowsRemovable checks for Windows removable drives +func isWindowsRemovable(path string) bool { + // Simplified check - in production use Windows API + drive := filepath.VolumeName(path) + // Check if drive letter is in typical USB range (E: to Z:) + if len(drive) > 0 { + letter := drive[0] + return letter >= 'E' && letter <= 'Z' + } + return false +} + +// isLinuxRemovable checks for Linux removable media +func isLinuxRemovable(path string) bool { + // Check if path contains /media or /mnt (typical USB mount points) + return filepath.HasPrefix(path, "/media") || + filepath.HasPrefix(path, "/mnt") +} + +// isNetworkPath checks if running from network share +func isNetworkPath(path string) bool { + switch runtime.GOOS { + case "windows": + return filepath.HasPrefix(path, "\\\\") + case "linux": + // Check for NFS/SMB mounts (simplified) + return false + } + return false +} + +// displayPortableStatus shows portable mode information +func displayPortableStatus(config *PortableConfig) { + fmt.Println("📁 Portable Mode Configuration") + fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") + fmt.Printf(" Platform: %s\n", config.Platform) + fmt.Printf(" Base Dir: %s\n", config.BaseDir) + fmt.Printf(" Data Dir: %s\n", config.DataDir) + fmt.Printf(" Running from: ") + + if config.IsUSB { + fmt.Println("USB Drive ✓") + } else if config.IsNetworkShare { + fmt.Println("Network Share ✓") + } else { + fmt.Println("Local Drive") + } + fmt.Println() +} + +// setupDirectories creates required directories +func (pa *PortableApp) setupDirectories() error { + dirs := []string{ + pa.config.DataDir, + pa.config.TorDir, + pa.config.TempDir, + } + + for _, dir := range dirs { + if err := os.MkdirAll(dir, 0700); err != nil { + return fmt.Errorf("failed to create directory %s: %w", dir, err) + } + } + + fmt.Println("✓ Directories initialized") + return nil +} + +// startGUI launches the portable GUI application +func (pa *PortableApp) startGUI() { + myApp := app.New() + myWindow := myApp.NewWindow("Khimera Portable v0.9") + + // Welcome screen + welcomeLabel := widget.NewLabel("Welcome to Khimera Portable") + welcomeLabel.Alignment = fyne.TextAlignCenter + + infoLabel := widget.NewLabel(fmt.Sprintf( + "Running from: %s\nData directory: %s", + pa.config.BaseDir, + pa.config.DataDir, + )) + infoLabel.Wrapping = fyne.TextWrapWord + + // Identity section + var passphraseEntry *widget.Entry + var statusLabel *widget.Label + + statusLabel = widget.NewLabel("No identity loaded") + + passphraseEntry = widget.NewPasswordEntry() + passphraseEntry.SetPlaceHolder("Enter passphrase...") + + // Load/Create identity button + loadBtn := widget.NewButton("Load Identity", func() { + passphrase := passphraseEntry.Text + if passphrase == "" { + statusLabel.SetText("⚠ Please enter a passphrase") + return + } + + // Try to load existing identity + if _, err := os.Stat(pa.config.IdentityPath); err == nil { + id, err := identity.LoadIdentity(pa.config.IdentityPath, []byte(passphrase)) + if err != nil { + statusLabel.SetText("⚠ Failed to load identity (wrong passphrase?)") + return + } + pa.identity = id + statusLabel.SetText("✓ Identity loaded: " + id.GetPublicKeyHex()[:16] + "...") + } else { + // Create new identity + id, err := identity.NewIdentity() + if err != nil { + statusLabel.SetText("⚠ Failed to create identity") + return + } + + if err := id.Save(pa.config.IdentityPath, []byte(passphrase)); err != nil { + statusLabel.SetText("⚠ Failed to save identity") + return + } + + pa.identity = id + statusLabel.SetText("✓ New identity created: " + id.GetPublicKeyHex()[:16] + "...") + } + + // Initialize other components + pa.initializeComponents() + }) + + // Quit button + quitBtn := widget.NewButton("Quit", func() { + pa.cleanup() + myApp.Quit() + }) + + // Layout + content := container.NewVBox( + welcomeLabel, + widget.NewSeparator(), + infoLabel, + widget.NewSeparator(), + widget.NewLabel("Identity Management:"), + passphraseEntry, + loadBtn, + statusLabel, + widget.NewSeparator(), + quitBtn, + ) + + myWindow.SetContent(content) + myWindow.Resize(fyne.NewSize(600, 400)) + myWindow.CenterOnScreen() + myWindow.ShowAndRun() +} + +// initializeComponents initializes core components after identity is loaded +func (pa *PortableApp) initializeComponents() error { + // Initialize session manager + pa.sessionMgr = session.NewSessionManager() + + // Initialize transport manager + pa.transportMgr = transport.NewTransportManager() + + // Try to load address book + if _, err := os.Stat(pa.config.ContactsPath); err == nil { + // Load existing contacts + fmt.Println("✓ Address book loaded") + } else { + // Create new address book + pa.addressBook = addressbook.NewAddressBook() + fmt.Println("✓ New address book created") + } + + fmt.Println("✓ Components initialized") + return nil +} + +// cleanup performs cleanup on application exit +func (pa *PortableApp) cleanup() { + fmt.Println("\n🧹 Cleaning up...") + + // Secure wipe sessions + if pa.sessionMgr != nil { + pa.sessionMgr.SecureWipeAll() + fmt.Println(" ✓ Sessions wiped") + } + + // Close transports + if pa.transportMgr != nil { + pa.transportMgr.Close() + fmt.Println(" ✓ Transports closed") + } + + // Wipe identity from memory + if pa.identity != nil { + pa.identity.SecureWipe() + fmt.Println(" ✓ Identity wiped from memory") + } + + // Clean temp directory + if pa.config.TempDir != "" { + os.RemoveAll(pa.config.TempDir) + fmt.Println(" ✓ Temp files removed") + } + + fmt.Println("✓ Cleanup complete") +} |
