refactor: use 'c' alias for constants package
- Update all imports from 'constants' to 'c' for brevity - Replace all 'constants.' references with 'c.' - Fix remaining hardcoded content-type headers in httputil - Fix remaining hardcoded User-Agent and Accept headers - Rename CSRF receiver from 'c' to 'csrf' to avoid conflict - Add ContentTypePlainSimple constant for Accept header matching - Fix JSONCached to use proper integer formatting
This commit is contained in:
@@ -7,26 +7,26 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/juanatsap/cv-site/internal/constants"
|
||||
c "github.com/juanatsap/cv-site/internal/constants"
|
||||
)
|
||||
|
||||
// SecurityHeaders adds production-grade security headers to responses
|
||||
func SecurityHeaders(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Prevent clickjacking
|
||||
w.Header().Set(constants.HeaderXFrameOptions, constants.FrameOptionsSameOrigin)
|
||||
w.Header().Set(c.HeaderXFrameOptions, c.FrameOptionsSameOrigin)
|
||||
|
||||
// Prevent MIME type sniffing
|
||||
w.Header().Set(constants.HeaderXContentTypeOpts, constants.NoSniff)
|
||||
w.Header().Set(c.HeaderXContentTypeOpts, c.NoSniff)
|
||||
|
||||
// XSS Protection (legacy but still useful for older browsers)
|
||||
w.Header().Set(constants.HeaderXXSSProtection, constants.XSSProtection)
|
||||
w.Header().Set(c.HeaderXXSSProtection, c.XSSProtection)
|
||||
|
||||
// Referrer policy - strict privacy
|
||||
w.Header().Set(constants.HeaderReferrerPolicy, constants.ReferrerPolicy)
|
||||
w.Header().Set(c.HeaderReferrerPolicy, c.ReferrerPolicy)
|
||||
|
||||
// Permissions Policy - disable unnecessary features
|
||||
w.Header().Set(constants.HeaderPermissionsPolicy,
|
||||
w.Header().Set(c.HeaderPermissionsPolicy,
|
||||
"geolocation=(), microphone=(), camera=(), payment=(), usb=(), "+
|
||||
"magnetometer=(), gyroscope=(), accelerometer=()")
|
||||
|
||||
@@ -40,12 +40,12 @@ func SecurityHeaders(next http.Handler) http.Handler {
|
||||
"frame-ancestors 'self'; " +
|
||||
"base-uri 'self'; " +
|
||||
"form-action 'self'"
|
||||
w.Header().Set(constants.HeaderCSP, csp)
|
||||
w.Header().Set(c.HeaderCSP, csp)
|
||||
|
||||
// HSTS - only in production with HTTPS
|
||||
if os.Getenv(constants.EnvVarGOEnv) == constants.EnvProduction {
|
||||
if os.Getenv(c.EnvVarGOEnv) == c.EnvProduction {
|
||||
// 1 year max-age, include subdomains
|
||||
w.Header().Set(constants.HeaderHSTS, constants.HSTSMaxAge)
|
||||
w.Header().Set(c.HeaderHSTS, c.HSTSMaxAge)
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
@@ -76,7 +76,7 @@ func OriginChecker(next http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
// Check Origin header (for CORS requests)
|
||||
origin := r.Header.Get(constants.HeaderOrigin)
|
||||
origin := r.Header.Get(c.HeaderOrigin)
|
||||
if origin != "" {
|
||||
if !isAllowedOrigin(origin, allowedOrigins) {
|
||||
http.Error(w, "Forbidden: External access not allowed", http.StatusForbidden)
|
||||
@@ -85,7 +85,7 @@ func OriginChecker(next http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
// Check Referer header (for direct requests)
|
||||
referer := r.Header.Get(constants.HeaderReferer)
|
||||
referer := r.Header.Get(c.HeaderReferer)
|
||||
if referer != "" {
|
||||
if !isAllowedOrigin(referer, allowedOrigins) {
|
||||
http.Error(w, "Forbidden: External access not allowed", http.StatusForbidden)
|
||||
@@ -98,7 +98,7 @@ func OriginChecker(next http.Handler) http.Handler {
|
||||
if origin == "" && referer == "" {
|
||||
// For production, you might want to be stricter here
|
||||
// For now, allow it (users can bookmark /export/pdf directly)
|
||||
if os.Getenv(constants.EnvVarGOEnv) == constants.EnvProduction && r.URL.Path == constants.RouteExportPDF {
|
||||
if os.Getenv(c.EnvVarGOEnv) == c.EnvProduction && r.URL.Path == c.RouteExportPDF {
|
||||
// In production, require at least a referer for PDF endpoint
|
||||
http.Error(w, "Forbidden: Direct access not allowed", http.StatusForbidden)
|
||||
return
|
||||
@@ -163,16 +163,16 @@ func NewRateLimiter(limit int, window time.Duration) *RateLimiter {
|
||||
func (rl *RateLimiter) Middleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Get client IP (handle X-Forwarded-For for proxies)
|
||||
ip := r.Header.Get(constants.HeaderXForwardedFor)
|
||||
ip := r.Header.Get(c.HeaderXForwardedFor)
|
||||
if ip == "" {
|
||||
ip = r.Header.Get(constants.HeaderXRealIP)
|
||||
ip = r.Header.Get(c.HeaderXRealIP)
|
||||
}
|
||||
if ip == "" {
|
||||
ip = strings.Split(r.RemoteAddr, ":")[0]
|
||||
}
|
||||
|
||||
if !rl.allow(ip) {
|
||||
w.Header().Set(constants.HeaderRetryAfter, "60")
|
||||
w.Header().Set(c.HeaderRetryAfter, "60")
|
||||
http.Error(w, "Rate limit exceeded. Please try again later.", http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
@@ -227,12 +227,12 @@ func (rl *RateLimiter) cleanup() {
|
||||
// 1 hour in development, 1 day in production
|
||||
func CacheControl(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
cacheValue := constants.CachePublic1Hour
|
||||
if os.Getenv(constants.EnvVarGOEnv) == constants.EnvProduction {
|
||||
cacheValue = constants.CachePublic1Day
|
||||
cacheValue := c.CachePublic1Hour
|
||||
if os.Getenv(c.EnvVarGOEnv) == c.EnvProduction {
|
||||
cacheValue = c.CachePublic1Day
|
||||
}
|
||||
|
||||
w.Header().Set(constants.HeaderCacheControl, cacheValue)
|
||||
w.Header().Set(c.HeaderCacheControl, cacheValue)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
@@ -243,12 +243,12 @@ func DynamicCacheControl(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// For dynamic HTML pages: short cache, must revalidate
|
||||
// This improves performance while ensuring fresh content
|
||||
if os.Getenv(constants.EnvVarGOEnv) == constants.EnvProduction {
|
||||
if os.Getenv(c.EnvVarGOEnv) == c.EnvProduction {
|
||||
// Production: 5 minutes cache, but must revalidate
|
||||
w.Header().Set(constants.HeaderCacheControl, constants.CachePublic5Min)
|
||||
w.Header().Set(c.HeaderCacheControl, c.CachePublic5Min)
|
||||
} else {
|
||||
// Development: no cache for easier testing
|
||||
w.Header().Set(constants.HeaderCacheControl, constants.CacheNoStore)
|
||||
w.Header().Set(c.HeaderCacheControl, c.CacheNoStore)
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user