main.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package main
  2. import (
  3. "crypto/rand"
  4. "crypto/rsa"
  5. "crypto/tls"
  6. "crypto/x509"
  7. "crypto/x509/pkix"
  8. "embed"
  9. "encoding/pem"
  10. "flag"
  11. "fmt"
  12. "io/fs"
  13. "log"
  14. "math/big"
  15. "net/http"
  16. "os"
  17. "time"
  18. )
  19. //go:embed www/*
  20. var embeddedFiles embed.FS
  21. const (
  22. certFile = "cert.pem"
  23. keyFile = "key.pem"
  24. )
  25. func main() {
  26. dev := flag.Bool("dev", true, "Serve files from www/ directory instead of embedded files")
  27. addr := flag.String("addr", ":8443", "HTTPS server address")
  28. flag.Parse()
  29. // Check and generate certs if needed
  30. if !fileExists(certFile) || !fileExists(keyFile) {
  31. fmt.Println("Certificates not found, generating self-signed certificate...")
  32. if err := generateSelfSignedCert(certFile, keyFile); err != nil {
  33. log.Fatalf("Failed to generate certificate: %v", err)
  34. }
  35. }
  36. var handler http.Handler
  37. if *dev {
  38. fmt.Println("Development mode: serving from www/ directory")
  39. handler = http.FileServer(http.Dir("www"))
  40. } else {
  41. fmt.Println("Production mode: serving embedded files")
  42. subFS, err := fs.Sub(embeddedFiles, "www")
  43. if err != nil {
  44. log.Fatalf("Failed to get sub filesystem: %v", err)
  45. }
  46. handler = http.FileServer(http.FS(subFS))
  47. }
  48. mux := http.NewServeMux()
  49. mux.Handle("/", handler)
  50. server := &http.Server{
  51. Addr: *addr,
  52. Handler: mux,
  53. TLSConfig: &tls.Config{
  54. MinVersion: tls.VersionTLS12,
  55. },
  56. }
  57. fmt.Printf("Starting HTTPS server on %s\n", *addr)
  58. log.Fatal(server.ListenAndServeTLS(certFile, keyFile))
  59. }
  60. func fileExists(filename string) bool {
  61. info, err := os.Stat(filename)
  62. return err == nil && !info.IsDir()
  63. }
  64. func generateSelfSignedCert(certPath, keyPath string) error {
  65. priv, err := rsa.GenerateKey(rand.Reader, 2048)
  66. if err != nil {
  67. return err
  68. }
  69. serialNumber, err := rand.Int(rand.Reader, big.NewInt(1<<62))
  70. if err != nil {
  71. return err
  72. }
  73. template := x509.Certificate{
  74. SerialNumber: serialNumber,
  75. Subject: pkix.Name{
  76. Organization: []string{"RedesKVM"},
  77. },
  78. NotBefore: time.Now(),
  79. NotAfter: time.Now().Add(365 * 24 * time.Hour),
  80. KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
  81. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  82. BasicConstraintsValid: true,
  83. }
  84. // Add localhost as SAN
  85. template.DNSNames = []string{"localhost"}
  86. derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
  87. if err != nil {
  88. return err
  89. }
  90. certOut, err := os.Create(certPath)
  91. if err != nil {
  92. return err
  93. }
  94. defer certOut.Close()
  95. if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
  96. return err
  97. }
  98. keyOut, err := os.OpenFile(keyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
  99. if err != nil {
  100. return err
  101. }
  102. defer keyOut.Close()
  103. privBytes := x509.MarshalPKCS1PrivateKey(priv)
  104. if err := pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: privBytes}); err != nil {
  105. return err
  106. }
  107. return nil
  108. }