diff --git a/backend/controllers/get_logs.go b/backend/controllers/get_logs.go index 42a21886..e7a4c010 100644 --- a/backend/controllers/get_logs.go +++ b/backend/controllers/get_logs.go @@ -5,43 +5,69 @@ import ( "encoding/json" "net/http" "strconv" + + "github.com/gorilla/sessions" ) // SyncLogsHandler godoc // @Summary Get sync logs -// @Description Fetch the latest sync operation logs +// @Description Fetch the latest sync operation logs for the authenticated user // @Tags Logs // @Accept json // @Produce json -// @Param last query int false "Number of latest log entries to return (default: 100)" +// @Param last query int false "Number of latest log entries to return (default: 20, max: 20)" // @Success 200 {array} models.LogEntry "List of log entries" // @Failure 400 {string} string "Invalid last parameter" +// @Failure 401 {string} string "Authentication required" // @Router /sync/logs [get] -func SyncLogsHandler(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodGet { - http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) - return - } +func SyncLogsHandler(store *sessions.CookieStore) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } - // Get the 'last' query parameter, default to 100 - lastParam := r.URL.Query().Get("last") - last := 100 - if lastParam != "" { - parsedLast, err := strconv.Atoi(lastParam) - if err != nil || parsedLast < 0 { - http.Error(w, "Invalid 'last' parameter", http.StatusBadRequest) + // Validate session - user must be authenticated to view logs + session, err := store.Get(r, "session-name") + if err != nil { + http.Error(w, "Authentication required", http.StatusUnauthorized) return } - last = parsedLast - } - // Get the log store and retrieve logs - logStore := models.GetLogStore() - logs := logStore.GetLogs(last) + userInfo, ok := session.Values["user"].(map[string]interface{}) + if !ok || userInfo == nil { + http.Error(w, "Authentication required", http.StatusUnauthorized) + return + } + + // Get user's UUID to filter logs + userUUID, _ := userInfo["uuid"].(string) + + // Get the 'last' query parameter, default to 20, max 20 + const maxLogs = 20 + lastParam := r.URL.Query().Get("last") + last := maxLogs + if lastParam != "" { + parsedLast, err := strconv.Atoi(lastParam) + if err != nil || parsedLast < 0 { + http.Error(w, "Invalid 'last' parameter", http.StatusBadRequest) + return + } + last = parsedLast + } + // Enforce hard cap to prevent resource exhaustion + if last > maxLogs { + last = maxLogs + } - w.Header().Set("Content-Type", "application/json") - if err := json.NewEncoder(w).Encode(logs); err != nil { - http.Error(w, "Failed to encode logs", http.StatusInternalServerError) - return + // Get the log store and retrieve logs filtered by user UUID + logStore := models.GetLogStore() + logs := logStore.GetLogsByUser(last, userUUID) + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(logs); err != nil { + http.Error(w, "Failed to encode logs", http.StatusInternalServerError) + return + } } } diff --git a/backend/main.go b/backend/main.go index 00057bd1..99508fa4 100644 --- a/backend/main.go +++ b/backend/main.go @@ -109,7 +109,7 @@ func main() { mux.Handle("/modify-task", rateLimitedHandler(http.HandlerFunc(controllers.ModifyTaskHandler))) mux.Handle("/complete-task", rateLimitedHandler(http.HandlerFunc(controllers.CompleteTaskHandler))) mux.Handle("/delete-task", rateLimitedHandler(http.HandlerFunc(controllers.DeleteTaskHandler))) - mux.Handle("/sync/logs", rateLimitedHandler(http.HandlerFunc(controllers.SyncLogsHandler))) + mux.Handle("/sync/logs", rateLimitedHandler(controllers.SyncLogsHandler(store))) mux.Handle("/complete-tasks", rateLimitedHandler(http.HandlerFunc(controllers.BulkCompleteTaskHandler))) mux.Handle("/delete-tasks", rateLimitedHandler(http.HandlerFunc(controllers.BulkDeleteTaskHandler))) diff --git a/backend/models/logs.go b/backend/models/logs.go index 4fb5f73a..8977b88b 100644 --- a/backend/models/logs.go +++ b/backend/models/logs.go @@ -95,3 +95,30 @@ func (ls *LogStore) GetLogs(last int) []LogEntry { } return result } + +// GetLogsByUser returns the last N log entries for a specific user (filtered by SyncID/UUID) +func (ls *LogStore) GetLogsByUser(last int, userUUID string) []LogEntry { + ls.mu.RLock() + defer ls.mu.RUnlock() + + // Filter entries by user UUID + var userEntries []LogEntry + for _, entry := range ls.entries { + if entry.SyncID == userUUID { + userEntries = append(userEntries, entry) + } + } + + // Determine how many to return + count := last + if count <= 0 || count > len(userEntries) { + count = len(userEntries) + } + + // Return last N entries in reverse order (newest first) + result := make([]LogEntry, count) + for i := 0; i < count; i++ { + result[i] = userEntries[len(userEntries)-1-i] + } + return result +}