158 lines
4.1 KiB
Go
158 lines
4.1 KiB
Go
package server
|
|
|
|
import (
|
|
"omega-server/local/api"
|
|
"omega-server/local/middleware/security"
|
|
"omega-server/local/utl/logging"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/gofiber/fiber/v2/middleware/cors"
|
|
"github.com/gofiber/fiber/v2/middleware/helmet"
|
|
"github.com/gofiber/fiber/v2/middleware/recover"
|
|
"github.com/gofiber/swagger"
|
|
"go.uber.org/dig"
|
|
)
|
|
|
|
func Start(di *dig.Container) *fiber.App {
|
|
app := fiber.New(fiber.Config{
|
|
AppName: "Omega Project Management",
|
|
ServerHeader: "omega-server",
|
|
EnablePrintRoutes: true,
|
|
ReadTimeout: 30 * time.Second,
|
|
WriteTimeout: 30 * time.Second,
|
|
IdleTimeout: 120 * time.Second,
|
|
BodyLimit: 10 * 1024 * 1024, // 10MB
|
|
Prefork: false,
|
|
CaseSensitive: false,
|
|
StrictRouting: false,
|
|
DisableKeepalive: false,
|
|
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
|
// Custom error handler
|
|
code := fiber.StatusInternalServerError
|
|
if e, ok := err.(*fiber.Error); ok {
|
|
code = e.Code
|
|
}
|
|
|
|
// Log error
|
|
logging.Error("HTTP Error: %v, Path: %s, Method: %s, IP: %s",
|
|
err, c.Path(), c.Method(), c.IP())
|
|
|
|
// Return JSON error response
|
|
return c.Status(code).JSON(fiber.Map{
|
|
"error": err.Error(),
|
|
"code": code,
|
|
})
|
|
},
|
|
})
|
|
|
|
// Initialize security middleware
|
|
securityMW := security.NewSecurityMiddleware()
|
|
|
|
// Add recovery middleware first
|
|
app.Use(recover.New(recover.Config{
|
|
EnableStackTrace: true,
|
|
}))
|
|
|
|
// Add security middleware stack
|
|
app.Use(securityMW.SecurityHeaders())
|
|
app.Use(securityMW.LogSecurityEvents())
|
|
app.Use(securityMW.TimeoutMiddleware(30 * time.Second))
|
|
app.Use(securityMW.RequestSizeLimit(10 * 1024 * 1024)) // 10MB
|
|
app.Use(securityMW.ValidateUserAgent())
|
|
app.Use(securityMW.ValidateContentType("application/json", "application/x-www-form-urlencoded", "multipart/form-data"))
|
|
app.Use(securityMW.InputSanitization())
|
|
app.Use(securityMW.RateLimit(100, 1*time.Minute)) // 100 requests per minute global
|
|
|
|
// Add Helmet middleware for security headers
|
|
app.Use(helmet.New(helmet.Config{
|
|
XSSProtection: "1; mode=block",
|
|
ContentTypeNosniff: "nosniff",
|
|
XFrameOptions: "DENY",
|
|
HSTSMaxAge: 31536000,
|
|
HSTSPreloadEnabled: true,
|
|
ContentSecurityPolicy: "default-src 'self'",
|
|
ReferrerPolicy: "strict-origin-when-cross-origin",
|
|
}))
|
|
|
|
// Configure CORS
|
|
allowedOrigin := os.Getenv("CORS_ALLOWED_ORIGIN")
|
|
if allowedOrigin == "" {
|
|
allowedOrigin = "http://localhost:5173"
|
|
}
|
|
|
|
app.Use(cors.New(cors.Config{
|
|
AllowOrigins: allowedOrigin,
|
|
AllowHeaders: "Origin, Content-Type, Accept, Authorization, X-Requested-With",
|
|
AllowMethods: "GET, POST, PUT, DELETE, OPTIONS, PATCH",
|
|
AllowCredentials: true,
|
|
MaxAge: 86400, // 24 hours
|
|
}))
|
|
|
|
// Add request logging middleware
|
|
app.Use(func(c *fiber.Ctx) error {
|
|
start := time.Now()
|
|
|
|
// Process request
|
|
err := c.Next()
|
|
|
|
// Log request
|
|
duration := time.Since(start)
|
|
logging.InfoResponse(
|
|
c.Method(),
|
|
c.Path(),
|
|
c.Response().StatusCode(),
|
|
duration.String(),
|
|
)
|
|
|
|
return err
|
|
})
|
|
|
|
// Swagger documentation
|
|
app.Get("/swagger/*", swagger.HandlerDefault)
|
|
|
|
// Health check endpoint
|
|
app.Get("/health", func(c *fiber.Ctx) error {
|
|
return c.JSON(fiber.Map{
|
|
"status": "healthy",
|
|
"timestamp": time.Now().UTC().Format(time.RFC3339),
|
|
"version": "1.0.0",
|
|
})
|
|
})
|
|
|
|
// Ping endpoint
|
|
app.Get("/ping", func(c *fiber.Ctx) error {
|
|
return c.SendString("pong")
|
|
})
|
|
|
|
// Initialize API routes
|
|
api.Init(di, app)
|
|
|
|
// 404 handler
|
|
app.Use(func(c *fiber.Ctx) error {
|
|
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
|
|
"error": "Route not found",
|
|
"path": c.Path(),
|
|
})
|
|
})
|
|
|
|
// Get port from environment
|
|
port := os.Getenv("PORT")
|
|
if port == "" {
|
|
port = "3000" // Default port
|
|
}
|
|
|
|
logging.Info("Starting server on port %s", port)
|
|
logging.Info("Swagger documentation available at: http://localhost:%s/swagger/", port)
|
|
logging.Info("Health check available at: http://localhost:%s/health", port)
|
|
|
|
// Start server
|
|
if err := app.Listen(":" + port); err != nil {
|
|
logging.Error("Failed to start server: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
return app
|
|
}
|