Skip to content

Commit

Permalink
feat(ip)!: Accept Request or IncomingMessage directly (#2018)
Browse files Browse the repository at this point in the history
This changes the `findIP` API so it can accept a `Request` object directly. This is achieved by requiring the `headers` field on the first argument. I've combined the separate "request-like" and "headers" argument into one.

This is primarily being done so `@arcjet/ip` can be used with Next.js 15 which [removed the `ip` property from `NextRequest`](https://nextjs.org/docs/canary/app/building-your-application/upgrading/version-15#nextrequest-geolocation).

Ref #1904
  • Loading branch information
blaine-arcjet authored Oct 23, 2024
1 parent d886c76 commit 1704da8
Show file tree
Hide file tree
Showing 19 changed files with 363 additions and 173 deletions.
2 changes: 1 addition & 1 deletion arcjet-bun/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ export default function arcjet<
// workaround to the API design in Bun that requires access to the
// `Server` to lookup an IP.
ip: ipCache.get(request),
headers,
},
headers,
{ platform: platform(env) },
);
if (ip === "") {
Expand Down
2 changes: 1 addition & 1 deletion arcjet-deno/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,8 @@ export default function arcjet<
// workaround to the API design in Deno that requires access to the
// `ServeHandlerInfo` to lookup an IP.
ip: ipCache.get(request),
headers,
},
headers,
{ platform: platform(env) },
);
if (ip === "") {
Expand Down
9 changes: 8 additions & 1 deletion arcjet-nest/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,14 @@ function arcjet<
// We construct an ArcjetHeaders to normalize over Headers
const headers = new ArcjetHeaders(request.headers);

let ip = findIP(request, headers, { platform: platform(process.env) });
let ip = findIP(
{
ip: request.ip,
socket: request.socket,
headers,
},
{ platform: platform(process.env) },
);
if (ip === "") {
// If the `ip` is empty but we're in development mode, we default the IP
// so the request doesn't fail.
Expand Down
11 changes: 10 additions & 1 deletion arcjet-next/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,16 @@ export default function arcjet<
// We construct an ArcjetHeaders to normalize over Headers
const headers = new ArcjetHeaders(request.headers);

let ip = findIP(request, headers, { platform: platform(process.env) });
let ip = findIP(
{
ip: request.ip,
socket: request.socket,
info: request.info,
requestContext: request.requestContext,
headers,
},
{ platform: platform(process.env) },
);
if (ip === "") {
// If the `ip` is empty but we're in development mode, we default the IP
// so the request doesn't fail.
Expand Down
8 changes: 7 additions & 1 deletion arcjet-node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,13 @@ export default function arcjet<
// We construct an ArcjetHeaders to normalize over Headers
const headers = new ArcjetHeaders(request.headers);

let ip = findIP(request, headers, { platform: platform(process.env) });
let ip = findIP(
{
socket: request.socket,
headers,
},
{ platform: platform(process.env) },
);
if (ip === "") {
// If the `ip` is empty but we're in development mode, we default the IP
// so the request doesn't fail.
Expand Down
2 changes: 1 addition & 1 deletion arcjet-remix/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,8 @@ export default function arcjet<
{
// The `getLoadContext` API will attach the `ip` to the context
ip: context?.ip,
headers,
},
headers,
{ platform: platform(process.env) },
);
if (ip === "") {
Expand Down
2 changes: 1 addition & 1 deletion arcjet-sveltekit/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ export default function arcjet<
let ip = findIP(
{
ip: event.getClientAddress(),
headers,
},
headers,
{ platform: platform(process.env) },
);
if (ip === "") {
Expand Down
3 changes: 2 additions & 1 deletion examples/nextjs-14-clerk-rl/app/api/arcjet/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import arcjet, { ArcjetDecision, tokenBucket, shield } from "@arcjet/next";
import { NextRequest, NextResponse } from "next/server";
import { currentUser } from "@clerk/nextjs/server";
import ip from "@arcjet/ip";

// The root Arcjet client is created outside of the handler.
const aj = arcjet({
Expand Down Expand Up @@ -49,7 +50,7 @@ export async function GET(req: NextRequest) {
})
);

const fingerprint = req.ip!
const fingerprint = ip(req);

// Deduct 5 tokens from the token bucket
decision = await rl.protect(req, { fingerprint, requested: 5 });
Expand Down
22 changes: 22 additions & 0 deletions examples/nextjs-14-clerk-rl/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/nextjs-14-clerk-rl/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"@arcjet/ip": "file:../../ip",
"@arcjet/next": "file:../../arcjet-next",
"@clerk/nextjs": "^5.7.5",
"next": "^14.2.15",
Expand Down
3 changes: 2 additions & 1 deletion examples/nextjs-14-nextauth-4/app/api/arcjet/route.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import ip from "@arcjet/ip";
import arcjet, { ArcjetDecision, tokenBucket, detectBot, shield} from "@arcjet/next";
import { getServerSession } from "next-auth";
import GithubProvider from "next-auth/providers/github";
Expand Down Expand Up @@ -64,7 +65,7 @@ export async function GET(req: NextRequest, res: Response) {
decision = await rl.protect(req, { fingerprint, requested: 5 });
console.log("Arcjet logged in decision", decision)
} else {
const fingerprint = req.ip!;
const fingerprint = ip(req);

// Limit the amount of requests for anonymous users.
const rl = aj.withRule(
Expand Down
24 changes: 23 additions & 1 deletion examples/nextjs-14-nextauth-4/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/nextjs-14-nextauth-4/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"lint": "next lint"
},
"dependencies": {
"@arcjet/ip": "file:../../ip",
"@arcjet/next": "file:../../arcjet-next",
"next": "^14.2.15",
"next-auth": "^4.24.8",
Expand Down
22 changes: 22 additions & 0 deletions examples/nextjs-14-permit/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/nextjs-14-permit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"@arcjet/ip": "file:../../ip",
"@arcjet/next": "file:../../arcjet-next",
"@clerk/nextjs": "^5.7.5",
"next": "14.2.15",
Expand Down
3 changes: 2 additions & 1 deletion examples/nextjs-14-permit/src/app/api/stats/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { arcjet } from "@/lib/arcjet";
import { permit } from "@/lib/permit";
import { getLastFriday } from "@/lib/dateHelper";
import { getOrderCount, getToppings } from "@/data/stats";
import ip from "@arcjet/ip";

// Returns ad-hoc rules depending on whether the user is logged in, and if they
// are, whether they have permission to update stats.
Expand Down Expand Up @@ -41,7 +42,7 @@ export async function GET(req: NextRequest) {
// Get the user's ID if they are logged in, otherwise use
// their IP address as a fingerprint
const user = await currentUser();
const fingerprint: string = user ? user.id : req.ip!;
const fingerprint: string = user ? user.id : ip(req);

// Get the Arcjet client and request a decision
const aj = await getClient();
Expand Down
Loading

0 comments on commit 1704da8

Please sign in to comment.