fix: download chat file attachments inline with auth

Clicking a file attachment in chat opens a preview modal (plain file refs)
or a new tab via window.open to /files/{id}/content. The JWT is stored in
localStorage and sent as an Authorization header on fetch — it is not
available as a cookie on plain navigation, so the new-tab request returns
401 for regular logins (the token cookie is only set in the OAuth flow).

Fix: skip the preview modal for plain file refs and fetch the file bytes
with the Authorization header, then trigger a direct browser download with
the original filename (?attachment=true forces Content-Disposition:
attachment for all content types). Falls back to the previous window.open
behavior on failure. Items with embedded content still open the modal;
external http(s) URLs are unchanged; input-box attachments are unaffected
(they pass modal=true).
This commit is contained in:
ShraddhanandKhot 2026-08-14 13:42:50 +00:00
parent d02b6a21fc
commit a4b4c1877f

View file

@ -57,7 +57,7 @@
: 'gap-1 rounded-2xl p-1.5'} text-left"
type="button"
on:click={async () => {
if (item?.file?.data?.content || item?.type === 'file' || item?.content || modal) {
if (item?.file?.data?.content || item?.content || modal) {
showModal = !showModal;
} else {
if (url) {
@ -65,7 +65,30 @@
if (url.startsWith('http')) {
window.open(`${url}/content`, '_blank').focus();
} else {
window.open(`${WEBUI_API_BASE_URL}/files/${url}/content`, '_blank').focus();
// The JWT lives in localStorage (sent as an Authorization header
// on fetch) and is not available as a cookie on plain navigation,
// so opening the file URL in a new tab returns 401. Fetch the
// bytes with the token and trigger a direct browser download.
try {
const res = await fetch(
`${WEBUI_API_BASE_URL}/files/${url}/content?attachment=true`,
{ headers: { Authorization: `Bearer ${localStorage.token}` } }
);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const blob = await res.blob();
const objectUrl = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = objectUrl;
a.download = name;
document.body.appendChild(a);
a.click();
a.remove();
setTimeout(() => window.URL.revokeObjectURL(objectUrl), 3000);
} catch (err) {
console.error(err);
window.open(`${WEBUI_API_BASE_URL}/files/${url}/content`, '_blank').focus();
}
}
} else {
window.open(`${url}`, '_blank').focus();