Files
2025-08-08 20:52:06 +10:00

108 lines
2.9 KiB
Go

package main
import (
"encoding/json"
"log"
"net/http"
"os"
"time"
"github.com/gorilla/mux"
"github.com/sirupsen/logrus"
"passkey-auth/internal/auth"
"passkey-auth/internal/config"
"passkey-auth/internal/cors"
"passkey-auth/internal/database"
"passkey-auth/internal/handlers"
)
func main() {
// Setup logging
logrus.SetFormatter(&logrus.JSONFormatter{})
logrus.SetLevel(logrus.DebugLevel)
// Load configuration
cfg, err := config.Load()
if err != nil {
log.Fatalf("Failed to load config: %v", err)
}
// Initialize database
db, err := database.New(cfg.Database.Path)
if err != nil {
log.Fatalf("Failed to initialize database: %v", err)
}
defer db.Close()
// Initialize WebAuthn
webAuthn, err := auth.NewWebAuthn(cfg)
if err != nil {
log.Fatalf("Failed to initialize WebAuthn: %v", err)
}
// Initialize handlers
h := handlers.New(db, webAuthn, cfg)
// Setup routes
router := mux.NewRouter()
// API routes
api := router.PathPrefix("/api").Subrouter()
api.HandleFunc("/config", h.GetConfig).Methods("GET")
api.HandleFunc("/register/begin", h.BeginRegistration).Methods("POST")
api.HandleFunc("/register/finish", h.FinishRegistration).Methods("POST")
api.HandleFunc("/login/begin", h.BeginLogin).Methods("POST")
api.HandleFunc("/login/finish", h.FinishLogin).Methods("POST")
api.HandleFunc("/logout", h.Logout).Methods("POST")
api.HandleFunc("/auth/status", h.GetAuthStatus).Methods("GET")
api.HandleFunc("/users", h.ListUsers).Methods("GET")
api.HandleFunc("/users", h.CreateUser).Methods("POST")
api.HandleFunc("/users/{id}", h.UpdateUser).Methods("PUT")
api.HandleFunc("/users/{id}", h.DeleteUser).Methods("DELETE")
// Nginx auth backend endpoint
router.HandleFunc("/auth", h.AuthCheck).Methods("GET", "HEAD")
// Health check
router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(map[string]string{"status": "healthy"}); err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
}
}).Methods("GET")
// Static files for admin UI
router.PathPrefix("/").Handler(http.FileServer(http.Dir("./web/"))).Methods("GET")
// Setup CORS with wildcard support
corsHandler := cors.WildcardCORS(cors.Config{
AllowedOrigins: cfg.CORS.AllowedOrigins,
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"*"},
AllowCredentials: true,
})
handler := corsHandler(router)
// Start server
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
// Create server with proper timeouts to prevent resource exhaustion
server := &http.Server{
Addr: ":" + port,
Handler: handler,
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
IdleTimeout: 60 * time.Second,
}
logrus.Infof("Starting server on port %s", port)
if err := server.ListenAndServe(); err != nil {
log.Fatalf("Server failed to start: %v", err)
}
}