Restrict status endpoints to user's characters
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled

Filter live status responses so callers only see automations, workflows, and pipelines associated with the current user's characters. Backend: use get_user_character_names in automations.get_all_statuses, workflows.get_all_workflow_statuses, and pipelines.get_all_pipeline_statuses (pipeline filtering checks character_states). Frontend: clear React Query cache when a token is set or removed (import useQueryClient and add it to callback deps) so cached data is refreshed after auth changes.
This commit is contained in:
Paweł Orzech 2026-03-01 23:07:38 +01:00
parent 59938451c1
commit 4d8974bc66
No known key found for this signature in database
4 changed files with 19 additions and 8 deletions

View file

@ -208,9 +208,10 @@ async def resume_automation(config_id: int, request: Request) -> None:
@router.get("/status/all", response_model=list[AutomationStatusResponse])
async def get_all_statuses(request: Request) -> list[AutomationStatusResponse]:
"""Get live status for all active automations."""
"""Get live status for active automations belonging to the current user."""
manager = _get_manager(request)
return manager.get_all_statuses()
user_chars = set(await get_user_character_names(request))
return [s for s in manager.get_all_statuses() if s.character_name in user_chars]
@router.get("/{config_id}/status", response_model=AutomationStatusResponse)

View file

@ -91,9 +91,13 @@ async def create_pipeline(
@router.get("/status/all", response_model=list[PipelineStatusResponse])
async def get_all_pipeline_statuses(request: Request) -> list[PipelineStatusResponse]:
"""Get live status for all active pipelines."""
"""Get live status for active pipelines belonging to the current user."""
manager = _get_manager(request)
return manager.get_all_pipeline_statuses()
user_chars = set(await get_user_character_names(request))
return [
s for s in manager.get_all_pipeline_statuses()
if any(cs.character_name in user_chars for cs in s.character_states)
]
@router.get("/{pipeline_id}", response_model=PipelineConfigDetailResponse)

View file

@ -83,9 +83,10 @@ async def create_workflow(
@router.get("/status/all", response_model=list[WorkflowStatusResponse])
async def get_all_workflow_statuses(request: Request) -> list[WorkflowStatusResponse]:
"""Get live status for all active workflows."""
"""Get live status for active workflows belonging to the current user."""
manager = _get_manager(request)
return manager.get_all_workflow_statuses()
user_chars = set(await get_user_character_names(request))
return [s for s in manager.get_all_workflow_statuses() if s.character_name in user_chars]
@router.get("/{workflow_id}", response_model=WorkflowConfigDetailResponse)

View file

@ -7,6 +7,7 @@ import {
useEffect,
useCallback,
} from "react";
import { useQueryClient } from "@tanstack/react-query";
import {
setAuthToken,
type AuthStatus,
@ -33,6 +34,7 @@ export function useAuth() {
}
export function AuthProvider({ children }: { children: React.ReactNode }) {
const queryClient = useQueryClient();
const [status, setStatus] = useState<AuthStatus | null>(null);
const [loading, setLoading] = useState(true);
@ -54,6 +56,8 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const result = await setAuthToken(token);
if (result.success) {
localStorage.setItem(STORAGE_KEY, token);
// Clear all cached data so the new user gets fresh data
queryClient.clear();
setStatus({ has_token: true, source: "user" });
return { success: true };
}
@ -65,13 +69,14 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
};
}
},
[]
[queryClient]
);
const handleRemoveToken = useCallback(async () => {
localStorage.removeItem(STORAGE_KEY);
queryClient.clear();
setStatus({ has_token: false, source: "none" });
}, []);
}, [queryClient]);
return (
<AuthContext.Provider