From f75d02c33a725ad0389d5050707d2ca19ccbac8b Mon Sep 17 00:00:00 2001 From: notmd Date: Sun, 29 Jan 2023 22:59:45 +0700 Subject: [PATCH] use `signIn` callback instead middleware --- website/src/middleware.ts | 37 +------------------ website/src/pages/api/auth/[...nextauth].ts | 31 +++++++++++++++- website/src/pages/api/auth/invalid-captcha.ts | 7 ---- 3 files changed, 30 insertions(+), 45 deletions(-) delete mode 100644 website/src/pages/api/auth/invalid-captcha.ts diff --git a/website/src/middleware.ts b/website/src/middleware.ts index 4c85d3ac..21eeaaa7 100644 --- a/website/src/middleware.ts +++ b/website/src/middleware.ts @@ -1,7 +1,5 @@ -import { NextResponse } from "next/server"; -import { NextRequestWithAuth, withAuth } from "next-auth/middleware"; +export { default } from "next-auth/middleware"; -import { checkCaptcha } from "./lib/captcha"; /** * Guards these pages and redirects them to the sign in page. */ @@ -16,38 +14,5 @@ export const config = { "/tasks/:path*", "/leaderboard", "/messages/:path*", - "/api/auth/signin/email", ], }; - -const middleware = async (req: NextRequestWithAuth) => { - if (req.method === "POST" && req.nextUrl.pathname === "/api/auth/signin/email") { - const data = await getBody(req); - const res = await checkCaptcha(data?.captcha, req.ip); - - if (res.success) { - return NextResponse.next(); - } - - const url = req.nextUrl.clone(); - url.pathname = "/api/auth/invalid-captcha"; - - return NextResponse.redirect(url); - } - - return withAuth(req); -}; - -async function getBody(req: Request): Promise | undefined> { - if (!("body" in req) || !req.body || req.method !== "POST") return; - - const contentType = req.headers.get("content-type"); - if (contentType?.includes("application/json")) { - return await req.json(); - } else if (contentType?.includes("application/x-www-form-urlencoded")) { - const params = new URLSearchParams(await req.text()); - return Object.fromEntries(params); - } -} - -export default middleware; diff --git a/website/src/pages/api/auth/[...nextauth].ts b/website/src/pages/api/auth/[...nextauth].ts index 3d3dbaa4..065d67f4 100644 --- a/website/src/pages/api/auth/[...nextauth].ts +++ b/website/src/pages/api/auth/[...nextauth].ts @@ -1,11 +1,13 @@ import { PrismaAdapter } from "@next-auth/prisma-adapter"; import { boolean } from "boolean"; +import { NextApiRequest, NextApiResponse } from "next"; import type { AuthOptions } from "next-auth"; import NextAuth from "next-auth"; import { Provider } from "next-auth/providers"; import CredentialsProvider from "next-auth/providers/credentials"; import DiscordProvider from "next-auth/providers/discord"; import EmailProvider from "next-auth/providers/email"; +import { checkCaptcha } from "src/lib/captcha"; import prisma from "src/lib/prismadb"; import { generateUsername } from "unique-username-generator"; @@ -74,7 +76,7 @@ const adminUserMap = process.env.ADMIN_USERS.split(",").reduce((result, entry) = return result; }, new Map()); -export const authOptions: AuthOptions = { +const authOptions: AuthOptions = { // Ensure we can store user data in a database. adapter: PrismaAdapter(prisma), providers, @@ -153,4 +155,29 @@ export const authOptions: AuthOptions = { }, }; -export default NextAuth(authOptions); +export default function auth(req: NextApiRequest, res: NextApiResponse) { + return NextAuth(req, res, { + ...authOptions, + callbacks: { + ...authOptions.callbacks, + async signIn({ account }) { + if (account.provider !== "email") { + return true; + } + + const captcha = req.body.captcha; + // https://stackoverflow.com/questions/66111742/get-the-client-ip-on-nextjs-and-use-ssr + const forwarded = req.headers["x-forwarded-for"]; + const ip = typeof forwarded === "string" ? forwarded.split(/, /)[0] : req.socket.remoteAddress; + + const res = await checkCaptcha(captcha, ip); + + if (res.success) { + return true; + } + + return "/auth/signin?error=InvalidCaptcha"; + }, + }, + }); +} diff --git a/website/src/pages/api/auth/invalid-captcha.ts b/website/src/pages/api/auth/invalid-captcha.ts deleted file mode 100644 index 86fe7eab..00000000 --- a/website/src/pages/api/auth/invalid-captcha.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { NextApiRequest, NextApiResponse } from "next"; - -export default function handler(_: NextApiRequest, res: NextApiResponse) { - return res.status(200).json({ - url: "/auth/signin?error=InvalidCaptcha", - }); -}