|
| 1 | +import logging |
| 2 | +from typing import Optional, Any |
| 3 | + |
| 4 | +from open_webui.models.users import UserModel |
| 5 | +from open_webui.models.files import Files |
| 6 | +from open_webui.models.knowledge import Knowledges |
| 7 | +from open_webui.models.channels import Channels |
| 8 | +from open_webui.models.chats import Chats |
| 9 | +from open_webui.models.groups import Groups |
| 10 | +from open_webui.models.access_grants import AccessGrants |
| 11 | + |
| 12 | +log = logging.getLogger(__name__) |
| 13 | + |
| 14 | + |
| 15 | +def has_access_to_file( |
| 16 | + file_id: Optional[str], |
| 17 | + access_type: str, |
| 18 | + user: UserModel, |
| 19 | + db: Optional[Any] = None, |
| 20 | +) -> bool: |
| 21 | + """ |
| 22 | + Check if a user has the specified access to a file through any of: |
| 23 | + - Knowledge bases (ownership or access grants) |
| 24 | + - Channels the user is a member of |
| 25 | + - Shared chats |
| 26 | +
|
| 27 | + NOTE: This does NOT check direct file ownership — callers should check |
| 28 | + file.user_id == user.id separately before calling this. |
| 29 | + """ |
| 30 | + file = Files.get_file_by_id(file_id, db=db) |
| 31 | + log.debug(f"Checking if user has {access_type} access to file") |
| 32 | + if not file: |
| 33 | + return False |
| 34 | + |
| 35 | + # Check if the file is associated with any knowledge bases the user has access to |
| 36 | + knowledge_bases = Knowledges.get_knowledges_by_file_id(file_id, db=db) |
| 37 | + user_group_ids = { |
| 38 | + group.id for group in Groups.get_groups_by_member_id(user.id, db=db) |
| 39 | + } |
| 40 | + for knowledge_base in knowledge_bases: |
| 41 | + if knowledge_base.user_id == user.id or AccessGrants.has_access( |
| 42 | + user_id=user.id, |
| 43 | + resource_type="knowledge", |
| 44 | + resource_id=knowledge_base.id, |
| 45 | + permission=access_type, |
| 46 | + user_group_ids=user_group_ids, |
| 47 | + db=db, |
| 48 | + ): |
| 49 | + return True |
| 50 | + |
| 51 | + knowledge_base_id = file.meta.get("collection_name") if file.meta else None |
| 52 | + if knowledge_base_id: |
| 53 | + knowledge_bases = Knowledges.get_knowledge_bases_by_user_id( |
| 54 | + user.id, access_type, db=db |
| 55 | + ) |
| 56 | + for knowledge_base in knowledge_bases: |
| 57 | + if knowledge_base.id == knowledge_base_id: |
| 58 | + return True |
| 59 | + |
| 60 | + # Check if the file is associated with any channels the user has access to |
| 61 | + channels = Channels.get_channels_by_file_id_and_user_id(file_id, user.id, db=db) |
| 62 | + if access_type == "read" and channels: |
| 63 | + return True |
| 64 | + |
| 65 | + # Check if the file is associated with any chats the user has access to |
| 66 | + # TODO: Granular access control for chats |
| 67 | + chats = Chats.get_shared_chats_by_file_id(file_id, db=db) |
| 68 | + if chats: |
| 69 | + return True |
| 70 | + |
| 71 | + return False |
0 commit comments