Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
490
cloud/maplepress-backend/internal/interface/http/server.go
Normal file
490
cloud/maplepress-backend/internal/interface/http/server.go
Normal file
|
|
@ -0,0 +1,490 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/config"
|
||||
httpmw "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/http/middleware"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/interface/http/handler/admin"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/interface/http/handler/gateway"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/interface/http/handler/healthcheck"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/interface/http/handler/plugin"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/interface/http/handler/site"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/interface/http/handler/tenant"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/interface/http/handler/user"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/interface/http/middleware"
|
||||
)
|
||||
|
||||
// Server represents the HTTP server
|
||||
type Server struct {
|
||||
server *http.Server
|
||||
logger *zap.Logger
|
||||
jwtMiddleware *httpmw.JWTMiddleware
|
||||
apikeyMiddleware *httpmw.APIKeyMiddleware
|
||||
rateLimitMiddlewares *httpmw.RateLimitMiddlewares // CWE-770: Registration and auth endpoints rate limiting
|
||||
securityHeadersMiddleware *httpmw.SecurityHeadersMiddleware
|
||||
requestSizeLimitMw *httpmw.RequestSizeLimitMiddleware
|
||||
config *config.Config
|
||||
healthHandler *healthcheck.Handler
|
||||
registerHandler *gateway.RegisterHandler
|
||||
loginHandler *gateway.LoginHandler
|
||||
refreshTokenHandler *gateway.RefreshTokenHandler
|
||||
helloHandler *gateway.HelloHandler
|
||||
meHandler *gateway.MeHandler
|
||||
createTenantHandler *tenant.CreateHandler
|
||||
getTenantHandler *tenant.GetHandler
|
||||
createUserHandler *user.CreateHandler
|
||||
getUserHandler *user.GetHandler
|
||||
createSiteHandler *site.CreateHandler
|
||||
getSiteHandler *site.GetHandler
|
||||
listSitesHandler *site.ListHandler
|
||||
deleteSiteHandler *site.DeleteHandler
|
||||
rotateSiteAPIKeyHandler *site.RotateAPIKeyHandler
|
||||
verifySiteHandler *site.VerifySiteHandler
|
||||
pluginStatusHandler *plugin.StatusHandler
|
||||
pluginVerifyHandler *plugin.PluginVerifyHandler
|
||||
pluginVersionHandler *plugin.VersionHandler
|
||||
syncPagesHandler *plugin.SyncPagesHandler
|
||||
searchPagesHandler *plugin.SearchPagesHandler
|
||||
deletePagesHandler *plugin.DeletePagesHandler
|
||||
syncStatusHandler *plugin.SyncStatusHandler
|
||||
unlockAccountHandler *admin.UnlockAccountHandler
|
||||
accountStatusHandler *admin.AccountStatusHandler
|
||||
}
|
||||
|
||||
// ProvideServer creates a new HTTP server
|
||||
func ProvideServer(
|
||||
cfg *config.Config,
|
||||
logger *zap.Logger,
|
||||
jwtMiddleware *httpmw.JWTMiddleware,
|
||||
apikeyMiddleware *httpmw.APIKeyMiddleware,
|
||||
rateLimitMiddlewares *httpmw.RateLimitMiddlewares,
|
||||
securityHeadersMiddleware *httpmw.SecurityHeadersMiddleware,
|
||||
requestSizeLimitMw *httpmw.RequestSizeLimitMiddleware,
|
||||
healthHandler *healthcheck.Handler,
|
||||
registerHandler *gateway.RegisterHandler,
|
||||
loginHandler *gateway.LoginHandler,
|
||||
refreshTokenHandler *gateway.RefreshTokenHandler,
|
||||
helloHandler *gateway.HelloHandler,
|
||||
meHandler *gateway.MeHandler,
|
||||
createTenantHandler *tenant.CreateHandler,
|
||||
getTenantHandler *tenant.GetHandler,
|
||||
createUserHandler *user.CreateHandler,
|
||||
getUserHandler *user.GetHandler,
|
||||
createSiteHandler *site.CreateHandler,
|
||||
getSiteHandler *site.GetHandler,
|
||||
listSitesHandler *site.ListHandler,
|
||||
deleteSiteHandler *site.DeleteHandler,
|
||||
rotateSiteAPIKeyHandler *site.RotateAPIKeyHandler,
|
||||
verifySiteHandler *site.VerifySiteHandler,
|
||||
pluginStatusHandler *plugin.StatusHandler,
|
||||
pluginVerifyHandler *plugin.PluginVerifyHandler,
|
||||
pluginVersionHandler *plugin.VersionHandler,
|
||||
syncPagesHandler *plugin.SyncPagesHandler,
|
||||
searchPagesHandler *plugin.SearchPagesHandler,
|
||||
deletePagesHandler *plugin.DeletePagesHandler,
|
||||
syncStatusHandler *plugin.SyncStatusHandler,
|
||||
unlockAccountHandler *admin.UnlockAccountHandler,
|
||||
accountStatusHandler *admin.AccountStatusHandler,
|
||||
) *Server {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
s := &Server{
|
||||
logger: logger,
|
||||
jwtMiddleware: jwtMiddleware,
|
||||
apikeyMiddleware: apikeyMiddleware,
|
||||
rateLimitMiddlewares: rateLimitMiddlewares,
|
||||
securityHeadersMiddleware: securityHeadersMiddleware,
|
||||
requestSizeLimitMw: requestSizeLimitMw,
|
||||
config: cfg,
|
||||
healthHandler: healthHandler,
|
||||
registerHandler: registerHandler,
|
||||
loginHandler: loginHandler,
|
||||
refreshTokenHandler: refreshTokenHandler,
|
||||
helloHandler: helloHandler,
|
||||
meHandler: meHandler,
|
||||
createTenantHandler: createTenantHandler,
|
||||
getTenantHandler: getTenantHandler,
|
||||
createUserHandler: createUserHandler,
|
||||
getUserHandler: getUserHandler,
|
||||
createSiteHandler: createSiteHandler,
|
||||
getSiteHandler: getSiteHandler,
|
||||
listSitesHandler: listSitesHandler,
|
||||
deleteSiteHandler: deleteSiteHandler,
|
||||
rotateSiteAPIKeyHandler: rotateSiteAPIKeyHandler,
|
||||
verifySiteHandler: verifySiteHandler,
|
||||
pluginStatusHandler: pluginStatusHandler,
|
||||
pluginVerifyHandler: pluginVerifyHandler,
|
||||
pluginVersionHandler: pluginVersionHandler,
|
||||
syncPagesHandler: syncPagesHandler,
|
||||
searchPagesHandler: searchPagesHandler,
|
||||
deletePagesHandler: deletePagesHandler,
|
||||
syncStatusHandler: syncStatusHandler,
|
||||
unlockAccountHandler: unlockAccountHandler,
|
||||
accountStatusHandler: accountStatusHandler,
|
||||
}
|
||||
|
||||
// Register routes
|
||||
s.registerRoutes(mux)
|
||||
|
||||
// Create HTTP server
|
||||
// CWE-770: Configure timeouts to prevent resource exhaustion
|
||||
s.server = &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port),
|
||||
Handler: s.applyMiddleware(mux),
|
||||
ReadTimeout: cfg.HTTP.ReadTimeout,
|
||||
WriteTimeout: cfg.HTTP.WriteTimeout,
|
||||
IdleTimeout: cfg.HTTP.IdleTimeout,
|
||||
}
|
||||
|
||||
logger.Info("✓ HTTP server configured",
|
||||
zap.String("address", s.server.Addr),
|
||||
zap.Duration("read_timeout", cfg.HTTP.ReadTimeout),
|
||||
zap.Duration("write_timeout", cfg.HTTP.WriteTimeout),
|
||||
zap.Int64("max_body_size", cfg.HTTP.MaxRequestBodySize))
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// registerRoutes registers all HTTP routes
|
||||
func (s *Server) registerRoutes(mux *http.ServeMux) {
|
||||
// ===== PUBLIC ROUTES (No authentication, no tenant) =====
|
||||
// Health check
|
||||
mux.HandleFunc("GET /health", s.healthHandler.Handle)
|
||||
|
||||
// Version endpoint - public API for checking backend version
|
||||
mux.HandleFunc("GET /api/v1/version", s.pluginVersionHandler.Handle)
|
||||
|
||||
// Public gateway routes (registration, login, etc.)
|
||||
// CWE-770: Apply request size limits and rate limiting
|
||||
// Apply small size limit (1MB) for registration/login endpoints
|
||||
if s.config.RateLimit.RegistrationEnabled {
|
||||
mux.HandleFunc("POST /api/v1/register",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyRegistrationRateLimit(s.registerHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
} else {
|
||||
mux.HandleFunc("POST /api/v1/register",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.registerHandler.Handle),
|
||||
).ServeHTTP)
|
||||
}
|
||||
mux.HandleFunc("POST /api/v1/login",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.loginHandler.Handle),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("POST /api/v1/refresh",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.refreshTokenHandler.Handle),
|
||||
).ServeHTTP)
|
||||
|
||||
// ===== AUTHENTICATED ROUTES (JWT only, no tenant context) =====
|
||||
// Gateway routes
|
||||
// CWE-770: Apply small size limit (1MB) and generic rate limiting for hello endpoint
|
||||
if s.config.RateLimit.GenericEnabled {
|
||||
mux.HandleFunc("POST /api/v1/hello",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthOnlyWithGenericRateLimit(s.helloHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
} else {
|
||||
mux.HandleFunc("POST /api/v1/hello",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthOnly(s.helloHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
}
|
||||
|
||||
// CWE-770: Apply generic rate limiting to /me endpoint to prevent profile enumeration and DoS
|
||||
if s.config.RateLimit.GenericEnabled {
|
||||
mux.HandleFunc("GET /api/v1/me",
|
||||
s.applyAuthOnlyWithGenericRateLimit(s.meHandler.Handle))
|
||||
} else {
|
||||
mux.HandleFunc("GET /api/v1/me", s.applyAuthOnly(s.meHandler.Handle))
|
||||
}
|
||||
|
||||
// Tenant management routes - these operate at system/admin level
|
||||
// CWE-770: Apply small size limit (1MB) and generic rate limiting for tenant creation
|
||||
if s.config.RateLimit.GenericEnabled {
|
||||
mux.HandleFunc("POST /api/v1/tenants",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthOnlyWithGenericRateLimit(s.createTenantHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("GET /api/v1/tenants/{id}", s.applyAuthOnlyWithGenericRateLimit(s.getTenantHandler.HandleByID))
|
||||
mux.HandleFunc("GET /api/v1/tenants/slug/{slug}", s.applyAuthOnlyWithGenericRateLimit(s.getTenantHandler.HandleBySlug))
|
||||
} else {
|
||||
mux.HandleFunc("POST /api/v1/tenants",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthOnly(s.createTenantHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("GET /api/v1/tenants/{id}", s.applyAuthOnly(s.getTenantHandler.HandleByID))
|
||||
mux.HandleFunc("GET /api/v1/tenants/slug/{slug}", s.applyAuthOnly(s.getTenantHandler.HandleBySlug))
|
||||
}
|
||||
|
||||
// ===== TENANT-SCOPED ROUTES (JWT + Tenant context) =====
|
||||
// User routes - these operate within a tenant context
|
||||
// CWE-770: Apply small size limit (1MB) and generic rate limiting for user creation
|
||||
if s.config.RateLimit.GenericEnabled {
|
||||
mux.HandleFunc("POST /api/v1/users",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthAndTenantWithGenericRateLimit(s.createUserHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("GET /api/v1/users/{id}", s.applyAuthAndTenantWithGenericRateLimit(s.getUserHandler.Handle))
|
||||
} else {
|
||||
mux.HandleFunc("POST /api/v1/users",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthAndTenant(s.createUserHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("GET /api/v1/users/{id}", s.applyAuthAndTenant(s.getUserHandler.Handle))
|
||||
}
|
||||
|
||||
// Site management routes - JWT authenticated, tenant-scoped
|
||||
// CWE-770: Apply small size limit (1MB) and generic rate limiting for site management
|
||||
if s.config.RateLimit.GenericEnabled {
|
||||
mux.HandleFunc("POST /api/v1/sites",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthAndTenantWithGenericRateLimit(s.createSiteHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("GET /api/v1/sites", s.applyAuthAndTenantWithGenericRateLimit(s.listSitesHandler.Handle))
|
||||
mux.HandleFunc("GET /api/v1/sites/{id}", s.applyAuthAndTenantWithGenericRateLimit(s.getSiteHandler.Handle))
|
||||
mux.HandleFunc("DELETE /api/v1/sites/{id}", s.applyAuthAndTenantWithGenericRateLimit(s.deleteSiteHandler.Handle))
|
||||
mux.HandleFunc("POST /api/v1/sites/{id}/rotate-api-key",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthAndTenantWithGenericRateLimit(s.rotateSiteAPIKeyHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("POST /api/v1/sites/{id}/verify",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthAndTenantWithGenericRateLimit(s.verifySiteHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
} else {
|
||||
mux.HandleFunc("POST /api/v1/sites",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthAndTenant(s.createSiteHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("GET /api/v1/sites", s.applyAuthAndTenant(s.listSitesHandler.Handle))
|
||||
mux.HandleFunc("GET /api/v1/sites/{id}", s.applyAuthAndTenant(s.getSiteHandler.Handle))
|
||||
mux.HandleFunc("DELETE /api/v1/sites/{id}", s.applyAuthAndTenant(s.deleteSiteHandler.Handle))
|
||||
mux.HandleFunc("POST /api/v1/sites/{id}/rotate-api-key",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthAndTenant(s.rotateSiteAPIKeyHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("POST /api/v1/sites/{id}/verify",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthAndTenant(s.verifySiteHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
}
|
||||
|
||||
// ===== ADMIN ROUTES (JWT authenticated) =====
|
||||
// CWE-307: Admin endpoints for account lockout management
|
||||
// CWE-770: Apply small size limit (1MB) and generic rate limiting for admin endpoints
|
||||
if s.config.RateLimit.GenericEnabled {
|
||||
mux.HandleFunc("POST /api/v1/admin/unlock-account",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthOnlyWithGenericRateLimit(s.unlockAccountHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("GET /api/v1/admin/account-status", s.applyAuthOnlyWithGenericRateLimit(s.accountStatusHandler.Handle))
|
||||
} else {
|
||||
mux.HandleFunc("POST /api/v1/admin/unlock-account",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAuthOnly(s.unlockAccountHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("GET /api/v1/admin/account-status", s.applyAuthOnly(s.accountStatusHandler.Handle))
|
||||
}
|
||||
|
||||
// ===== WORDPRESS PLUGIN API ROUTES (API Key authentication) =====
|
||||
// CWE-770: Apply lenient site-based rate limiting to protect core business endpoints
|
||||
// Default: 1000 requests/hour per site (very lenient for high-volume legitimate traffic)
|
||||
|
||||
if s.config.RateLimit.PluginAPIEnabled {
|
||||
// Plugin status/verification - with rate limiting
|
||||
mux.HandleFunc("GET /api/v1/plugin/status", s.applyAPIKeyAuthWithPluginRateLimit(s.pluginStatusHandler.Handle))
|
||||
|
||||
// Plugin domain verification endpoint
|
||||
mux.HandleFunc("POST /api/v1/plugin/verify",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAPIKeyAuthWithPluginRateLimit(s.pluginVerifyHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
|
||||
// Page sync and search routes
|
||||
// CWE-770: Apply larger size limit (50MB) for page sync (bulk operations) + rate limiting
|
||||
mux.HandleFunc("POST /api/v1/plugin/pages/sync",
|
||||
s.requestSizeLimitMw.LimitLarge()(
|
||||
http.HandlerFunc(s.applyAPIKeyAuthWithPluginRateLimit(s.syncPagesHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
// Apply medium limit (5MB) for search and delete operations + rate limiting
|
||||
mux.HandleFunc("POST /api/v1/plugin/pages/search",
|
||||
s.requestSizeLimitMw.LimitMedium()(
|
||||
http.HandlerFunc(s.applyAPIKeyAuthWithPluginRateLimit(s.searchPagesHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("DELETE /api/v1/plugin/pages",
|
||||
s.requestSizeLimitMw.LimitMedium()(
|
||||
http.HandlerFunc(s.applyAPIKeyAuthWithPluginRateLimit(s.deletePagesHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("DELETE /api/v1/plugin/pages/all", s.applyAPIKeyAuthWithPluginRateLimit(s.deletePagesHandler.HandleDeleteAll))
|
||||
mux.HandleFunc("GET /api/v1/plugin/pages/status", s.applyAPIKeyAuthWithPluginRateLimit(s.syncStatusHandler.Handle))
|
||||
mux.HandleFunc("GET /api/v1/plugin/pages/{page_id}", s.applyAPIKeyAuthWithPluginRateLimit(s.syncStatusHandler.HandleGetPageDetails))
|
||||
} else {
|
||||
// Plugin endpoints without rate limiting (not recommended for production)
|
||||
mux.HandleFunc("GET /api/v1/plugin/status", s.applyAPIKeyAuth(s.pluginStatusHandler.Handle))
|
||||
|
||||
// Plugin domain verification endpoint
|
||||
mux.HandleFunc("POST /api/v1/plugin/verify",
|
||||
s.requestSizeLimitMw.LimitSmall()(
|
||||
http.HandlerFunc(s.applyAPIKeyAuth(s.pluginVerifyHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
|
||||
mux.HandleFunc("POST /api/v1/plugin/pages/sync",
|
||||
s.requestSizeLimitMw.LimitLarge()(
|
||||
http.HandlerFunc(s.applyAPIKeyAuth(s.syncPagesHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("POST /api/v1/plugin/pages/search",
|
||||
s.requestSizeLimitMw.LimitMedium()(
|
||||
http.HandlerFunc(s.applyAPIKeyAuth(s.searchPagesHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("DELETE /api/v1/plugin/pages",
|
||||
s.requestSizeLimitMw.LimitMedium()(
|
||||
http.HandlerFunc(s.applyAPIKeyAuth(s.deletePagesHandler.Handle)),
|
||||
).ServeHTTP)
|
||||
mux.HandleFunc("DELETE /api/v1/plugin/pages/all", s.applyAPIKeyAuth(s.deletePagesHandler.HandleDeleteAll))
|
||||
mux.HandleFunc("GET /api/v1/plugin/pages/status", s.applyAPIKeyAuth(s.syncStatusHandler.Handle))
|
||||
mux.HandleFunc("GET /api/v1/plugin/pages/{page_id}", s.applyAPIKeyAuth(s.syncStatusHandler.HandleGetPageDetails))
|
||||
}
|
||||
}
|
||||
|
||||
// applyMiddleware applies global middleware to all routes
|
||||
func (s *Server) applyMiddleware(handler http.Handler) http.Handler {
|
||||
// Apply middleware in order (innermost to outermost)
|
||||
// 1. Logger middleware (logging)
|
||||
// 2. Security headers middleware (CWE-693: Protection Mechanism Failure)
|
||||
handler = middleware.LoggerMiddleware(s.logger)(handler)
|
||||
handler = s.securityHeadersMiddleware.Handler(handler)
|
||||
return handler
|
||||
}
|
||||
|
||||
// applyAuthOnly applies only JWT authentication middleware (no tenant)
|
||||
func (s *Server) applyAuthOnly(handler http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Chain: JWT validation -> Auth check -> Handler
|
||||
s.jwtMiddleware.Handler(
|
||||
s.jwtMiddleware.RequireAuth(
|
||||
http.HandlerFunc(handler),
|
||||
),
|
||||
).ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// applyAuthOnlyWithGenericRateLimit applies JWT authentication + generic rate limiting (CWE-770)
|
||||
// Used for authenticated CRUD endpoints (tenant/user/site management, admin, /me, /hello)
|
||||
// Applies user-based rate limiting (extracted from JWT context)
|
||||
func (s *Server) applyAuthOnlyWithGenericRateLimit(handler http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Chain: JWT validation -> Auth check -> Generic rate limit (user-based) -> Handler
|
||||
s.jwtMiddleware.Handler(
|
||||
s.jwtMiddleware.RequireAuth(
|
||||
s.rateLimitMiddlewares.Generic.HandlerWithUserKey(
|
||||
http.HandlerFunc(handler),
|
||||
),
|
||||
),
|
||||
).ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// applyAuthAndTenant applies JWT authentication + tenant middleware
|
||||
func (s *Server) applyAuthAndTenant(handler http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Chain: JWT validation -> Auth check -> Tenant -> Handler
|
||||
s.jwtMiddleware.Handler(
|
||||
s.jwtMiddleware.RequireAuth(
|
||||
middleware.TenantMiddleware()(
|
||||
http.HandlerFunc(handler),
|
||||
),
|
||||
),
|
||||
).ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// applyAuthAndTenantWithGenericRateLimit applies JWT authentication + tenant + generic rate limiting (CWE-770)
|
||||
// Used for tenant-scoped CRUD endpoints (user/site management)
|
||||
// Applies user-based rate limiting (extracted from JWT context)
|
||||
func (s *Server) applyAuthAndTenantWithGenericRateLimit(handler http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Chain: JWT validation -> Auth check -> Tenant -> Generic rate limit (user-based) -> Handler
|
||||
s.jwtMiddleware.Handler(
|
||||
s.jwtMiddleware.RequireAuth(
|
||||
middleware.TenantMiddleware()(
|
||||
s.rateLimitMiddlewares.Generic.HandlerWithUserKey(
|
||||
http.HandlerFunc(handler),
|
||||
),
|
||||
),
|
||||
),
|
||||
).ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// applyAPIKeyAuth applies API key authentication middleware (for WordPress plugin)
|
||||
func (s *Server) applyAPIKeyAuth(handler http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Chain: API key validation -> Require API key -> Handler
|
||||
s.apikeyMiddleware.Handler(
|
||||
s.apikeyMiddleware.RequireAPIKey(
|
||||
http.HandlerFunc(handler),
|
||||
),
|
||||
).ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// applyAPIKeyAuthWithPluginRateLimit applies API key authentication + plugin API rate limiting (CWE-770)
|
||||
// Used for WordPress Plugin API endpoints (core business endpoints)
|
||||
// Applies site-based rate limiting (extracted from API key context)
|
||||
func (s *Server) applyAPIKeyAuthWithPluginRateLimit(handler http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Chain: API key validation -> Require API key -> Plugin rate limit (site-based) -> Handler
|
||||
s.apikeyMiddleware.Handler(
|
||||
s.apikeyMiddleware.RequireAPIKey(
|
||||
s.rateLimitMiddlewares.PluginAPI.HandlerWithSiteKey(
|
||||
http.HandlerFunc(handler),
|
||||
),
|
||||
),
|
||||
).ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// applyRegistrationRateLimit applies rate limiting middleware for registration (CWE-770)
|
||||
func (s *Server) applyRegistrationRateLimit(handler http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Chain: Rate limit check -> Handler
|
||||
s.rateLimitMiddlewares.Registration.Handler(
|
||||
http.HandlerFunc(handler),
|
||||
).ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// Start starts the HTTP server
|
||||
func (s *Server) Start() error {
|
||||
s.logger.Info("")
|
||||
s.logger.Info("🚀 MaplePress Backend is ready!")
|
||||
s.logger.Info("",
|
||||
zap.String("address", s.server.Addr),
|
||||
zap.String("url", fmt.Sprintf("http://localhost:%s", s.server.Addr[len(s.server.Addr)-4:])))
|
||||
s.logger.Info("")
|
||||
|
||||
if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
return fmt.Errorf("failed to start server: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shutdown gracefully shuts down the HTTP server
|
||||
func (s *Server) Shutdown(ctx context.Context) error {
|
||||
s.logger.Info("shutting down HTTP server")
|
||||
|
||||
if err := s.server.Shutdown(ctx); err != nil {
|
||||
return fmt.Errorf("failed to shutdown server: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("HTTP server shut down successfully")
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue