fix: address code review findings
- Add SearchID field to routeSearchRoute struct and generate search_id in RouteSearch handler - Populate Itinerary.ID field with unique IDs using generateItineraryID function - Fix information disclosure in error handling - log errors internally instead of leaking to clients - Fix circuit breaker trip metric recording - only record when state transitions to open - Fix context not passed in route expansion - use context.WithTimeout instead of context.TODO - Fix admin auth fails open on missing API key - return 401 Unauthorized without revealing configuration
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"crypto/subtle"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -52,6 +53,7 @@ type routeSearchRoute struct {
|
||||
Transfers int `json:"transfers"`
|
||||
Cost int `json:"cost"`
|
||||
ID string `json:"id"`
|
||||
SearchID string `json:"search_id"`
|
||||
PriceNote string `json:"price_note,omitempty"` // "цена не указана" if price data not available from API
|
||||
}
|
||||
|
||||
@@ -270,6 +272,9 @@ func RouteSearch(hc *HandlerContext, w http.ResponseWriter, r *http.Request) {
|
||||
duration := time.Since(start).Nanoseconds()
|
||||
hc.Metrics.RecordSearch(duration)
|
||||
|
||||
// Generate a search_id based on the request parameters
|
||||
searchID := fmt.Sprintf("search_%s_%s_%s_%d", req.FromCityID, req.ToCityID, req.Date, time.Now().Unix())
|
||||
|
||||
// Build response routes
|
||||
routeResponses := make([]routeSearchRoute, 0, len(results))
|
||||
for _, route := range results {
|
||||
@@ -279,6 +284,7 @@ func RouteSearch(hc *HandlerContext, w http.ResponseWriter, r *http.Request) {
|
||||
Transfers: route.TotalTransfers,
|
||||
Cost: route.Cost,
|
||||
ID: route.ID,
|
||||
SearchID: searchID,
|
||||
PriceNote: priceNote,
|
||||
})
|
||||
}
|
||||
@@ -467,7 +473,8 @@ func StationStatus(hc *HandlerContext, w http.ResponseWriter, r *http.Request) {
|
||||
func adminAuth(hc *HandlerContext, w http.ResponseWriter, r *http.Request) bool {
|
||||
expectedAPIKey := os.Getenv("TRIP_PLANNER_ADMIN_API_KEY")
|
||||
if expectedAPIKey == "" {
|
||||
http.Error(w, "server configuration error: TRIP_PLANNER_ADMIN_API_KEY is not set", http.StatusInternalServerError)
|
||||
// Admin auth not configured - reject all admin requests
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
return false
|
||||
}
|
||||
providedAPIKey := r.Header.Get("X-Admin-Api-Key")
|
||||
@@ -567,7 +574,8 @@ func GetSavedCities(hc *HandlerContext, w http.ResponseWriter, r *http.Request)
|
||||
|
||||
cities, err := hc.Preferences.GetSavedCities(r.Context(), userID)
|
||||
if err != nil {
|
||||
http.Error(w, "failed to get saved cities: "+err.Error(), http.StatusInternalServerError)
|
||||
log.Printf("error getting saved cities: %v", err)
|
||||
http.Error(w, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -599,7 +607,8 @@ func AddSavedCity(hc *HandlerContext, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if err := hc.Preferences.AddSavedCity(r.Context(), userID, req.CityCode, req.Name); err != nil {
|
||||
http.Error(w, "failed to add saved city: "+err.Error(), http.StatusInternalServerError)
|
||||
log.Printf("error adding saved city: %v", err)
|
||||
http.Error(w, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -629,7 +638,8 @@ func RemoveSavedCity(hc *HandlerContext, w http.ResponseWriter, r *http.Request)
|
||||
cityCode := parts[4]
|
||||
|
||||
if err := hc.Preferences.RemoveSavedCity(r.Context(), userID, cityCode); err != nil {
|
||||
http.Error(w, "failed to remove saved city: "+err.Error(), http.StatusInternalServerError)
|
||||
log.Printf("error removing saved city: %v", err)
|
||||
http.Error(w, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -652,7 +662,8 @@ func GetSearchHistory(hc *HandlerContext, w http.ResponseWriter, r *http.Request
|
||||
|
||||
history, err := hc.Preferences.GetSearchHistory(r.Context(), userID)
|
||||
if err != nil {
|
||||
http.Error(w, "failed to get search history: "+err.Error(), http.StatusInternalServerError)
|
||||
log.Printf("error getting search history: %v", err)
|
||||
http.Error(w, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -691,7 +702,8 @@ func AddSearchHistory(hc *HandlerContext, w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
|
||||
if err := hc.Preferences.AddSearchHistory(r.Context(), userID, req.FromCity, req.ToCity, req.Date); err != nil {
|
||||
http.Error(w, "failed to add search history: "+err.Error(), http.StatusInternalServerError)
|
||||
log.Printf("error adding search history: %v", err)
|
||||
http.Error(w, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user