@@ -41,11 +41,7 @@ const typeDefs = readFileSync(join(__dirname, './config/schema.graphql'), 'utf-8
4141
4242const KADENA_GRAPHQL_API_PORT = getRequiredEnvString ( 'KADENA_GRAPHQL_API_PORT' ) ;
4343
44- const ALLOWED_ORIGINS = [
45- getRequiredEnvString ( 'API_GATEWAY_URL' ) ,
46- getRequiredEnvString ( 'API_KADENA_URL' ) ,
47- `http://localhost:${ KADENA_GRAPHQL_API_PORT } ` ,
48- ] ;
44+ const ALLOWED_ORIGINS = [ process . env . API_GATEWAY_URL ?? '' , process . env . API_KADENA_URL ?? '' ] ;
4945
5046const validatePaginationParamsPlugin : ApolloServerPlugin = {
5147 requestDidStart : async ( ) => ( {
@@ -127,13 +123,16 @@ const ipFilterMiddleware = (req: Request, res: Response, next: NextFunction) =>
127123const isAllowedOrigin = ( origin : string ) : boolean => {
128124 try {
129125 const originUrl = new URL ( origin ) ;
126+ if ( originUrl . hostname === 'localhost' ) return true ;
127+
130128 return ALLOWED_ORIGINS . some ( allowed => {
131129 const allowedUrl = new URL ( allowed ) ;
132130 // Check if it's an exact match
133131 if ( originUrl . origin === allowedUrl . origin ) return true ;
134132 // Check if it's a subdomain (only for kadena.io)
135- if ( allowedUrl . hostname === 'kadena.io' && originUrl . hostname . endsWith ( '.kadena.io' ) )
133+ if ( allowedUrl . hostname === 'kadena.io' && originUrl . hostname . endsWith ( '.kadena.io' ) ) {
136134 return true ;
135+ }
137136 return false ;
138137 } ) ;
139138 } catch {
@@ -233,15 +232,6 @@ export async function useKadenaGraphqlServer() {
233232 const wsServer = new WebSocketServer ( {
234233 server : httpServer ,
235234 path : '/graphql' ,
236- verifyClient : ( { origin } , callback ) => {
237- if ( ! origin || origin === 'null' ) {
238- return callback ( false , 400 , 'No origin' ) ;
239- }
240- if ( isAllowedOrigin ( origin ) ) {
241- return callback ( true ) ;
242- }
243- return callback ( false , 403 , 'Forbidden' ) ;
244- } ,
245235 } ) ;
246236
247237 const serverCleanup = useServer (
@@ -282,14 +272,42 @@ export async function useKadenaGraphqlServer() {
282272 }
283273 } ,
284274 methods : [ 'POST' , 'OPTIONS' ] ,
285- allowedHeaders : [ 'Content-Type' , 'Authorization' ] ,
275+ allowedHeaders : [
276+ 'Content-Type' ,
277+ 'Authorization' ,
278+ 'Accept' ,
279+ 'Origin' ,
280+ 'X-Requested-With' ,
281+ 'Cache-Control' ,
282+ 'Pragma' ,
283+ ] ,
284+ exposedHeaders : [ 'Access-Control-Allow-Origin' ] ,
286285 credentials : true ,
286+ maxAge : 86400 , // 24 hours
287287 } ) ,
288288 expressMiddleware ( server , {
289289 context : createGraphqlContext ,
290290 } ) ,
291291 ) ;
292292
293+ // Handle OPTIONS requests explicitly
294+ app . options ( '*' , ( req : Request , res : Response ) => {
295+ const origin = req . headers . origin ;
296+ if ( origin && isAllowedOrigin ( origin ) ) {
297+ res . setHeader ( 'Access-Control-Allow-Origin' , origin ) ;
298+ res . setHeader ( 'Access-Control-Allow-Credentials' , 'true' ) ;
299+ res . setHeader ( 'Access-Control-Allow-Methods' , 'POST, OPTIONS' ) ;
300+ res . setHeader (
301+ 'Access-Control-Allow-Headers' ,
302+ 'Content-Type, Authorization, Accept, Origin, X-Requested-With, Cache-Control, Pragma' ,
303+ ) ;
304+ res . setHeader ( 'Access-Control-Max-Age' , '86400' ) ;
305+ res . status ( 204 ) . end ( ) ;
306+ } else {
307+ res . status ( 403 ) . end ( ) ;
308+ }
309+ } ) ;
310+
293311 app . post ( '/new-block' , ipFilterMiddleware , async ( req , res ) => {
294312 const payload = await dispatchInfoSchema . safeParseAsync ( req . body ) ;
295313 if ( ! payload . success ) {
0 commit comments