Skip to content

Commit

Permalink
WIP - ratelimiting
Browse files Browse the repository at this point in the history
  • Loading branch information
muliswilliam committed Sep 24, 2023
1 parent ae0dc35 commit 1b0faa6
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 22 deletions.
28 changes: 7 additions & 21 deletions src/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,10 @@
import { authMiddleware } from '@clerk/nextjs'
import { publicRoutes } from './middleware/public-routes'
import { stackMiddlewares } from './middleware/stack-middlewares'
import { withAuth } from './middleware/with-clerk-auth'
import { withRateLimit } from './middleware/with-rate-limit'

// This example protects all routes including api/trpc routes
// Please edit this to allow other routes to be public as needed.
// See https://clerk.com/docs/references/nextjs/auth-middleware for more information about configuring your middleware
export default authMiddleware({
// routes that do not require authentication
publicRoutes: [
'/',
'/messages/(.*)',
'/chats/(.*)',
'/api/chat/livekit_token',
'/api/files/upload',
'/api/msg/new',
'/api/msg/destroy',
'/api/msg/message-viewed',
'/api/ip'
]
})
export default stackMiddlewares([withRateLimit, withAuth])

export const config = {
// matcher: ['/((?!_next/image|_next/static|favicon.ico|logo.png).*)']
matcher: ["/((?!.*\\..*|_next).*)","/","/(api|trpc)(.*)"],
}
matcher: ["/((?!.*\\..*|_next).*)","/","/(api|trpc)(.*)"]
}
12 changes: 12 additions & 0 deletions src/middleware/public-routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const publicRoutes = [
'/',
'/messages/(.*)',
'/chats/(.*)',
'/api/chat/livekit_token',
'/api/files/upload',
'/api/msg/new',
'/api/msg/destroy',
'/api/msg/message-viewed',
'/api/msg/:messageId',
'/api/ip'
]
14 changes: 14 additions & 0 deletions src/middleware/stack-middlewares.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

import { NextMiddleware, NextResponse } from "next/server";
import { MiddlewareFactory } from "../shared/types";
export function stackMiddlewares(
functions: MiddlewareFactory[] = [],
index = 0
): NextMiddleware {
const current = functions[index];
if (current) {
const next = stackMiddlewares(functions, index + 1);
return current(next);
}
return () => NextResponse.next();
}
17 changes: 17 additions & 0 deletions src/middleware/with-clerk-auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { NextFetchEvent, NextMiddleware, NextRequest } from 'next/server'
import { authMiddleware } from '@clerk/nextjs'
import { publicRoutes } from './public-routes'
import { MiddlewareFactory } from '../shared/types'

// This example protects all routes including api/trpc routes
// Please edit this to allow other routes to be public as needed.
// See https://clerk.com/docs/references/nextjs/auth-middleware for more information about configuring your middleware

export const withAuth: MiddlewareFactory = (next: NextMiddleware) => {
return async (request: NextRequest, _next: NextFetchEvent) => {
return await authMiddleware({
// routes that do not require authentication
publicRoutes: publicRoutes
})(next.)
}
}
33 changes: 33 additions & 0 deletions src/middleware/with-rate-limit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { NextFetchEvent, NextMiddleware, NextRequest, NextResponse } from 'next/server'
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'
import { publicRoutes } from './public-routes'
import { MiddlewareFactory } from '../shared/types'

const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL as string,
token: process.env.UPSTASH_REDIS_REST_TOKEN as string
})

const ratelimit = new Ratelimit({
redis: redis,
// 100 messages per day
limiter: Ratelimit.slidingWindow(parseInt(process.env.FREE_TIER_MESSAGES_LIMIT || '1'), '1 d')
})

export const withRateLimit: MiddlewareFactory = (next: NextMiddleware) => {
// return async (request: NextRequest, _next: NextFetchEvent) => {
// const ip =
// request.ip || request.headers.get('x-vercel-forwarded-for') || '127.0.0.1'
// const { success } = await ratelimit.limit(ip)
// console.log(`Rate limit ${ip} ${success ? 'passed' : 'blocked'}`)
// return success
// ? next(request, _next)
// : NextResponse.redirect(new URL('/blocked', request.url))
// }
return async (request: NextRequest, _next: NextFetchEvent) => {
console.log("Log some data here", request.nextUrl.pathname);
return next(request, _next);
};
}

9 changes: 9 additions & 0 deletions src/pages/blocked.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react'

export default function BlockedPage() {
return (
<div>
<h1>Blocked</h1>
</div>
)
}
5 changes: 4 additions & 1 deletion src/shared/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { NextMiddleware } from "next/server";
import { LocalAudioTrack, LocalVideoTrack } from 'livekit-client';
import { Prisma } from '@prisma/client';
export interface EncryptionDetails {
Expand Down Expand Up @@ -63,4 +64,6 @@ export interface IpAddressInfo {
export type EventWithIpAddressInfo = Prisma.EventGetPayload<{
event: true
include: { ipAddressInfo: true }
}>
}>

export type MiddlewareFactory = (middleware: NextMiddleware) => NextMiddleware;

0 comments on commit 1b0faa6

Please sign in to comment.