@@ -18,6 +18,18 @@ const RPC_BASE_URL = "https://rpc.inlang.com";
1818const RPC_PATH = "/_rpc" ;
1919
2020async function proxyRpcRequest ( request : Request ) {
21+ const corsHeaders = buildCorsHeaders ( request ) ;
22+ if ( corsHeaders === null ) {
23+ return new Response ( "CORS origin denied" , { status : 403 } ) ;
24+ }
25+
26+ if ( request . method === "OPTIONS" ) {
27+ return new Response ( null , {
28+ status : 204 ,
29+ headers : corsHeaders ,
30+ } ) ;
31+ }
32+
2133 const upstreamUrl = `${ RPC_BASE_URL } ${ RPC_PATH } ` ;
2234 const headers = new Headers ( request . headers ) ;
2335
@@ -34,9 +46,74 @@ async function proxyRpcRequest(request: Request) {
3446 redirect : "manual" ,
3547 } ) ;
3648
49+ const responseHeaders = new Headers ( response . headers ) ;
50+ for ( const [ key , value ] of corsHeaders . entries ( ) ) {
51+ if ( key . toLowerCase ( ) === "vary" ) {
52+ mergeVaryHeader ( responseHeaders , value ) ;
53+ continue ;
54+ }
55+ responseHeaders . set ( key , value ) ;
56+ }
57+
3758 return new Response ( response . body , {
3859 status : response . status ,
3960 statusText : response . statusText ,
40- headers : response . headers ,
61+ headers : responseHeaders ,
4162 } ) ;
4263}
64+
65+ function buildCorsHeaders ( request : Request ) {
66+ const headers = new Headers ( ) ;
67+ const origin = request . headers . get ( "origin" ) ;
68+ if ( ! origin ) {
69+ return headers ;
70+ }
71+
72+ if ( ! isAllowedOrigin ( origin ) ) {
73+ return null ;
74+ }
75+
76+ headers . set ( "access-control-allow-origin" , origin ) ;
77+ headers . set ( "access-control-allow-credentials" , "true" ) ;
78+ headers . set ( "access-control-allow-methods" , "POST,OPTIONS" ) ;
79+ headers . set (
80+ "access-control-allow-headers" ,
81+ request . headers . get ( "access-control-request-headers" ) ?? "content-type"
82+ ) ;
83+ headers . set ( "vary" , "origin" ) ;
84+ return headers ;
85+ }
86+
87+ function mergeVaryHeader ( headers : Headers , value : string ) {
88+ const existing = headers . get ( "vary" ) ;
89+ if ( ! existing ) {
90+ headers . set ( "vary" , value ) ;
91+ return ;
92+ }
93+
94+ const existingValues = existing
95+ . split ( "," )
96+ . map ( ( entry ) => entry . trim ( ) . toLowerCase ( ) )
97+ . filter ( Boolean ) ;
98+ const additions = value
99+ . split ( "," )
100+ . map ( ( entry ) => entry . trim ( ) . toLowerCase ( ) )
101+ . filter ( Boolean ) ;
102+ const merged = Array . from ( new Set ( [ ...existingValues , ...additions ] ) ) ;
103+ headers . set ( "vary" , merged . join ( ", " ) ) ;
104+ }
105+
106+ function isAllowedOrigin ( origin : string ) {
107+ let hostname = "" ;
108+ try {
109+ hostname = new URL ( origin ) . hostname ;
110+ } catch {
111+ return false ;
112+ }
113+
114+ if ( hostname === "localhost" ) {
115+ return true ;
116+ }
117+
118+ return hostname === "inlang.com" || hostname . endsWith ( ".inlang.com" ) ;
119+ }
0 commit comments