Compare commits

...

6 Commits

Author SHA1 Message Date
7c58b9021a Merge remote-tracking branch 'origin/dev' into dev
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 50s
Build and Push Docker Images / build-frontend (push) Successful in 25s
Build and Push Docker Images / build-website (push) Successful in 22s
Build and Push Docker Images / build-central-services-api (push) Successful in 22s
Build and Push Docker Images / build-docs (push) Successful in 22s
Build and Push Docker Images / build-central-services-admin (push) Successful in 23s
2026-09-04 07:48:52 +02:00
62eef04a6b KI-AGENT: Password-Reset gegen hängenden Mailversand absichern 2026-09-04 07:47:43 +02:00
a298712973 Merge remote-tracking branch 'origin/dev' into dev 2026-08-31 21:44:33 +02:00
12130395e3 Merge remote-tracking branch 'origin/dev' into dev 2026-08-31 21:40:50 +02:00
1ae76380a9 Merge remote-tracking branch 'origin/dev' into dev 2026-08-31 21:37:21 +02:00
40bd1769ee KI-AGENT: Upload-Timeout für Tenant-Import erhöhen 2026-08-27 08:51:01 +02:00
3 changed files with 31 additions and 6 deletions

View File

@@ -6,7 +6,7 @@ import { sendMail } from "../../utils/mailer";
import { authUsers } from "../../../db/schema"; import { authUsers } from "../../../db/schema";
import { authTenantUsers } from "../../../db/schema"; import { authTenantUsers } from "../../../db/schema";
import { tenants } from "../../../db/schema"; import { tenants } from "../../../db/schema";
import { eq } from "drizzle-orm"; import { and, eq } from "drizzle-orm";
import { import {
createAccessToken, createAccessToken,
issueRefreshToken, issueRefreshToken,
@@ -211,6 +211,8 @@ export default async function authRoutes(server: FastifyInstance) {
.select({ .select({
id: authUsers.id, id: authUsers.id,
email: authUsers.email, email: authUsers.email,
passwordHash: authUsers.passwordHash,
mustChangePassword: authUsers.must_change_password,
}) })
.from(authUsers) .from(authUsers)
.where(eq(authUsers.email, email.toLowerCase())) .where(eq(authUsers.email, email.toLowerCase()))
@@ -228,12 +230,11 @@ export default async function authRoutes(server: FastifyInstance) {
.update(authUsers) .update(authUsers)
.set({ .set({
passwordHash, passwordHash,
// @ts-ignore must_change_password: true,
mustChangePassword: true,
}) })
.where(eq(authUsers.id, user.id)); .where(eq(authUsers.id, user.id));
await sendMail( const mailResult = await sendMail(
user.email, user.email,
"FEDEO | Dein neues Passwort", "FEDEO | Dein neues Passwort",
` `
@@ -241,9 +242,26 @@ export default async function authRoutes(server: FastifyInstance) {
<p>Dein Passwort wurde zurückgesetzt.</p> <p>Dein Passwort wurde zurückgesetzt.</p>
<p><strong>Neues Passwort:</strong> ${plainPassword}</p> <p><strong>Neues Passwort:</strong> ${plainPassword}</p>
<p>Bitte ändere es nach dem Login umgehend.</p> <p>Bitte ändere es nach dem Login umgehend.</p>
` `
); );
if (!mailResult.success) {
// Ein fehlgeschlagener Mailversand darf das bisherige Passwort nicht
// unbrauchbar machen. Die Hash-Bedingung schützt parallele Resets.
await server.db
.update(authUsers)
.set({
passwordHash: user.passwordHash,
must_change_password: user.mustChangePassword,
})
.where(and(
eq(authUsers.id, user.id),
eq(authUsers.passwordHash, passwordHash),
));
return reply.code(502).send({ error: "Password reset email could not be sent" });
}
return { success: true }; return { success: true };
}); });
} }

View File

@@ -7,6 +7,11 @@ export const initMailer = async () => {
host: secrets.MAILER_SMTP_HOST, host: secrets.MAILER_SMTP_HOST,
port: Number(secrets.MAILER_SMTP_PORT) || 587, port: Number(secrets.MAILER_SMTP_PORT) || 587,
secure: secrets.MAILER_SMTP_SSL === "true", // true für 465, false für andere Ports secure: secrets.MAILER_SMTP_SSL === "true", // true für 465, false für andere Ports
// Ohne explizite Timeouts kann ein API-Request bei einem nicht erreichbaren
// SMTP-Server mehrere Minuten offen bleiben.
connectionTimeout: 10_000,
greetingTimeout: 10_000,
socketTimeout: 20_000,
auth: { auth: {
user: secrets.MAILER_SMTP_USER, user: secrets.MAILER_SMTP_USER,
pass: secrets.MAILER_SMTP_PASS, pass: secrets.MAILER_SMTP_PASS,
@@ -34,4 +39,4 @@ export async function sendMail(
console.error("❌ Fehler beim Mailversand:", err) console.error("❌ Fehler beim Mailversand:", err)
return { success: false, error: err } return { success: false, error: err }
} }
} }

View File

@@ -10,6 +10,8 @@ services:
- --providers.docker.exposedbydefault=false - --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80 - --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443 - --entrypoints.websecure.address=:443
- --entrypoints.web.transport.respondingtimeouts.readtimeout=10m
- --entrypoints.websecure.transport.respondingtimeouts.readtimeout=10m
- --entrypoints.web.http.redirections.entrypoint.to=websecure - --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https - --entrypoints.web.http.redirections.entrypoint.scheme=https
- --certificatesresolvers.letsencrypt.acme.tlschallenge=true - --certificatesresolvers.letsencrypt.acme.tlschallenge=true