diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 4eca154fa1..9573d1df91 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -1487,7 +1487,9 @@ async def chat_completion( asyncio.create_task(run_initial_title_generation()) else: # Existing chat — verify ownership - if not await Chats.is_chat_owner(chat_id, user.id) and user.role != 'admin': + if not await Chats.is_chat_owner(chat_id, user.id) and not ( + user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS + ): raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.DEFAULT(), @@ -2075,7 +2077,7 @@ async def verify_chat_ownership(chat_id: str | None, user) -> None: detail='Channel chats are not supported on this endpoint', ) - if user.role != 'admin' and not await Chats.is_chat_owner(chat_id, user.id): + if not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS) and not await Chats.is_chat_owner(chat_id, user.id): raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.DEFAULT(), @@ -2139,11 +2141,11 @@ async def list_tasks_by_chat_id_endpoint(request: Request, chat_id: str, user=De socket_id = get_temporary_chat_session_id(chat_id) if socket_id: owner_id = get_user_id_from_session_pool(socket_id) - if owner_id != user.id and user.role != 'admin': + if owner_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS): return {'task_ids': []} else: chat = await Chats.get_chat_by_id(chat_id) - if chat is None or (chat.user_id != user.id and user.role != 'admin'): + if chat is None or (chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS)): return {'task_ids': []} task_ids = await list_task_ids_by_item_id(request.app.state.redis, chat_id) @@ -2158,11 +2160,11 @@ async def stop_tasks_by_chat_id_endpoint(request: Request, chat_id: str, user=De chat = None if socket_id: owner_id = get_user_id_from_session_pool(socket_id) - if owner_id != user.id and user.role != 'admin': + if owner_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS): raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND) else: chat = await Chats.get_chat_by_id(chat_id) - if chat is None or (chat.user_id != user.id and user.role != 'admin'): + if chat is None or (chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS)): raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND) result = await stop_item_tasks(request.app.state.redis, chat_id) diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index b1597aa2db..58a4da1f1b 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -30,6 +30,7 @@ from open_webui.env import ( AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT, BYPASS_RETRIEVAL_ACCESS_CONTROL, + ENABLE_ADMIN_CHAT_ACCESS, ENABLE_FORWARD_USER_INFO_HEADERS, ENABLE_RETRIEVAL_UNSCOPED_COLLECTIONS, MPS_INFERENCE_LOCK, @@ -1462,7 +1463,9 @@ async def get_sources_from_items( elif item.get('type') == 'chat': # Chat Attached chat = await Chats.get_chat_by_id(item.get('id')) - has_read_access = bool(chat and (user.role == 'admin' or chat.user_id == user.id)) + has_read_access = bool( + chat and ((user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS) or chat.user_id == user.id) + ) if chat and not has_read_access: has_read_access = await AccessGrants.has_access( diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index e46fed259c..e6194d0f64 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -680,7 +680,7 @@ async def export_single_chat_stats( ) # Verify the chat belongs to the user (unless admin) - if chat.user_id != user.id and user.role != 'admin': + if chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -1428,7 +1428,7 @@ async def update_chat_message_by_id( detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - if chat.user_id != user.id and user.role != 'admin': + if chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -1489,7 +1489,7 @@ async def delete_chat_message_by_id( detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - if chat.user_id != user.id and user.role != 'admin': + if chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -1537,7 +1537,7 @@ async def send_chat_message_event_by_id( detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - if chat.user_id != user.id and user.role != 'admin': + if chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -1584,6 +1584,8 @@ async def delete_chat_by_id( # not be reachable for a chat the caller may not delete. if user.role == 'admin': chat = await Chats.get_chat_by_id(id, db=db) + if chat and chat.user_id != user.id and not ENABLE_ADMIN_CHAT_ACCESS: + chat = None else: if not await has_permission(user.id, 'chat.delete', await Config.get('user.permissions')): raise HTTPException( @@ -1850,7 +1852,7 @@ async def clone_shared_chat_by_id( # Enforce access grants (owner and admins bypass) shared = await SharedChats.get_by_id(id, db=db) - if shared and user.role != 'admin' and shared.user_id != user.id: + if shared and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS) and shared.user_id != user.id: has_grant = await is_open_shared_chat(shared, db=db) or await AccessGrants.has_access( user_id=user.id, resource_type='shared_chat', @@ -2042,7 +2044,7 @@ async def update_shared_chat_access_by_id( user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session), ): - if user.role == 'admin': + if user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS: chat = await Chats.get_chat_by_id(id, db=db) else: chat = await Chats.get_chat_by_id_and_user_id(id, user.id, db=db) @@ -2078,7 +2080,7 @@ async def get_shared_chat_access_by_id( user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session), ): - if user.role == 'admin': + if user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS: chat = await Chats.get_chat_by_id(id, db=db) else: chat = await Chats.get_chat_by_id_and_user_id(id, user.id, db=db) diff --git a/backend/open_webui/utils/tool_approval.py b/backend/open_webui/utils/tool_approval.py index c59b2d6316..e2c33e9a74 100644 --- a/backend/open_webui/utils/tool_approval.py +++ b/backend/open_webui/utils/tool_approval.py @@ -5,6 +5,7 @@ from pydantic import BaseModel from sqlalchemy.ext.asyncio import AsyncSession from open_webui.constants import ERROR_MESSAGES +from open_webui.env import ENABLE_ADMIN_CHAT_ACCESS from open_webui.models.chats import Chats from open_webui.socket.main import get_event_emitter from open_webui.utils.json_codec import JSONCodec @@ -25,7 +26,7 @@ async def resolve_tool_call_output( db: AsyncSession | None = None, ) -> dict: chat = await Chats.get_chat_by_id(chat_id, db=db) - if not chat or (chat.user_id != user.id and user.role != 'admin'): + if not chat or (chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS)): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED,