diff --git a/backend/open_webui/routers/terminals.py b/backend/open_webui/routers/terminals.py index 49c39c8bf..59f1f3ab4 100644 --- a/backend/open_webui/routers/terminals.py +++ b/backend/open_webui/routers/terminals.py @@ -31,14 +31,20 @@ def _sanitize_proxy_path(path: str) -> str | None: """Sanitize a proxy path to prevent directory traversal / SSRF. Returns the cleaned path, or None if the path is invalid. + Trailing slashes are preserved — many upstream frameworks treat + ``/path`` and ``/path/`` differently. """ decoded = unquote(path) + had_trailing_slash = decoded.endswith('/') normalized = posixpath.normpath(decoded) # Remove any leading slashes that would reset the base cleaned = normalized.lstrip('/') # Reject if normpath resolved to parent traversal or current-dir only if cleaned.startswith('..') or cleaned == '.': return None + # Restore trailing slash if the original path had one + if had_trailing_slash and cleaned and not cleaned.endswith('/'): + cleaned += '/' return cleaned diff --git a/src/lib/components/chat/FileNav.svelte b/src/lib/components/chat/FileNav.svelte index 770d2b270..adb8bdf6d 100644 --- a/src/lib/components/chat/FileNav.svelte +++ b/src/lib/components/chat/FileNav.svelte @@ -40,6 +40,7 @@ import FilePreview from './FileNav/FilePreview.svelte'; import FileEntryRow from './FileNav/FileEntryRow.svelte'; import PortList from './FileNav/PortList.svelte'; + import PortPreview from './FileNav/PortPreview.svelte'; import XTerminal from './XTerminal.svelte'; const i18n = getContext('i18n'); @@ -90,6 +91,7 @@ // ── File preview state ─────────────────────────────────────────────── let selectedFile: string | null = null; + let previewPort: number | null = null; let fileContent: string | null = null; let fileImageUrl: string | null = null; let fileVideoUrl: string | null = null; @@ -253,6 +255,7 @@ loading = true; error = null; selectedFile = null; + previewPort = null; clearFilePreview(); currentPath = path; savedPath = path; @@ -632,6 +635,7 @@ {/if} + {#if previewPort === null} + {/if}
- {#if selectedFile !== null} + {#if previewPort !== null} + { previewPort = null; }} + /> + {:else if selectedFile !== null} - {#if selectedTerminal && !selectedFile} + {#if selectedTerminal && !selectedFile && previewPort === null}
- + { + selectedFile = null; + clearFilePreview(); + previewPort = e.detail; + }} + />
{/if} diff --git a/src/lib/components/chat/FileNav/PortList.svelte b/src/lib/components/chat/FileNav/PortList.svelte index 8a5dfb3cd..9e8595112 100644 --- a/src/lib/components/chat/FileNav/PortList.svelte +++ b/src/lib/components/chat/FileNav/PortList.svelte @@ -1,10 +1,11 @@ + +
+ +
+ + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + +
+ + + {#if isLoading} +
+
+
+ {/if} + + + {#key iframeKey} +