From a34bf43756eea5b8409c7aefeb066797ffb8db0f Mon Sep 17 00:00:00 2001 From: florianfederspiel Date: Sat, 23 May 2026 21:02:45 +0200 Subject: [PATCH] E-Mail Anhang-Download CORS absichern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit KI-AGENT: OPTIONS-Preflights werden nicht mehr durch den Auth-Hook blockiert und der E-Mail Anhang-Download setzt CORS-Header auch für Fehlerantworten explizit. --- backend/src/plugins/auth.ts | 4 ++++ backend/src/routes/emailAsUser.ts | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/backend/src/plugins/auth.ts b/backend/src/plugins/auth.ts index 8a69e1b..2b442a8 100644 --- a/backend/src/plugins/auth.ts +++ b/backend/src/plugins/auth.ts @@ -64,6 +64,10 @@ export default fp(async (server: FastifyInstance) => { } server.addHook("preHandler", async (req, reply) => { + if (req.method === "OPTIONS") { + return + } + // 1️⃣ Token aus Header oder Cookie lesen const cookieToken = req.cookies?.token const authHeader = req.headers.authorization diff --git a/backend/src/routes/emailAsUser.ts b/backend/src/routes/emailAsUser.ts index 6c9fdfd..37e42e3 100644 --- a/backend/src/routes/emailAsUser.ts +++ b/backend/src/routes/emailAsUser.ts @@ -39,6 +39,25 @@ export default async function emailAsUserRoutes(server: FastifyInstance) { const bodyValue = (body: any, camelKey: string, snakeKey: string) => body[camelKey] ?? body[snakeKey] + const applyDownloadCorsHeaders = (req: any, reply: any) => { + const origin = req.headers.origin + if ( + origin + && ( + /^http:\/\/(localhost|127\.0\.0\.1):\d+$/.test(origin) + || origin === "https://beta.fedeo.de" + || origin === "https://app.fedeo.de" + || origin === "capacitor://localhost" + ) + ) { + reply.header("Access-Control-Allow-Origin", origin) + reply.header("Access-Control-Allow-Credentials", "true") + reply.header("Vary", "Origin") + } + + reply.header("Access-Control-Expose-Headers", "Authorization, Content-Disposition, Content-Type, Content-Length") + } + const accountWhere = (tenantId: number, userId: string, id?: string) => { const conditions = [ eq(userCredentials.tenantId, tenantId), @@ -456,6 +475,8 @@ export default async function emailAsUserRoutes(server: FastifyInstance) { }) server.get("/email/attachments/:id/download", async (req, reply) => { + applyDownloadCorsHeaders(req, reply) + try { if (!req.user?.tenant_id) { return reply.code(400).send({ error: "No tenant selected" })