package api import ( "net/http" "time" "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/config" "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/handlers" apiMiddleware "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/middleware" "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/api/service" "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/auth" "devone.aplikasi.web.id/gitea/mario/go-ohif-proxy/internal/proxy" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" "go.uber.org/zap" ) // SetupRouter configures and returns the API router func SetupRouter(cfg *config.Config, logger *zap.Logger) http.Handler { r := chi.NewRouter() // Base middleware r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.Recoverer) r.Use(apiMiddleware.Logger(logger)) // CORS configuration r.Use(cors.Handler(cors.Options{ AllowedOrigins: []string{"*"}, // In production, restrict this to your frontend domains AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"}, ExposedHeaders: []string{"Link"}, AllowCredentials: true, MaxAge: 300, // Maximum value not ignored by any of major browsers })) // Initialize Google auth client for proxy googleAuth, err := auth.NewGoogleClient(cfg.Google.CredentialsPath) if err != nil { logger.Fatal("Failed to initialize Google auth client", zap.Error(err)) } // Initialize Healthcare API client healthcareClient := proxy.NewClient(googleAuth, cfg.Google) // Initialize JWT auth service jwtSecret := cfg.Auth.JWTSecret if jwtSecret == "" { jwtSecret = "vQ6PQqUyh7pBNOytClgN+Nw1XBq7F8Qo6VP3VwIqvHY=" // Default from your example, should be set in config } // Convert config values to time.Duration accessExpiry := time.Duration(cfg.Auth.AccessTokenExpiry) * time.Minute refreshExpiry := time.Duration(cfg.Auth.RefreshTokenExpiry) * time.Hour // Create JWT manager with config values jwtManager := auth.NewJWTManager(jwtSecret, accessExpiry, refreshExpiry) authService := service.NewAuthService(jwtManager) // Public routes that don't require authentication r.Group(func(r chi.Router) { // Health check r.Get("/health", handlers.HealthCheck) // Authentication endpoints r.Route("/auth", func(r chi.Router) { authHandler := handlers.NewAuthHandler(logger, authService) r.Post("/login", authHandler.Login) r.Post("/refresh", authHandler.RefreshToken) r.Post("/logout", authHandler.Logout) }) }) // Protected routes that require authentication r.Group(func(r chi.Router) { // Apply authentication middleware r.Use(apiMiddleware.Auth(authService, logger)) // DICOM Web routes r.Route("/dicomWeb", func(r chi.Router) { // Add audit logging middleware to DICOM routes r.Use(apiMiddleware.AuditLog(logger)) // Add patient view restriction for patient role r.Use(apiMiddleware.PatientViewRestriction(logger)) // Create handler for all DICOM requests dicomHandler := handlers.NewDicomHandler(healthcareClient, logger) // Common routes for studies with role-specific handling r.Route("/studies", func(r chi.Router) { // StudyInstanceUID parameter routes - accessible by all roles r.Get("/{studyInstanceUID}", dicomHandler.ForwardRequest) // Study details r.Get("/{studyInstanceUID}/series", dicomHandler.ForwardRequest) // Series list for study // Deep hierarchy routes - accessible by patients and all doctors r.Get("/{studyInstanceUID}/series/{seriesUID}/metadata", dicomHandler.ForwardRequest) r.Get("/{studyInstanceUID}/series/{seriesUID}/instances/{instanceUID}/frames/{frame}", dicomHandler.ForwardRequest) // Query routes - accessible by all roles r.Get("/", dicomHandler.ForwardRequest) // Study list with filters }) // Expertise doctors have full access to all DICOM endpoints r.With(apiMiddleware.RoleRequired("expertise_doctor")).HandleFunc("/*", dicomHandler.ForwardRequest) }) }) return r }