Commit Graph
362 Commits
Author SHA1 Message Date
G30 819ad1d904 fix(chat): convert recursive findClosingDelimiter to iterative loop to prevent stack overflow (#25845) 2026-06-17 03:07:12 +02:00
Timothy Jaeryang Baek 6fce92aa12 chore: format 2026-06-01 13:56:55 -07:00
Chane Lu 974b13839e fix: polyfill readable stream async iteration for Safari PDF extraction (#25473) 2026-06-01 13:47:57 -07:00
Classic298andClaude Opus 4.8 bf6325ff33 fix: sanitize mermaid SVG output to prevent stored XSS in file preview (#25219)
renderMermaidDiagram returned raw mermaid SVG, which FilePreview.svelte injects
via wrapper.innerHTML = svg. Mermaid runs with securityLevel: 'loose', so it
neither sanitizes click hrefs (formatUrl skips sanitizeUrl) nor DOMPurifies its
output; a .md file with a click X href "javascript:..." directive (or an
HTML-label payload) therefore executes script in the app origin when previewed.
The chat path was already safe because SVGPanZoom DOMPurifies before rendering;
file preview was not.

Sanitize at the source: renderMermaidDiagram now returns DOMPurify-cleaned SVG
via a shared sanitizeSvg helper (same policy as SVGPanZoom), so every consumer
including the FilePreview innerHTML sink receives safe output.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 14:49:43 -07:00
Timothy Jaeryang Baek 60c9db1cb8 refac: kb sync 2026-05-20 01:13:52 +04:00
Timothy Jaeryang Baek d310a0777c refac 2026-05-19 20:12:00 +04:00
Timothy Jaeryang Baek c951b4f262 chore: format 2026-05-11 02:29:13 +09:00
Timothy Jaeryang Baek 3bba1c2270 feat: add IFRAME_CSP env var for srcdoc iframe content security policy
Adds an IFRAME_CSP environment variable that injects a Content-Security-Policy
<meta> tag into all srcdoc iframes rendering untrusted content:
- Artifacts (LLM-generated HTML previews)
- FullHeightIframe (tool/embed output)
- FilePreview (user-uploaded HTML files)
- CitationModal (RAG document HTML)

Shared utility in src/lib/utils/csp.ts handles injection with HTML-safe
attribute escaping. URL-based iframes (src=) are correctly excluded.

Env-var only — no PersistentConfig, no admin UI, no DB. Set once at deploy
time, requires restart. Empty string (default) means no CSP restriction.
2026-05-11 01:56:02 +09:00
Timothy Jaeryang Baek 7bcc0e2e5c chore: format 2026-05-09 15:25:27 +09:00
Timothy Jaeryang Baek 85c7373f68 refac 2026-05-09 07:37:53 +09:00
Classic298 cfd2888545 fix:image url validation and signout post (#24420)
* refac(routers): reject external URLs in profile/model image handlers

* refac(ui): centralize image URL validation in safeImageUrl helper

* refac(auths): make signout POST-only

* refac: gate external profile image redirect behind ENABLE_PROFILE_IMAGE_URL_FORWARDING

Restore the 302 redirect for external http(s) profile image URLs in
the user and model profile-image endpoints, but gate it behind a new
ENABLE_PROFILE_IMAGE_URL_FORWARDING env flag (default: True).

Existing deployments that rely on external profile image forwarding
continue to work unchanged.  Operators who want to suppress the
redirect (to prevent client-side IP/UA/Referer leaks) can set the
flag to False.
2026-05-09 07:33:31 +09:00
Timothy Jaeryang Baek 5b80932e59 refac 2026-05-09 06:56:22 +09:00
Timothy Jaeryang Baek 2ba6b423aa refac 2026-05-09 06:50:11 +09:00
Timothy Jaeryang Baek f70b0da156 refac 2026-05-09 06:16:27 +09:00
Timothy Jaeryang Baek bf4f44ee9c refac 2026-05-09 05:27:47 +09:00
Timothy Jaeryang Baek 8ffc3d746f refac 2026-05-09 04:22:46 +09:00
Timothy Jaeryang Baek 4d766a3edf refac 2026-05-09 03:19:48 +09:00
Timothy Jaeryang Baek 3b821e1f3a refac 2026-04-21 16:32:17 +09:00
Timothy Jaeryang Baek 085d3cb1c9 refac 2026-04-21 16:16:48 +09:00
Timothy Jaeryang Baek 5087492e25 refac 2026-04-19 15:49:42 +09:00
Timothy Jaeryang Baek 4113b15a60 chore: format 2026-04-17 14:28:18 +09:00
Shirasawa 7b5880ab9e fix: clean up Mermaid temporary DOM nodes after render failures (#23727)
* fix: clean up Mermaid temporary DOM nodes after render failures

* fix: prevent Mermaid temp DOM artifacts from accumulating
2026-04-17 11:44:10 +09:00
Timothy Jaeryang Baek 45e49d33e5 refac 2026-04-13 21:52:19 -05:00
Timothy Jaeryang Baek fc98000aa8 refac 2026-04-12 19:15:54 -05:00
Timothy Jaeryang Baek 21cc828132 refac 2026-04-12 19:13:13 -05:00
Timothy Jaeryang Baek 25898116ea chore: format 2026-04-12 18:12:59 -05:00
Timothy Jaeryang Baek 15b89b9218 refac 2026-04-12 16:56:00 -05:00
Algorithm5838 b6db719758 perf: build mention regex once in factory closure (#23551) 2026-04-11 15:02:17 -06:00
Algorithm5838 16e6cb458f perf: skip replaceTokens when no {{ present (#23161) 2026-04-01 05:37:44 -05:00
Algorithm5838 2d83d0f950 perf: replace unescapeHtml DOMParser with html-entities decode (#23165) 2026-04-01 05:35:20 -05:00
Algorithm5838 354a179f6d perf: skip processChineseContent for non-Chinese content (#23162) 2026-04-01 05:34:50 -05:00
Timothy Jaeryang Baek eb5c95ef8e refac 2026-04-01 05:30:07 -05:00
Timothy Jaeryang Baek ade617efa8 refac 2026-03-24 04:49:48 -05:00
Timothy Jaeryang Baek 139e764b2f refac 2026-03-23 23:39:52 -05:00
Timothy Jaeryang Baek 9a6bf78e14 refac 2026-03-22 21:36:45 -05:00
Timothy Jaeryang Baek 4c8615f01c refac 2026-03-21 17:45:36 -05:00
Timothy Jaeryang Baek 4f0e574201 refac 2026-03-21 17:26:30 -05:00
Timothy Jaeryang Baek 53b8a1f71b enh: colon fence md 2026-03-21 17:23:38 -05:00
157ae917eb fix: replace legacy surrogate-pair emoji regex with Unicode property escape (#22915)
The previous regular expression used manual surrogate-pair ranges to
match emojis and missed a large category of commonly used symbols:

  /[\uD800-\uDBFF][\uDC00-\uDFFF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/g

This approach only covers emojis encoded as surrogate pairs (U+1F000 –
U+1F4FF range), but silently skips BMP emojis that use a text-
presentation code point followed by the variation selector U+FE0F,
such as ❤️ (U+2764 U+FE0F), ☀️, ✅, ⚡, ⭐, and keycap sequences
like 1️⃣, as well as ZWJ family sequences (👨‍👩‍👧‍👦) and flag sequences.

Replace with the Unicode property escape \p{RGI_Emoji} using the 'v'
(unicodeSets) flag introduced in ES2024. This single pattern covers
every standardised emoji sequence defined by Unicode, including all
the cases above.

Browser support: Chrome 112+, Firefox 116+, Safari 17+, Node.js 20+.
All browsers targeted by open-webui already support this syntax.

Co-authored-by: Tim Baek <tim@openwebui.com>
Co-authored-by: joaoback <156559121+joaoback@users.noreply.github.com>
Co-authored-by: yoloni <yoloni@tencent.com>
2026-03-21 16:43:09 -05:00
Timothy Jaeryang Baek 694fb3776f refac 2026-03-19 17:56:05 -05:00
Classic298 bbbe2b66b4 fix: use static month names in getTimeRange to prevent OS locale leaking into sidebar (#22454)
getTimeRange returns month names that are used as i18n translation keys
(consumed via \.t(chat.time_range) in the sidebar, search modal, etc.).
The keys must be exact English strings like 'January', 'February', etc.

Previously, toLocaleString('default', { month: 'long' }) was used to
generate these keys. The 'default' locale defers to the browser's locale
resolution, which in Firefox with intl.regional_prefs.use_os_locales=true
picks up OS regional settings instead of the browser language. This caused
German month names (e.g. 'Februar', 'Januar') to appear in the sidebar for
users whose OS region is set to Germany, even when both browser and app
language are set to English. Chrome was unaffected because it ignores OS
regional settings for the 'default' locale.

Since i18n has no translation key for 'Februar', the German string passed
through untranslated. Replace toLocaleString with a static MONTH_NAMES
array lookup to make the intent explicit and eliminate any browser/OS
locale dependency.
2026-03-08 16:44:03 -05:00
Timothy Jaeryang Baek 35bc831077 refac 2026-03-07 18:18:02 -06:00
Timothy Jaeryang Baek 6d9996e599 refac 2026-03-06 20:12:37 -06:00
Timothy Jaeryang Baek b3622474d7 refac 2026-03-06 16:25:00 -06:00
Shirasawa 200fb093b1 fix: Use toBlob on first mobile export to avoid black canvas image on Android (#22317) 2026-03-06 15:48:44 -06:00
Classic298 576ee92438 perf: rewrite createMessagesList from recursive to iterative (#22194)
Replace the recursive spread-based implementation with an iterative
push+reverse approach. The recursive version created a new array at
each level of recursion via spread, resulting in O(d^2) array copies
where d is the conversation depth. The iterative version walks from
the target message to the root, pushes each message, and reverses
once at the end for O(d) total work.

No behavioral change - same input produces the same output array.
2026-03-06 15:36:13 -06:00
Classic298 a70c718a0d fix: TTS reading thinking content when reasoning has code blocks (#22237)
removeAllDetails() uses replaceOutsideCode() which splits content on
triple-backtick code blocks before applying the details-removal regex.

When thinking/reasoning content inside a <details> block contained
code blocks (backticks survive html.escape), the <details> opening
and </details> closing tags ended up in different split segments,
making the regex unable to match either. This caused thinking content
to leak through to TTS playback.

Fix: add a direct <details> strip (without code-block splitting) as
the first step of getMessageContentParts(), which is the TTS-specific
entry point. This catches the edge case while keeping removeAllDetails
safe for copy-to-clipboard (where legitimate <details> inside code
blocks should be preserved).

Fixes #22197
2026-03-06 14:46:31 -06:00
Classic298 fe58ef69d9 perf(frontend): lazy-load shiki to remove ~5-10MB from initial bundle (#22304)
codeHighlight.ts had a top-level static import of shiki that pulled
the entire highlighter engine (~5-10MB of JavaScript including all
language grammars) into any page that imported the module - even if
only the lightweight isCodeFile() function was used.

Replace the static shiki import with:
- A static set of ~85 common language IDs for synchronous extension
  checks (isCodeFile, extToLang) - no shiki dependency needed
- A dynamic import('shiki') inside highlightCode(), which is already
  async so callers are completely unaffected

The static language set covers all commonly-used file extensions.
Obscure extensions not in the set simply won't be detected by
isCodeFile() (the file still opens fine, just won't show the code
file indicator). Highlighting itself still works for all shiki
languages since the full bundle loads on demand.
2026-03-06 13:47:17 -06:00
Classic298 8cd2157564 Perf: precompile katex unicode regex (#22196)
* perf: pre-compile KaTeX Unicode regex at module load time

The katexStart() function was creating a new RegExp with Unicode
property escapes (\p{Script=Han}, \p{Script=Hiragana}, etc.) on
every invocation. Unicode property escapes are extremely expensive
to compile as the regex engine must build character class tables
covering tens of thousands of code points.

Since marked calls the start() function at every character position
while scanning source text, this meant hundreds of regex compilations
per marked.lexer() call, and lexer runs ~60 times/sec during streaming.
Profiling showed KaTeX regex consuming 87% (320ms/365ms) of total
markdown rendering time.

Changes:
- Pre-compile SURROUNDING_CHARS_REGEX once at module load time
- Use .test() instead of .match() to avoid array allocations
- Fix delimiter search to find earliest match, not last match

* perf: replace katexStart with single-pass character scan

The katexStart() function was the dominant cost in marked's lexer,
consuming 55-58% of total markdown rendering time per profiling.

It was called at every character position by marked and each call:
- Looped through 3-5 delimiters, each doing indexOf() on the full
  remaining source (3-5 x O(n) string scans per call)
- Ran the complex ruleReg regex with Unicode lookaheads for validation
- On failed validation, created substrings and looped again

Replace with a single linear character scan using charCodeAt that:
- Checks only for $ (charCode 36) or backslash (charCode 92)
- Filters backslash hits by next character to avoid false positives
- Preserves the surrounding-character validation
- Returns immediately on first valid candidate
- Lets the tokenizer handle full validation (it already does this)

This reduces start() from O(n * delimiters * retries) to O(n) with
a very small constant factor per call.

* Update katex-extension.ts
2026-03-05 16:02:00 -06:00
Timothy Jaeryang Baek f962bae983 feat: improve XLSX preview + add code syntax highlighting
XLSX QoL:
- Custom table renderer (excelToTable.ts) with column letters,
  row numbers, right-aligned numbers, empty cell handling
- Monospace font, sticky headers + row nums, cell cursor
- Sheet tabs moved to bottom bar (like PPTX navigation)
- Unified styles between FileNav and FileItemModal

Code highlighting:
- Shiki-based syntax highlighting for code files in FileNav
- Line numbers, dark/light theme support
- Source/Preview toggle for code files
2026-03-04 15:59:55 -06:00