KI-AGENT: Password-Reset gegen hängenden Mailversand absichern

This commit is contained in:
2026-09-04 07:47:43 +02:00
parent a298712973
commit 62eef04a6b
2 changed files with 29 additions and 6 deletions

View File

@@ -6,7 +6,7 @@ import { sendMail } from "../../utils/mailer";
import { authUsers } from "../../../db/schema";
import { authTenantUsers } from "../../../db/schema";
import { tenants } from "../../../db/schema";
import { eq } from "drizzle-orm";
import { and, eq } from "drizzle-orm";
import {
createAccessToken,
issueRefreshToken,
@@ -211,6 +211,8 @@ export default async function authRoutes(server: FastifyInstance) {
.select({
id: authUsers.id,
email: authUsers.email,
passwordHash: authUsers.passwordHash,
mustChangePassword: authUsers.must_change_password,
})
.from(authUsers)
.where(eq(authUsers.email, email.toLowerCase()))
@@ -228,12 +230,11 @@ export default async function authRoutes(server: FastifyInstance) {
.update(authUsers)
.set({
passwordHash,
// @ts-ignore
mustChangePassword: true,
must_change_password: true,
})
.where(eq(authUsers.id, user.id));
await sendMail(
const mailResult = await sendMail(
user.email,
"FEDEO | Dein neues Passwort",
`
@@ -241,9 +242,26 @@ export default async function authRoutes(server: FastifyInstance) {
<p>Dein Passwort wurde zurückgesetzt.</p>
<p><strong>Neues Passwort:</strong> ${plainPassword}</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 };
});
}

View File

@@ -7,6 +7,11 @@ export const initMailer = async () => {
host: secrets.MAILER_SMTP_HOST,
port: Number(secrets.MAILER_SMTP_PORT) || 587,
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: {
user: secrets.MAILER_SMTP_USER,
pass: secrets.MAILER_SMTP_PASS,
@@ -34,4 +39,4 @@ export async function sendMail(
console.error("❌ Fehler beim Mailversand:", err)
return { success: false, error: err }
}
}
}