mirror of
https://github.com/open-webui/open-webui.git
synced 2026-08-12 16:52:25 -06:00
refac
This commit is contained in:
@@ -48,7 +48,7 @@ from open_webui.retrieval.external import retrieve_external_knowledge
|
||||
from open_webui.retrieval.vector.factory import VECTOR_DB_CLIENT
|
||||
from open_webui.retrieval.vector.main import GetResult, SearchResult
|
||||
from open_webui.retrieval.web.utils import get_web_loader
|
||||
from open_webui.utils.access_control.files import has_access_to_file
|
||||
from open_webui.utils.access_control.files import get_owner_accessible_folder_files, has_access_to_file
|
||||
from open_webui.utils.access_control.folders import has_folder_access
|
||||
from open_webui.utils.headers import include_user_info_headers
|
||||
from open_webui.utils.misc import get_content_from_message, get_message_list
|
||||
@@ -1354,7 +1354,7 @@ async def get_sources_from_items(
|
||||
|
||||
folder = await Folders.get_folder_by_id(folder_id)
|
||||
if folder and (user.role == 'admin' or await has_folder_access(user.id, folder, 'read', db=None)):
|
||||
files = (folder.data or {}).get('files', [])
|
||||
files = await get_owner_accessible_folder_files(folder)
|
||||
folder_items.update((entry.get('type'), entry.get('id')) for entry in files if isinstance(entry, dict))
|
||||
items.extend(files)
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ from open_webui.utils.access_control import has_permission
|
||||
from open_webui.utils.access_control import (
|
||||
filter_allowed_access_grants,
|
||||
)
|
||||
from open_webui.utils.access_control.files import get_accessible_folder_files
|
||||
from open_webui.utils.access_control.files import can_read_all_folder_files, get_accessible_folder_files
|
||||
from open_webui.utils.auth import get_admin_user, get_verified_user
|
||||
from open_webui.tasks import has_active_tasks
|
||||
from pydantic import BaseModel
|
||||
@@ -156,6 +156,18 @@ async def create_folder(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
||||
)
|
||||
if form_data.data and 'files' in form_data.data:
|
||||
owner = await Users.get_user_by_id(parent.user_id, db=db)
|
||||
if not owner:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=ERROR_MESSAGES.NOT_FOUND,
|
||||
)
|
||||
if not await can_read_all_folder_files(form_data.data['files'], owner, db=db):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
||||
)
|
||||
# Create as the folder owner's subfolder (keep tree consistent)
|
||||
try:
|
||||
folder = await Folders.insert_new_folder(parent.user_id, form_data, form_data.parent_id, db=db)
|
||||
@@ -174,6 +186,14 @@ async def create_folder(
|
||||
detail=ERROR_MESSAGES.DEFAULT('Error creating folder'),
|
||||
)
|
||||
|
||||
if form_data.data and 'files' in form_data.data and not await can_read_all_folder_files(
|
||||
form_data.data['files'], user, db=db
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
||||
)
|
||||
|
||||
try:
|
||||
folder = await Folders.insert_new_folder(user.id, form_data, form_data.parent_id, db=db)
|
||||
await publish_event(
|
||||
@@ -315,11 +335,14 @@ async def update_folder_name_by_id(
|
||||
detail=ERROR_MESSAGES.DEFAULT('Folder already exists'),
|
||||
)
|
||||
|
||||
# Validate read access to every file/collection being attached.
|
||||
# Folder files are consumed by chat middleware as RAG context.
|
||||
if form_data.data and isinstance(form_data.data.get('files'), list):
|
||||
accessible_files = await get_accessible_folder_files(form_data.data['files'], user, db=db)
|
||||
if len(accessible_files) != len(form_data.data['files']):
|
||||
if form_data.data and 'files' in form_data.data:
|
||||
owner = user if folder.user_id == user.id else await Users.get_user_by_id(folder.user_id, db=db)
|
||||
if not owner:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=ERROR_MESSAGES.NOT_FOUND,
|
||||
)
|
||||
if not await can_read_all_folder_files(form_data.data['files'], owner, db=db):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
||||
|
||||
@@ -4,14 +4,17 @@ from open_webui.models.access_grants import AccessGrants
|
||||
from open_webui.models.channels import Channels
|
||||
from open_webui.models.chats import Chats
|
||||
from open_webui.models.files import Files
|
||||
from open_webui.models.folders import FolderModel
|
||||
from open_webui.models.groups import Groups
|
||||
from open_webui.models.knowledge import Knowledges
|
||||
from open_webui.models.models import Models
|
||||
from open_webui.models.users import UserModel
|
||||
from open_webui.models.users import UserModel, Users
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
FOLDER_FILE_TYPES = {'file', 'collection', 'note'}
|
||||
|
||||
|
||||
async def has_access_to_file(
|
||||
file_id: str | None,
|
||||
@@ -122,27 +125,26 @@ async def get_accessible_folder_files(
|
||||
) -> list[dict]:
|
||||
"""Filter folder.data['files'] entries to those the caller can read.
|
||||
|
||||
Entries carry a 'type' ('file', 'collection' or 'note') and 'id'. File, collection and
|
||||
note ids are each access-checked against the caller; admins bypass all checks and
|
||||
genuinely unknown types are kept as-is.
|
||||
Entries carry a 'type' ('file', 'collection' or 'note') and 'id'. Entries of any other
|
||||
shape are dropped because they cannot be access-checked.
|
||||
"""
|
||||
if not entries:
|
||||
if not isinstance(entries, list):
|
||||
return []
|
||||
entries = [
|
||||
entry
|
||||
for entry in entries
|
||||
if isinstance(entry, dict) and entry.get('type') in FOLDER_FILE_TYPES and entry.get('id')
|
||||
]
|
||||
if user.role == 'admin':
|
||||
return list(entries)
|
||||
return entries
|
||||
|
||||
# One group-membership fetch for the whole folder listing
|
||||
user_group_ids = {group.id for group in await Groups.get_groups_by_member_id(user.id, db=db)}
|
||||
|
||||
accessible: list[dict] = []
|
||||
for entry in entries:
|
||||
if not isinstance(entry, dict):
|
||||
continue
|
||||
entry_type = entry.get('type')
|
||||
entry_id = entry.get('id')
|
||||
if not entry_id:
|
||||
accessible.append(entry)
|
||||
continue
|
||||
if entry_type == 'file':
|
||||
if await has_access_to_file(entry_id, 'read', user, db=db, user_group_ids=user_group_ids):
|
||||
accessible.append(entry)
|
||||
@@ -165,6 +167,32 @@ async def get_accessible_folder_files(
|
||||
)
|
||||
):
|
||||
accessible.append(entry)
|
||||
else:
|
||||
accessible.append(entry)
|
||||
return accessible
|
||||
|
||||
|
||||
async def can_read_all_folder_files(
|
||||
entries: list[dict] | None,
|
||||
user: UserModel,
|
||||
db: AsyncSession | None = None,
|
||||
) -> bool:
|
||||
if entries is None:
|
||||
return True
|
||||
if not isinstance(entries, list):
|
||||
return False
|
||||
if not entries:
|
||||
return True
|
||||
|
||||
return len(await get_accessible_folder_files(entries, user, db=db)) == len(entries)
|
||||
|
||||
|
||||
async def get_owner_accessible_folder_files(folder: FolderModel, db: AsyncSession | None = None) -> list[dict]:
|
||||
"""Return the folder entries its owner can still delegate."""
|
||||
files = (folder.data or {}).get('files') or []
|
||||
if not files:
|
||||
return []
|
||||
|
||||
owner = await Users.get_user_by_id(folder.user_id, db=db)
|
||||
if not owner:
|
||||
return []
|
||||
|
||||
return await get_accessible_folder_files(files, owner, db=db)
|
||||
|
||||
@@ -77,6 +77,7 @@ from open_webui.socket.main import (
|
||||
)
|
||||
from open_webui.utils.access_control import has_connection_access, has_permission
|
||||
from open_webui.models.access_grants import AccessGrants
|
||||
from open_webui.utils.access_control.files import get_owner_accessible_folder_files
|
||||
from open_webui.utils.access_control.folders import has_folder_access
|
||||
from open_webui.utils.chat import generate_chat_completion
|
||||
from open_webui.utils.chat_id import is_saved_chat_id
|
||||
@@ -2456,7 +2457,7 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
||||
else:
|
||||
# Native FC: skip RAG injection, builtin tools
|
||||
# will read folder knowledge from metadata.
|
||||
metadata['folder_knowledge'] = folder.data['files']
|
||||
metadata['folder_knowledge'] = await get_owner_accessible_folder_files(folder)
|
||||
|
||||
# Model "Knowledge" handling
|
||||
user_message = get_last_user_message(form_data['messages'])
|
||||
|
||||
Reference in New Issue
Block a user