swadhinbiswas feat: finalize platform polish - discussions, gists, webhook queue, realtime, push-mirror, auth/metrics hardening · 8/28/2026
f02976d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import { getDatabase, schema } from "@/db";
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
import { passwordResetTokens, users } from "@/db/schema";
import { badRequest, parseBody, serverError, success } from "@/lib/api";
import { now } from "@/lib/utils";
import type { APIRoute } from "astro";
import bcrypt from "bcryptjs";
import { eq } from "drizzle-orm";
import { z } from "zod";
import { logger } from "@/lib/logger";
import { withErrorHandler } from "@/lib/errors";
const resetPasswordSchema = z.object({
token: z.string().min(1),
password: z.string().min(8),
});
export const POST: APIRoute = withErrorHandler(async ({ request }) => {
const parsed = await parseBody(request, resetPasswordSchema);
if ("error" in parsed) return parsed.error;
const { token, password } = parsed.data;
const db = getDatabase() as NodePgDatabase<typeof schema>;
// Find token
const resetToken = await db.query.passwordResetTokens.findFirst({
where: eq(passwordResetTokens.token, token),
});
if (!resetToken) {
logger.warn({ token }, "Invalid password reset token used");
return badRequest("Invalid or expired token");
}
// Check expiration
if (new Date(resetToken.expiresAt) < new Date()) {
// Delete expired token
await db
.delete(passwordResetTokens)
.where(eq(passwordResetTokens.id, resetToken.id));
logger.warn({ token }, "Expired password reset token used");
return badRequest("Invalid or expired token");
}
// Hash new password
const salt = await bcrypt.genSalt(10);
const passwordHash = await bcrypt.hash(password, salt);
// Update user password
await db
.update(users)
.set({
passwordHash,
updatedAt: new Date(),
})
.where(eq(users.id, resetToken.userId));
// Revoke all sessions — reset tokens prove account compromise recovery path
await db
.delete(schema.sessions)
.where(eq(schema.sessions.userId, resetToken.userId));
const { revokeUserSessionCache } = await import("@/lib/auth-cache");
revokeUserSessionCache(resetToken.userId);
// Delete used token
await db
.delete(passwordResetTokens)
.where(eq(passwordResetTokens.id, resetToken.id));
logger.info({ userId: resetToken.userId }, "Password reset completed via token");
return success({ message: "Password reset successfully" });
});