package middleware import ( "context" "log" "net/http" "ristek-task-be/internal/jwt" "strings" ) type wrapper struct { http.ResponseWriter request *http.Request statusCode int } func (w *wrapper) WriteHeader(code int) { w.statusCode = code w.ResponseWriter.WriteHeader(code) return } func ClientIP(request *http.Request) string { ip := request.Header.Get("Cf-Connecting-IP") if ip != "" { return ip } ip = request.Header.Get("X-Real-IP") if ip == "" { ip = request.Header.Get("X-Forwarded-For") if ip == "" { ip = request.RemoteAddr } } if strings.Contains(ip, ",") { ips := strings.Split(ip, ",") ip = strings.TrimSpace(ips[0]) } if strings.Contains(ip, ":") { ips := strings.Split(ip, ":") ip = ips[0] } return ip } func Handler(next http.Handler) http.Handler { return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { wrappedWriter := &wrapper{ ResponseWriter: writer, request: request, statusCode: http.StatusOK, } next.ServeHTTP(wrappedWriter, request) log.Printf("%s %s %s %v", ClientIP(request), request.Method, request.RequestURI, wrappedWriter.statusCode) }) } type contextKey string const UserIDKey contextKey = "user_id" func CORS(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") w.Header().Set("Access-Control-Max-Age", "86400") if r.Method == http.MethodOptions { w.WriteHeader(http.StatusNoContent) return } next.ServeHTTP(w, r) }) } func Auth(j *jwt.JWT) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { authHeader := r.Header.Get("Authorization") if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") { http.Error(w, "unauthorized", http.StatusUnauthorized) return } tokenStr := strings.TrimPrefix(authHeader, "Bearer ") userID, err := j.ValidateAccessToken(tokenStr) if err != nil { http.Error(w, "unauthorized", http.StatusUnauthorized) return } ctx := context.WithValue(r.Context(), UserIDKey, userID) next.ServeHTTP(w, r.WithContext(ctx)) }) } }