refac
This commit is contained in:
@@ -932,6 +932,44 @@ def get_reranking_function(reranking_engine, reranking_model, reranking_function
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def filter_accessible_collections(
|
||||||
|
collection_names: set[str],
|
||||||
|
user: UserModel,
|
||||||
|
access_type: str = 'read',
|
||||||
|
) -> set[str]:
|
||||||
|
"""
|
||||||
|
Return only the collection names the user is allowed to access.
|
||||||
|
Admins bypass all checks. For non-admins:
|
||||||
|
- file-* → validated via has_access_to_file
|
||||||
|
- user-memory-* → must match user's own memory collection
|
||||||
|
- knowledge-bases → always denied (meta-collection)
|
||||||
|
- known KB ids → validated via Knowledges.check_access_by_user_id
|
||||||
|
- everything else → allowed (ephemeral collections like web-search-*)
|
||||||
|
"""
|
||||||
|
if user.role == 'admin':
|
||||||
|
return collection_names
|
||||||
|
|
||||||
|
validated = set()
|
||||||
|
for name in collection_names:
|
||||||
|
if name == 'knowledge-bases':
|
||||||
|
continue
|
||||||
|
elif name.startswith('file-'):
|
||||||
|
file_id = name[len('file-'):]
|
||||||
|
if await has_access_to_file(file_id=file_id, access_type=access_type, user=user):
|
||||||
|
validated.add(name)
|
||||||
|
elif name.startswith('user-memory-'):
|
||||||
|
if name == f'user-memory-{user.id}':
|
||||||
|
validated.add(name)
|
||||||
|
else:
|
||||||
|
# May be a knowledge-base ID or an ephemeral collection
|
||||||
|
if await Knowledges.check_access_by_user_id(name, user.id, permission=access_type):
|
||||||
|
validated.add(name)
|
||||||
|
elif not await Knowledges.get_knowledge_by_id(name):
|
||||||
|
# Not a KB at all — ephemeral collection (e.g. web-search-*), allow
|
||||||
|
validated.add(name)
|
||||||
|
return validated
|
||||||
|
|
||||||
|
|
||||||
async def get_sources_from_items(
|
async def get_sources_from_items(
|
||||||
request,
|
request,
|
||||||
items,
|
items,
|
||||||
@@ -1147,6 +1185,13 @@ async def get_sources_from_items(
|
|||||||
log.debug(f'skipping {item} as it has already been extracted')
|
log.debug(f'skipping {item} as it has already been extracted')
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Filter out collections the user cannot read
|
||||||
|
if user:
|
||||||
|
collection_names = await filter_accessible_collections(collection_names, user)
|
||||||
|
if not collection_names:
|
||||||
|
log.debug(f'access denied for all collections in item {item}')
|
||||||
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if full_context:
|
if full_context:
|
||||||
# Sync helper makes blocking VECTOR_DB_CLIENT calls;
|
# Sync helper makes blocking VECTOR_DB_CLIENT calls;
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ from open_webui.retrieval.web.yandex import search_yandex
|
|||||||
from open_webui.retrieval.web.ydc import search_youcom
|
from open_webui.retrieval.web.ydc import search_youcom
|
||||||
|
|
||||||
from open_webui.retrieval.utils import (
|
from open_webui.retrieval.utils import (
|
||||||
|
filter_accessible_collections,
|
||||||
get_content_from_url,
|
get_content_from_url,
|
||||||
get_embedding_function,
|
get_embedding_function,
|
||||||
get_reranking_function,
|
get_reranking_function,
|
||||||
@@ -2350,50 +2351,19 @@ async def process_web_search(request: Request, form_data: SearchForm, user=Depen
|
|||||||
|
|
||||||
async def _validate_collection_access(collection_names: list[str], user, access_type: str = 'read') -> None:
|
async def _validate_collection_access(collection_names: list[str], user, access_type: str = 'read') -> None:
|
||||||
"""
|
"""
|
||||||
Prevent users from accessing collections they don't own.
|
Raise 403 if the user lacks access to any of the requested collections.
|
||||||
Enforces ownership on user-memory-*, file-*, and knowledge-base collections.
|
Delegates to the shared filter_accessible_collections utility so the
|
||||||
Admins bypass this check.
|
access rules stay in one place.
|
||||||
"""
|
"""
|
||||||
if user.role == 'admin':
|
requested = set(collection_names)
|
||||||
return
|
allowed = await filter_accessible_collections(requested, user, access_type=access_type)
|
||||||
|
denied = requested - allowed
|
||||||
|
if denied:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
||||||
|
)
|
||||||
|
|
||||||
for name in collection_names:
|
|
||||||
# The 'knowledge-bases' meta-collection stores embedded metadata
|
|
||||||
# (names, descriptions, UUIDs) for every KB in the instance.
|
|
||||||
# Querying it would let any user enumerate all knowledge bases.
|
|
||||||
if name == 'knowledge-bases':
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
|
||||||
)
|
|
||||||
elif name.startswith('user-memory-') and name != f'user-memory-{user.id}':
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
|
||||||
)
|
|
||||||
elif name.startswith('file-'):
|
|
||||||
file_id = name[len('file-') :]
|
|
||||||
if not await has_access_to_file(
|
|
||||||
file_id=file_id,
|
|
||||||
access_type=access_type,
|
|
||||||
user=user,
|
|
||||||
):
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# Non-prefixed collection names may be knowledge base IDs.
|
|
||||||
# Verify the caller has the required permission on the knowledge base.
|
|
||||||
knowledge = await Knowledges.get_knowledge_by_id(name)
|
|
||||||
if knowledge is not None:
|
|
||||||
if not await Knowledges.check_access_by_user_id(
|
|
||||||
name, user.id, permission=access_type
|
|
||||||
):
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class QueryDocForm(BaseModel):
|
class QueryDocForm(BaseModel):
|
||||||
|
|||||||
Reference in New Issue
Block a user