From 945275faaedaf450f0d1edba430d2f0cea550a0b Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 22 Mar 2026 06:58:58 -0500 Subject: [PATCH] refac --- backend/open_webui/models/access_grants.py | 10 +++++ backend/open_webui/routers/channels.py | 4 +- backend/open_webui/routers/notes.py | 3 +- .../utils/access_control/__init__.py | 3 +- .../workspace/common/AccessControl.svelte | 42 ++++++++++++++++++- 5 files changed, 56 insertions(+), 6 deletions(-) diff --git a/backend/open_webui/models/access_grants.py b/backend/open_webui/models/access_grants.py index ee7f950ff..20601fd30 100644 --- a/backend/open_webui/models/access_grants.py +++ b/backend/open_webui/models/access_grants.py @@ -192,6 +192,16 @@ def has_public_read_access_grant(access_grants: Optional[list]) -> bool: return False +def has_public_write_access_grant(access_grants: Optional[list]) -> bool: + """ + Returns True when a direct grant list includes wildcard public-write. + """ + for grant in normalize_access_grants(access_grants): + if grant['principal_type'] == 'user' and grant['principal_id'] == '*' and grant['permission'] == 'write': + return True + return False + + def has_user_access_grant(access_grants: Optional[list]) -> bool: """ Returns True when a direct grant list includes any non-wildcard user grant. diff --git a/backend/open_webui/routers/channels.py b/backend/open_webui/routers/channels.py index 06d2d2a6b..c2e97202a 100644 --- a/backend/open_webui/routers/channels.py +++ b/backend/open_webui/routers/channels.py @@ -36,7 +36,7 @@ from open_webui.models.channels import ( ChannelWebhookModel, ChannelWebhookForm, ) -from open_webui.models.access_grants import AccessGrants, has_public_read_access_grant +from open_webui.models.access_grants import AccessGrants, has_public_read_access_grant, has_public_write_access_grant from open_webui.models.messages import ( Messages, MessageModel, @@ -88,7 +88,7 @@ def channel_has_access( ): return True - if not strict and permission == 'write' and has_public_read_access_grant(channel.access_grants): + if not strict and permission == 'write' and has_public_write_access_grant(channel.access_grants): return True return False diff --git a/backend/open_webui/routers/notes.py b/backend/open_webui/routers/notes.py index dd826053c..705d86e1c 100644 --- a/backend/open_webui/routers/notes.py +++ b/backend/open_webui/routers/notes.py @@ -30,6 +30,7 @@ from open_webui.utils.auth import get_admin_user, get_verified_user from open_webui.utils.access_control import ( has_permission, has_public_read_access_grant, + has_public_write_access_grant, filter_allowed_access_grants, ) from open_webui.models.access_grants import AccessGrants @@ -234,7 +235,7 @@ async def get_note_by_id( permission='write', db=db, ) - or has_public_read_access_grant(note.access_grants) + or has_public_write_access_grant(note.access_grants) ) return NoteResponse(**note.model_dump(), write_access=write_access) diff --git a/backend/open_webui/utils/access_control/__init__.py b/backend/open_webui/utils/access_control/__init__.py index 3ee394acc..5d357bcb2 100644 --- a/backend/open_webui/utils/access_control/__init__.py +++ b/backend/open_webui/utils/access_control/__init__.py @@ -5,6 +5,7 @@ from open_webui.models.users import UserModel from open_webui.models.groups import Groups from open_webui.models.access_grants import ( has_public_read_access_grant, + has_public_write_access_grant, has_user_access_grant, strip_user_access_grants, ) @@ -225,7 +226,7 @@ def filter_allowed_access_grants( return access_grants # Check if user can share publicly - if has_public_read_access_grant(access_grants) and not has_permission( + if (has_public_read_access_grant(access_grants) or has_public_write_access_grant(access_grants)) and not has_permission( user_id, public_permission_key, default_permissions, diff --git a/src/lib/components/workspace/common/AccessControl.svelte b/src/lib/components/workspace/common/AccessControl.svelte index 5c031a0ed..bd8c5dca5 100644 --- a/src/lib/components/workspace/common/AccessControl.svelte +++ b/src/lib/components/workspace/common/AccessControl.svelte @@ -12,6 +12,7 @@ import Plus from '$lib/components/icons/Plus.svelte'; import AddAccessModal from './AddAccessModal.svelte'; import Tooltip from '$lib/components/common/Tooltip.svelte'; + import Switch from '$lib/components/common/Switch.svelte'; type AccessGrant = { id?: string; @@ -159,6 +160,12 @@ grant.principal_type === 'user' && grant.principal_id === '*' && grant.permission === 'read' ); + const hasPublicWriteGrant = (grants: AccessGrant[]): boolean => + grants.some( + (grant) => + grant.principal_type === 'user' && grant.principal_id === '*' && grant.permission === 'write' + ); + const currentGrants = (): AccessGrant[] => Array.isArray(accessGrants) ? (accessGrants as AccessGrant[]) : []; @@ -194,12 +201,12 @@ }; const setPublic = (isPublic: boolean) => { + // Remove all user:* grants const filtered = currentGrants().filter( (grant) => !( grant.principal_type === 'user' && - grant.principal_id === '*' && - grant.permission === 'read' + grant.principal_id === '*' ) ); if (isPublic) { @@ -212,6 +219,23 @@ commitAccessGrants(filtered); }; + const togglePublicWrite = () => { + let next = [...currentGrants()]; + if (hasPublicWriteGrant(next)) { + next = next.filter( + (grant) => + !( + grant.principal_type === 'user' && + grant.principal_id === '*' && + grant.permission === 'write' + ) + ); + } else { + next = upsertPrincipalGrant('user', '*', 'write', next); + } + commitAccessGrants(next); + }; + const upsertPrincipalGrant = ( principalType: 'user' | 'group', principalId: string, @@ -491,6 +515,20 @@ + + {#if hasPublicReadGrant(accessGrants ?? []) && accessRoles.includes('write')} +
+
+ {$i18n.t('Allow everyone to edit')} +
+ { + togglePublicWrite(); + }} + /> +
+ {/if} {#if share}