Add contact email confirmation and abuse protection

This commit is contained in:
t.indorf
2026-05-16 11:38:30 +02:00
parent 9542def530
commit 0b80c62beb
12 changed files with 376 additions and 17 deletions
+4
View File
@@ -19,3 +19,7 @@ export const contactRequestSchema = z.object({
});
export type ContactRequestInput = z.infer<typeof contactRequestSchema>;
export type ContactSubmissionPayload = ContactRequestInput & {
website?: string;
};
+14
View File
@@ -0,0 +1,14 @@
import { UserRole } from "@prisma/client";
type RedirectUser = {
role?: UserRole | string;
kitaId?: string | null;
};
export function getPostLoginRedirect(user: RedirectUser) {
if (user.role === UserRole.SUPERADMIN || user.role === "SUPERADMIN") {
return "/admin";
}
return user.kitaId ? "/dashboard" : "/onboarding";
}
+39
View File
@@ -0,0 +1,39 @@
type Bucket = {
count: number;
resetAt: number;
};
const buckets = new Map<string, Bucket>();
export type RateLimitResult =
| { allowed: true; remaining: number; resetAt: number }
| { allowed: false; retryAfterSeconds: number };
export function rateLimit(
key: string,
limit: number,
windowSeconds: number,
): RateLimitResult {
const now = Date.now();
const windowMs = windowSeconds * 1000;
const existing = buckets.get(key);
if (!existing || existing.resetAt <= now) {
buckets.set(key, { count: 1, resetAt: now + windowMs });
return { allowed: true, remaining: limit - 1, resetAt: now + windowMs };
}
if (existing.count >= limit) {
return {
allowed: false,
retryAfterSeconds: Math.ceil((existing.resetAt - now) / 1000),
};
}
existing.count += 1;
return {
allowed: true,
remaining: limit - existing.count,
resetAt: existing.resetAt,
};
}