feat(security): rate-limit auth/login + auth/verify
This commit is contained in:
parent
bafe24b778
commit
0eeb3c351f
4 changed files with 194 additions and 6 deletions
|
|
@ -1,18 +1,32 @@
|
|||
// server/api/auth/login.post.js
|
||||
import { getRequestIP } from "h3";
|
||||
import { connectDB } from "../../utils/mongoose.js";
|
||||
import { validateBody } from "../../utils/validateBody.js";
|
||||
import { emailSchema } from "../../utils/schemas.js";
|
||||
import { sendMagicLink } from "../../utils/magicLink.js";
|
||||
import { rateLimit } from "../../utils/rateLimit.js";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const ip = getRequestIP(event, { xForwardedFor: true }) || "unknown";
|
||||
if (!rateLimit(`auth:login:ip:${ip}`, { max: 5, windowMs: 3600_000 })) {
|
||||
throw createError({ statusCode: 429, statusMessage: "Too many login attempts" });
|
||||
}
|
||||
|
||||
await connectDB();
|
||||
|
||||
const { email } = await validateBody(event, emailSchema);
|
||||
const body = await validateBody(event, emailSchema);
|
||||
|
||||
if (!rateLimit(`auth:login:email:${body.email}`, { max: 3, windowMs: 3600_000 })) {
|
||||
throw createError({
|
||||
statusCode: 429,
|
||||
statusMessage: "Too many login attempts for this email",
|
||||
});
|
||||
}
|
||||
|
||||
const GENERIC_MESSAGE = "If this email is registered, we've sent a login link.";
|
||||
|
||||
try {
|
||||
await sendMagicLink(email);
|
||||
await sendMagicLink(body.email);
|
||||
return {
|
||||
success: true,
|
||||
message: GENERIC_MESSAGE,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
// server/api/auth/verify.post.js
|
||||
import { getRequestIP } from 'h3'
|
||||
import jwt from 'jsonwebtoken'
|
||||
import Member from '../../models/member.js'
|
||||
import { validateBody } from '../../utils/validateBody.js'
|
||||
import { verifyMagicLinkSchema } from '../../utils/schemas.js'
|
||||
import { setAuthCookie } from '../../utils/auth.js'
|
||||
import { rateLimit } from '../../utils/rateLimit.js'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const ip = getRequestIP(event, { xForwardedFor: true }) || 'unknown'
|
||||
if (!rateLimit(`auth:verify:ip:${ip}`, { max: 5, windowMs: 3600_000 })) {
|
||||
throw createError({ statusCode: 429, statusMessage: 'Too many verification attempts' })
|
||||
}
|
||||
|
||||
const { token } = await validateBody(event, verifyMagicLinkSchema)
|
||||
|
||||
const config = useRuntimeConfig(event)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue