fix: add rate limter error

This commit is contained in:
Bereket Engida
2024-09-24 02:41:01 +03:00
parent bc82bf3d30
commit 6c9782202f
10 changed files with 70 additions and 49 deletions

View File

@@ -74,7 +74,7 @@ export function OrganizationCard(props: { session: Session | null }) {
); );
return ( return (
<Card className="rounded-none md:rounded-sm !bg-none border-none"> <Card>
<CardHeader> <CardHeader>
<CardTitle>Organization</CardTitle> <CardTitle>Organization</CardTitle>
<div className="flex justify-between"> <div className="flex justify-between">

View File

@@ -1,27 +1,29 @@
import { auth } from "@/lib/auth" import { auth } from "@/lib/auth";
import { headers } from "next/headers" import { headers } from "next/headers";
import { redirect } from "next/navigation" import { redirect } from "next/navigation";
import UserCard from "./user-card" import UserCard from "./user-card";
import { OrganizationCard } from "./organization-card" import { OrganizationCard } from "./organization-card";
export default async function DashboardPage() { export default async function DashboardPage() {
const [session, activeSessions] = await Promise.all([ const [session, activeSessions] = await Promise.all([
auth.api.getSession({ auth.api.getSession({
headers: headers() headers: headers(),
}), }),
auth.api.listSessions({ auth.api.listSessions({
headers: headers() headers: headers(),
}) }),
]).catch(e => { ]).catch((e) => {
throw redirect("/sign-in") throw redirect("/sign-in");
}) });
return ( return (
<div className="w-full"> <div className="w-full">
<div className="flex gap-4 flex-col"> <div className="flex gap-4 flex-col">
<UserCard session={JSON.parse(JSON.stringify(session))} activeSessions={JSON.parse(JSON.stringify(activeSessions))} /> <UserCard
<OrganizationCard session={JSON.parse(JSON.stringify(session))} /> session={JSON.parse(JSON.stringify(session))}
</div> activeSessions={JSON.parse(JSON.stringify(activeSessions))}
</div> />
) <OrganizationCard session={JSON.parse(JSON.stringify(session))} />
} </div>
</div>
);
}

View File

@@ -89,7 +89,7 @@ export default function UserCard(props: {
const [isSignOut, setIsSignOut] = useState<boolean>(false); const [isSignOut, setIsSignOut] = useState<boolean>(false);
return ( return (
<Card className="rounded-none md:rounded-sm !bg-none border-none"> <Card>
<CardHeader> <CardHeader>
<CardTitle>User</CardTitle> <CardTitle>User</CardTitle>
</CardHeader> </CardHeader>
@@ -407,6 +407,7 @@ function ChangePassword() {
toast.error("Passwords do not match"); toast.error("Passwords do not match");
return; return;
} }
a;
if (newPassword.length < 8) { if (newPassword.length < 8) {
toast.error("Password must be at least 8 characters"); toast.error("Password must be at least 8 characters");
return; return;

View File

@@ -4,6 +4,7 @@ import {
passkeyClient, passkeyClient,
twoFactorClient, twoFactorClient,
} from "better-auth/client/plugins"; } from "better-auth/client/plugins";
import { toast } from "sonner";
export const client = createAuthClient({ export const client = createAuthClient({
plugins: [ plugins: [
@@ -14,7 +15,11 @@ export const client = createAuthClient({
passkeyClient(), passkeyClient(),
], ],
fetchOptions: { fetchOptions: {
credentials: "include", onError(e) {
if (e.error.status === 429) {
toast.error("Too many requests. Please try again later.");
}
},
}, },
}); });

View File

@@ -41,6 +41,8 @@ export const auth = betterAuth({
plugins: [ plugins: [
rateLimiter({ rateLimiter({
enabled: true, enabled: true,
max: 1000,
}), }),
organization({ organization({
async sendInvitationEmail(data) { async sendInvitationEmail(data) {

View File

@@ -51,7 +51,6 @@ export const getSession = <Option extends BetterAuthOptions>() =>
requireHeaders: true, requireHeaders: true,
}, },
async (ctx) => { async (ctx) => {
console.log("called");
try { try {
const sessionCookieToken = await ctx.getSignedCookie( const sessionCookieToken = await ctx.getSignedCookie(
ctx.context.authCookies.sessionToken.name, ctx.context.authCookies.sessionToken.name,
@@ -213,7 +212,6 @@ export const revokeSession = createAuthEndpoint(
}, },
async (ctx) => { async (ctx) => {
const id = ctx.body.id; const id = ctx.body.id;
console.log(id);
try { try {
await ctx.context.internalAdapter.deleteSession(id); await ctx.context.internalAdapter.deleteSession(id);
} catch (error) { } catch (error) {

View File

@@ -20,6 +20,7 @@ export const getClientConfig = <O extends ClientOptions>(options?: O) => {
.filter((pl) => pl !== undefined) || []), .filter((pl) => pl !== undefined) || []),
], ],
}); });
const plugins = options?.plugins || []; const plugins = options?.plugins || [];
let pluginsActions = {} as Record<string, any>; let pluginsActions = {} as Record<string, any>;
let pluginsAtoms = {} as Record<string, Atom<any>>; let pluginsAtoms = {} as Record<string, Atom<any>>;

View File

@@ -61,11 +61,17 @@ export const csrfPlugin = {
"CSRF route not found. Make sure the server is running and the base URL is correct and includes the path (e.g. http://localhost:3000/api/auth).", "CSRF route not found. Make sure the server is running and the base URL is correct and includes the path (e.g. http://localhost:3000/api/auth).",
); );
} }
if (error.status === 429) { if (error.status === 429) {
return new Response(null, { return new Response(
status: 429, JSON.stringify({
statusText: "Too Many Requests", message: "Too many requests. Please try again later.",
}); }),
{
status: 429,
statusText: "Too Many Requests",
},
);
} }
throw new BetterAuthError( throw new BetterAuthError(
"Failed to fetch CSRF token: " + error.message, "Failed to fetch CSRF token: " + error.message,

View File

@@ -207,22 +207,27 @@ export const rateLimiter = (options: RateLimitOptions) => {
rateLimit.lastRequest >= windowStart && rateLimit.lastRequest >= windowStart &&
rateLimit.count >= opts.max rateLimit.count >= opts.max
) { ) {
return new Response(null, { return new Response(
status: 429, JSON.stringify({
statusText: "Too Many Requests", message: "Too many requests. Please try again later.",
headers: { }),
"X-RateLimit-Window": opts.window.toString(), {
"X-RateLimit-Max": opts.max.toString(), status: 429,
"X-RateLimit-Remaining": ( statusText: "Too Many Requests",
opts.max - rateLimit.count headers: {
).toString(), "X-RateLimit-Window": opts.window.toString(),
"X-RateLimit-Reset": ( "X-RateLimit-Max": opts.max.toString(),
rateLimit.lastRequest + "X-RateLimit-Remaining": (
opts.window * 1000 - opts.max - rateLimit.count
now ).toString(),
).toString(), "X-RateLimit-Reset": (
rateLimit.lastRequest +
opts.window * 1000 -
now
).toString(),
},
}, },
}); );
} }
if (rateLimit.lastRequest < windowStart) { if (rateLimit.lastRequest < windowStart) {

View File

@@ -12,6 +12,7 @@
[x] fix the issue with the client triggers not working fot 2 consecutive calls [x] fix the issue with the client triggers not working fot 2 consecutive calls
[ ] add a way to specify on the client to use the base path as the whole path [ ] add a way to specify on the client to use the base path as the whole path
[x] implement magic links [x] implement magic links
[ ] rate limiter error handling
## Docs ## Docs