Skip to content

Commit 860b90f

Browse files
committed
refac
1 parent 914ccf0 commit 860b90f

2 files changed

Lines changed: 58 additions & 43 deletions

File tree

backend/open_webui/retrieval/utils.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,44 @@ def get_reranking_function(reranking_engine, reranking_model, reranking_function
932932
)
933933

934934

935+
async def filter_accessible_collections(
936+
collection_names: set[str],
937+
user: UserModel,
938+
access_type: str = 'read',
939+
) -> set[str]:
940+
"""
941+
Return only the collection names the user is allowed to access.
942+
Admins bypass all checks. For non-admins:
943+
- file-* → validated via has_access_to_file
944+
- user-memory-* → must match user's own memory collection
945+
- knowledge-bases → always denied (meta-collection)
946+
- known KB ids → validated via Knowledges.check_access_by_user_id
947+
- everything else → allowed (ephemeral collections like web-search-*)
948+
"""
949+
if user.role == 'admin':
950+
return collection_names
951+
952+
validated = set()
953+
for name in collection_names:
954+
if name == 'knowledge-bases':
955+
continue
956+
elif name.startswith('file-'):
957+
file_id = name[len('file-'):]
958+
if await has_access_to_file(file_id=file_id, access_type=access_type, user=user):
959+
validated.add(name)
960+
elif name.startswith('user-memory-'):
961+
if name == f'user-memory-{user.id}':
962+
validated.add(name)
963+
else:
964+
# May be a knowledge-base ID or an ephemeral collection
965+
if await Knowledges.check_access_by_user_id(name, user.id, permission=access_type):
966+
validated.add(name)
967+
elif not await Knowledges.get_knowledge_by_id(name):
968+
# Not a KB at all — ephemeral collection (e.g. web-search-*), allow
969+
validated.add(name)
970+
return validated
971+
972+
935973
async def get_sources_from_items(
936974
request,
937975
items,
@@ -1147,6 +1185,13 @@ async def get_sources_from_items(
11471185
log.debug(f'skipping {item} as it has already been extracted')
11481186
continue
11491187

1188+
# Filter out collections the user cannot read
1189+
if user:
1190+
collection_names = await filter_accessible_collections(collection_names, user)
1191+
if not collection_names:
1192+
log.debug(f'access denied for all collections in item {item}')
1193+
continue
1194+
11501195
try:
11511196
if full_context:
11521197
# Sync helper makes blocking VECTOR_DB_CLIENT calls;

backend/open_webui/routers/retrieval.py

Lines changed: 13 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
from open_webui.retrieval.web.ydc import search_youcom
8383

8484
from open_webui.retrieval.utils import (
85+
filter_accessible_collections,
8586
get_content_from_url,
8687
get_embedding_function,
8788
get_reranking_function,
@@ -2350,50 +2351,19 @@ async def search_query_with_semaphore(query):
23502351

23512352
async def _validate_collection_access(collection_names: list[str], user, access_type: str = 'read') -> None:
23522353
"""
2353-
Prevent users from accessing collections they don't own.
2354-
Enforces ownership on user-memory-*, file-*, and knowledge-base collections.
2355-
Admins bypass this check.
2354+
Raise 403 if the user lacks access to any of the requested collections.
2355+
Delegates to the shared filter_accessible_collections utility so the
2356+
access rules stay in one place.
23562357
"""
2357-
if user.role == 'admin':
2358-
return
2359-
2360-
for name in collection_names:
2361-
# The 'knowledge-bases' meta-collection stores embedded metadata
2362-
# (names, descriptions, UUIDs) for every KB in the instance.
2363-
# Querying it would let any user enumerate all knowledge bases.
2364-
if name == 'knowledge-bases':
2365-
raise HTTPException(
2366-
status_code=status.HTTP_403_FORBIDDEN,
2367-
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
2368-
)
2369-
elif name.startswith('user-memory-') and name != f'user-memory-{user.id}':
2370-
raise HTTPException(
2371-
status_code=status.HTTP_403_FORBIDDEN,
2372-
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
2373-
)
2374-
elif name.startswith('file-'):
2375-
file_id = name[len('file-') :]
2376-
if not await has_access_to_file(
2377-
file_id=file_id,
2378-
access_type=access_type,
2379-
user=user,
2380-
):
2381-
raise HTTPException(
2382-
status_code=status.HTTP_403_FORBIDDEN,
2383-
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
2384-
)
2385-
else:
2386-
# Non-prefixed collection names may be knowledge base IDs.
2387-
# Verify the caller has the required permission on the knowledge base.
2388-
knowledge = await Knowledges.get_knowledge_by_id(name)
2389-
if knowledge is not None:
2390-
if not await Knowledges.check_access_by_user_id(
2391-
name, user.id, permission=access_type
2392-
):
2393-
raise HTTPException(
2394-
status_code=status.HTTP_403_FORBIDDEN,
2395-
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
2396-
)
2358+
requested = set(collection_names)
2359+
allowed = await filter_accessible_collections(requested, user, access_type=access_type)
2360+
denied = requested - allowed
2361+
if denied:
2362+
raise HTTPException(
2363+
status_code=status.HTTP_403_FORBIDDEN,
2364+
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
2365+
)
2366+
23972367

23982368

23992369
class QueryDocForm(BaseModel):

0 commit comments

Comments
 (0)