package main import ( "encoding/json" "flag" "fmt" "log" "net" "net/http" "os" "time" "potatium.local/potatium/internal/app" ) func main() { webDir := flag.String("web-dir", "web/wallet", "directory containing static wallet design preview") listen := flag.String("listen", "127.0.0.1:8080", "loopback address for development preview") flag.Parse() host, _, err := net.SplitHostPort(*listen) if err != nil || (host != "127.0.0.1" && host != "localhost" && host != "::1") { fmt.Fprintln(os.Stderr, "refusing non-loopback listener; use SSH port forwarding") os.Exit(2) } if _, err := os.Stat(*webDir + "/index.html"); err != nil { log.Fatalf("web-dir must contain index.html: %v", err) } mux := http.NewServeMux() mux.HandleFunc("GET /api/v1/status", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("Cache-Control", "no-store") if err := json.NewEncoder(w).Encode(app.CurrentStatus()); err != nil { log.Printf("status encoding failed: %v", err) } }) mux.Handle("/", http.FileServer(http.Dir(*webDir))) protected := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("X-Frame-Options", "DENY") w.Header().Set("Referrer-Policy", "no-referrer") w.Header().Set("Cache-Control", "no-store") w.Header().Set("Content-Security-Policy", "default-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; connect-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'self'") mux.ServeHTTP(w, r) }) server := &http.Server{ Addr: *listen, Handler: protected, ReadHeaderTimeout: 5 * time.Second, } log.Printf("Potatium UI preview (NO CHAIN / NO WALLET) at http://%s", *listen) log.Fatal(server.ListenAndServe()) }