11import { NextRequest , NextResponse } from "next/server" ;
2+ import { z } from "zod" ;
23import {
34 createBrowserSessionToken ,
45 createCallerToken ,
@@ -13,6 +14,11 @@ import { CallerSchema } from "./schema";
1314
1415export async function middleware ( request : NextRequest ) {
1516 const appInstallToken = request . nextUrl . searchParams . get ( "token" ) ;
17+ const result = extractAndValidateHeaders ( request . headers ) ;
18+ console . log ( result ) ;
19+
20+ // const headers = extractAndValidateHeaders(request.headers);
21+ // console.log(headers);
1622
1723 let newGuestToken : string | undefined ;
1824 let newBrowserSessionToken : string | undefined ;
@@ -95,3 +101,60 @@ function uuidv4() {
95101 return v . toString ( 16 ) ;
96102 } ) ;
97103}
104+ // Define a schema for IP location data
105+ const IPLocationSchema = z . object ( {
106+ latitude : z . number ( ) . optional ( ) ,
107+ longitude : z . number ( ) . optional ( ) ,
108+ } ) ;
109+
110+ // Define a schema for the headers we want to extract and validate
111+ const HeadersSchema = z . object ( {
112+ continent : z . enum ( [ "AF" , "AN" , "AS" , "EU" , "NA" , "OC" , "SA" ] ) . optional ( ) ,
113+ country : z . string ( ) . length ( 2 ) . optional ( ) ,
114+ region : z . string ( ) . max ( 3 ) . optional ( ) ,
115+ city : z . string ( ) . optional ( ) ,
116+ timezone : z . string ( ) . optional ( ) ,
117+ signature : z . string ( ) . optional ( ) ,
118+ gps : IPLocationSchema . optional ( ) ,
119+ } ) ;
120+
121+ // Type definition for the headers context
122+ type HeadersContext = {
123+ continent ?: string ;
124+ country ?: string ;
125+ region ?: string ;
126+ city ?: string ;
127+ timezone ?: string ;
128+ signature ?: string ;
129+ gps ?: {
130+ latitude : number ;
131+ longitude : number ;
132+ } ;
133+ } ;
134+
135+ // Function to extract and validate headers from a request with a .get() method
136+ function extractAndValidateHeaders ( headers : NextRequest [ "headers" ] ) {
137+ // Extract headers and convert them into a structured object
138+ const headersToValidate : HeadersContext = {
139+ continent : headers . get ( "x-vercel-ip-continent" ) || undefined ,
140+ country : headers . get ( "x-vercel-ip-country" ) || undefined ,
141+ region : headers . get ( "x-vercel-ip-country-region" ) || undefined ,
142+ city : headers . get ( "x-vercel-ip-city" ) || undefined ,
143+ timezone : headers . get ( "x-vercel-ip-timezone" ) || undefined ,
144+ signature : headers . get ( "x-vercel-signature" ) || undefined ,
145+ gps : {
146+ latitude : parseFloat ( headers . get ( "x-vercel-ip-latitude" ) || "0" ) ,
147+ longitude : parseFloat ( headers . get ( "x-vercel-ip-longitude" ) || "0" ) ,
148+ } ,
149+ } ;
150+
151+ // Validate the structured object using the Zod schema
152+ const result = HeadersSchema . safeParse ( headersToValidate ) ;
153+
154+ if ( result . success ) {
155+ return result . data ;
156+ } else {
157+ console . error ( "Validation failed:" , result . error ) ;
158+ return undefined ;
159+ }
160+ }
0 commit comments