E-Mail Anhänge ohne Fetch herunterladen
KI-AGENT: Der E-Mail Anhang-Download nutzt jetzt einen nativen Browser-Link statt Cross-Origin-Fetch und erlaubt dafür den bestehenden JWT gezielt als Download-Token.
This commit is contained in:
@@ -68,6 +68,15 @@ export default fp(async (server: FastifyInstance) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const urlPath = req.url.split("?")[0]
|
||||||
|
const queryToken = (req.query as any)?.downloadToken
|
||||||
|
const downloadToken =
|
||||||
|
typeof queryToken === "string"
|
||||||
|
&& urlPath.startsWith("/api/email/attachments/")
|
||||||
|
&& urlPath.endsWith("/download")
|
||||||
|
? queryToken
|
||||||
|
: null
|
||||||
|
|
||||||
// 1️⃣ Token aus Header oder Cookie lesen
|
// 1️⃣ Token aus Header oder Cookie lesen
|
||||||
const cookieToken = req.cookies?.token
|
const cookieToken = req.cookies?.token
|
||||||
const authHeader = req.headers.authorization
|
const authHeader = req.headers.authorization
|
||||||
@@ -78,7 +87,7 @@ export default fp(async (server: FastifyInstance) => {
|
|||||||
const token =
|
const token =
|
||||||
headerToken && headerToken.length > 10
|
headerToken && headerToken.length > 10
|
||||||
? headerToken
|
? headerToken
|
||||||
: cookieToken || null
|
: cookieToken || downloadToken || null
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return reply.code(401).send({ error: "Authentication required" })
|
return reply.code(401).send({ error: "Authentication required" })
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ type EmailMessage = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { $api } = useNuxtApp()
|
const { $api } = useNuxtApp()
|
||||||
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
|
|
||||||
const accounts = ref<EmailAccount[]>([])
|
const accounts = ref<EmailAccount[]>([])
|
||||||
@@ -456,24 +457,22 @@ async function moveSelectedMessage() {
|
|||||||
async function downloadAttachment(attachment: NonNullable<EmailMessage["attachments"]>[number]) {
|
async function downloadAttachment(attachment: NonNullable<EmailMessage["attachments"]>[number]) {
|
||||||
actionLoading.value = `attachment-${attachment.id}`
|
actionLoading.value = `attachment-${attachment.id}`
|
||||||
try {
|
try {
|
||||||
const response = await $api.raw(`/api/email/attachments/${attachment.id}/download`, {
|
const apiBase = String(runtimeConfig.public.apiBase || "").replace(/\/$/, "")
|
||||||
responseType: "arrayBuffer",
|
const path = `/api/email/attachments/${attachment.id}/download`
|
||||||
timeout: 60_000,
|
const downloadUrl = new URL(apiBase ? `${apiBase}${path}` : path, window.location.origin)
|
||||||
})
|
const token = useCookie("token").value
|
||||||
const contentType = response.headers.get("content-type") || attachment.contentType || "application/octet-stream"
|
|
||||||
const blob = new Blob([response._data as ArrayBuffer], { type: contentType })
|
if (token) {
|
||||||
const disposition = response.headers.get("content-disposition") || ""
|
downloadUrl.searchParams.set("downloadToken", token)
|
||||||
const dispositionFilename = disposition.match(/filename="([^"]+)"/)?.[1]
|
}
|
||||||
const filename = dispositionFilename || attachment.filename || "anhang"
|
|
||||||
const url = URL.createObjectURL(blob)
|
|
||||||
const link = document.createElement("a")
|
const link = document.createElement("a")
|
||||||
|
|
||||||
link.href = url
|
link.href = downloadUrl.toString()
|
||||||
link.download = filename
|
link.download = attachment.filename || "anhang"
|
||||||
document.body.appendChild(link)
|
document.body.appendChild(link)
|
||||||
link.click()
|
link.click()
|
||||||
link.remove()
|
link.remove()
|
||||||
URL.revokeObjectURL(url)
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
toast.add({
|
toast.add({
|
||||||
title: "Download fehlgeschlagen",
|
title: "Download fehlgeschlagen",
|
||||||
@@ -481,7 +480,9 @@ async function downloadAttachment(attachment: NonNullable<EmailMessage["attachme
|
|||||||
color: "error",
|
color: "error",
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
actionLoading.value = ""
|
window.setTimeout(() => {
|
||||||
|
actionLoading.value = ""
|
||||||
|
}, 750)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user