mirror of
https://github.com/open-webui/open-webui.git
synced 2026-09-28 01:31:28 +00:00
fix: restrict uploads to admin-configured terminals, resolve before fetching file, accept 2xx
This commit is contained in:
parent
297369b195
commit
4cbbe73376
1 changed files with 47 additions and 61 deletions
|
|
@ -2857,12 +2857,56 @@ async def upload_file_to_terminal(
|
|||
try:
|
||||
from open_webui.models.files import Files
|
||||
from open_webui.storage.provider import Storage
|
||||
from open_webui.utils.access_control import has_connection_access
|
||||
from open_webui.utils.access_control.files import has_access_to_file
|
||||
|
||||
user_id = __user__.get('id')
|
||||
user_role = __user__.get('role', 'user')
|
||||
|
||||
# --- 1. Retrieve file and check access ---
|
||||
# --- 1. Resolve terminal connection and build auth ---
|
||||
cookies = {}
|
||||
headers = {'X-User-Id': __user__.get('id', '')}
|
||||
|
||||
connections = __request__.app.state.config.TERMINAL_SERVER_CONNECTIONS or []
|
||||
connection = next(
|
||||
(c for c in connections if c.get('id') == terminal_id), None
|
||||
)
|
||||
|
||||
if not connection:
|
||||
return json.dumps({'error': f"Terminal connection '{terminal_id}' not found"})
|
||||
|
||||
if not await has_connection_access(UserModel(**__user__), connection):
|
||||
return json.dumps({'error': 'Access denied to terminal server'})
|
||||
|
||||
terminal_url = connection.get('url', '').rstrip('/')
|
||||
|
||||
# Route through orchestrator policy endpoint if configured
|
||||
policy_id = connection.get('policy_id')
|
||||
if policy_id:
|
||||
terminal_url = f'{terminal_url}/p/{policy_id}'
|
||||
|
||||
# Build auth headers/cookies matching resolve_terminal_tools pattern
|
||||
auth_type = connection.get('auth_type', 'bearer')
|
||||
if auth_type == 'bearer':
|
||||
key = connection.get('key', '')
|
||||
if key:
|
||||
headers['Authorization'] = f'Bearer {key}'
|
||||
elif auth_type == 'session':
|
||||
cookies = __request__.cookies
|
||||
if hasattr(__request__, 'state') and hasattr(__request__.state, 'token'):
|
||||
headers['Authorization'] = f'Bearer {__request__.state.token.credentials}'
|
||||
elif auth_type == 'system_oauth':
|
||||
cookies = __request__.cookies
|
||||
oauth_token = metadata.get('oauth_token') or {}
|
||||
if oauth_token.get('access_token'):
|
||||
headers['Authorization'] = f'Bearer {oauth_token["access_token"]}'
|
||||
# auth_type == 'none': no Authorization header
|
||||
|
||||
chat_id = metadata.get('chat_id')
|
||||
if chat_id:
|
||||
headers['X-Session-Id'] = chat_id
|
||||
|
||||
# --- 2. Retrieve file and check access ---
|
||||
file_record = await Files.get_file_by_id(file_id)
|
||||
if not file_record:
|
||||
return json.dumps({'error': 'File not found'})
|
||||
|
|
@ -2880,65 +2924,6 @@ async def upload_file_to_terminal(
|
|||
|
||||
local_path = Storage.get_file(file_record.path)
|
||||
|
||||
# --- 2. Resolve terminal connection and build auth ---
|
||||
from open_webui.utils.access_control import has_connection_access
|
||||
|
||||
terminal_url = None
|
||||
cookies = {}
|
||||
headers = {'X-User-Id': __user__.get('id', '')}
|
||||
|
||||
# Try system terminal first (terminal_id is a connection ID)
|
||||
connections = __request__.app.state.config.TERMINAL_SERVER_CONNECTIONS or []
|
||||
connection = next(
|
||||
(c for c in connections if c.get('id') == terminal_id), None
|
||||
)
|
||||
|
||||
if connection:
|
||||
if not await has_connection_access(UserModel(**__user__), connection):
|
||||
return json.dumps({'error': 'Access denied to terminal server'})
|
||||
|
||||
terminal_url = connection.get('url', '').rstrip('/')
|
||||
|
||||
# Route through orchestrator policy endpoint if configured
|
||||
policy_id = connection.get('policy_id')
|
||||
if policy_id:
|
||||
terminal_url = f'{terminal_url}/p/{policy_id}'
|
||||
|
||||
# Build auth headers/cookies matching resolve_terminal_tools pattern
|
||||
auth_type = connection.get('auth_type', 'bearer')
|
||||
if auth_type == 'bearer':
|
||||
key = connection.get('key', '')
|
||||
if key:
|
||||
headers['Authorization'] = f'Bearer {key}'
|
||||
elif auth_type == 'session':
|
||||
cookies = __request__.cookies
|
||||
if hasattr(__request__, 'state') and hasattr(__request__.state, 'token'):
|
||||
headers['Authorization'] = f'Bearer {__request__.state.token.credentials}'
|
||||
elif auth_type == 'system_oauth':
|
||||
cookies = __request__.cookies
|
||||
oauth_token = metadata.get('oauth_token') or {}
|
||||
if oauth_token.get('access_token'):
|
||||
headers['Authorization'] = f'Bearer {oauth_token["access_token"]}'
|
||||
# auth_type == 'none': no Authorization header
|
||||
else:
|
||||
# Try direct/user-configured terminal (terminal_id is the URL)
|
||||
direct_tool_servers = metadata.get('tool_servers') or []
|
||||
for ts in direct_tool_servers:
|
||||
ts_url = (ts.get('url') or '').rstrip('/')
|
||||
if ts_url and ts_url == terminal_id.rstrip('/'):
|
||||
terminal_url = ts_url
|
||||
key = ts.get('key', '')
|
||||
if key:
|
||||
headers['Authorization'] = f'Bearer {key}'
|
||||
break
|
||||
|
||||
if not terminal_url:
|
||||
return json.dumps({'error': f"Terminal connection '{terminal_id}' could not be resolved"})
|
||||
|
||||
chat_id = metadata.get('chat_id')
|
||||
if chat_id:
|
||||
headers['X-Session-Id'] = chat_id
|
||||
|
||||
# --- 3. Upload to terminal server ---
|
||||
import aiohttp
|
||||
|
||||
|
|
@ -2975,7 +2960,7 @@ async def upload_file_to_terminal(
|
|||
headers=headers,
|
||||
cookies=cookies,
|
||||
) as response:
|
||||
if response.status != 200:
|
||||
if not (200 <= response.status < 300):
|
||||
detail = (await response.text())[:500]
|
||||
return json.dumps(
|
||||
{'error': f'Upload failed (HTTP {response.status}): {detail}'}
|
||||
|
|
@ -2994,3 +2979,4 @@ async def upload_file_to_terminal(
|
|||
except Exception as e:
|
||||
log.exception(f'upload_file_to_terminal error: {e}')
|
||||
return json.dumps({'error': str(e)})
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue