package main import ( "crypto/rand" "crypto/rsa" "crypto/tls" "crypto/x509" "crypto/x509/pkix" "embed" "encoding/pem" "flag" "fmt" "io/fs" "log" "math/big" "net/http" "os" "time" ) //go:embed www/* var embeddedFiles embed.FS const ( certFile = "cert.pem" keyFile = "key.pem" ) func main() { dev := flag.Bool("dev", true, "Serve files from www/ directory instead of embedded files") addr := flag.String("addr", ":8443", "HTTPS server address") flag.Parse() // Check and generate certs if needed if !fileExists(certFile) || !fileExists(keyFile) { fmt.Println("Certificates not found, generating self-signed certificate...") if err := generateSelfSignedCert(certFile, keyFile); err != nil { log.Fatalf("Failed to generate certificate: %v", err) } } var handler http.Handler if *dev { fmt.Println("Development mode: serving from www/ directory") handler = http.FileServer(http.Dir("www")) } else { fmt.Println("Production mode: serving embedded files") subFS, err := fs.Sub(embeddedFiles, "www") if err != nil { log.Fatalf("Failed to get sub filesystem: %v", err) } handler = http.FileServer(http.FS(subFS)) } mux := http.NewServeMux() mux.Handle("/", handler) server := &http.Server{ Addr: *addr, Handler: mux, TLSConfig: &tls.Config{ MinVersion: tls.VersionTLS12, }, } fmt.Printf("Starting HTTPS server on %s\n", *addr) log.Fatal(server.ListenAndServeTLS(certFile, keyFile)) } func fileExists(filename string) bool { info, err := os.Stat(filename) return err == nil && !info.IsDir() } func generateSelfSignedCert(certPath, keyPath string) error { priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return err } serialNumber, err := rand.Int(rand.Reader, big.NewInt(1<<62)) if err != nil { return err } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"RedesKVM"}, }, NotBefore: time.Now(), NotAfter: time.Now().Add(365 * 24 * time.Hour), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, } // Add localhost as SAN template.DNSNames = []string{"localhost"} derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) if err != nil { return err } certOut, err := os.Create(certPath) if err != nil { return err } defer certOut.Close() if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { return err } keyOut, err := os.OpenFile(keyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { return err } defer keyOut.Close() privBytes := x509.MarshalPKCS1PrivateKey(priv) if err := pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: privBytes}); err != nil { return err } return nil }