Commented and refactored.
This commit is contained in:
parent
0074a4c0b7
commit
1257ea8881
162
index.js
162
index.js
|
@ -15,158 +15,140 @@ The main goal is to facilitate cross-origin requests while enforcing specific se
|
|||
|
||||
// Configuration: Whitelist and Blacklist (not used in this version)
|
||||
// whitelist = [ "^http.?://www.zibri.org$", "zibri.org$", "test\\..*" ]; // regexp for whitelisted urls
|
||||
blacklist = [ ]; // regexp for blacklisted urls
|
||||
whitelist = [ ".*" ]; // regexp for whitelisted origins
|
||||
const blacklistUrls = []; // regexp for blacklisted urls
|
||||
const whitelistOrigins = [ ".*" ]; // regexp for whitelisted origins
|
||||
|
||||
// Function to check if a given URI or origin is listed in the whitelist or blacklist
|
||||
function isListed(uri, listing) {
|
||||
var ret = false;
|
||||
if (typeof uri == "string") {
|
||||
// Iterate through each pattern in the listing to match against the URI
|
||||
listing.forEach((m) => {
|
||||
if (uri.match(m) != null) {
|
||||
ret = true; // Set to true if URI matches any pattern in the listing
|
||||
function isListedInWhitelist(uri, listing) {
|
||||
let isListed = false;
|
||||
if (typeof uri === "string") {
|
||||
listing.forEach((pattern) => {
|
||||
if (uri.match(pattern) !== null) {
|
||||
isListed = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// If URI is null (e.g., when Origin header is missing), decide based on the implementation
|
||||
ret = true; // In this case, true accepts null origins, false would reject them
|
||||
// When URI is null (e.g., when Origin header is missing), decide based on the implementation
|
||||
isListed = true; // true accepts null origins, false would reject them
|
||||
}
|
||||
return ret;
|
||||
return isListed;
|
||||
}
|
||||
|
||||
// Event listener for incoming fetch requests
|
||||
addEventListener("fetch", async event => {
|
||||
event.respondWith((async function() {
|
||||
// Determine if the incoming request is an OPTIONS preflight request
|
||||
isOPTIONS = (event.request.method == "OPTIONS");
|
||||
const isPreflightRequest = (event.request.method === "OPTIONS");
|
||||
|
||||
// Extract the origin URL from the incoming request
|
||||
var origin_url = new URL(event.request.url);
|
||||
const originUrl = new URL(event.request.url);
|
||||
|
||||
// Function to modify headers to enable CORS
|
||||
function fix(myHeaders) {
|
||||
myHeaders.set("Access-Control-Allow-Origin", event.request.headers.get("Origin"));
|
||||
if (isOPTIONS) {
|
||||
myHeaders.set("Access-Control-Allow-Methods", event.request.headers.get("access-control-request-method"));
|
||||
acrh = event.request.headers.get("access-control-request-headers");
|
||||
function setupCORSHeaders(headers) {
|
||||
headers.set("Access-Control-Allow-Origin", event.request.headers.get("Origin"));
|
||||
if (isPreflightRequest) {
|
||||
headers.set("Access-Control-Allow-Methods", event.request.headers.get("access-control-request-method"));
|
||||
const requestedHeaders = event.request.headers.get("access-control-request-headers");
|
||||
|
||||
if (acrh) {
|
||||
myHeaders.set("Access-Control-Allow-Headers", acrh);
|
||||
if (requestedHeaders) {
|
||||
headers.set("Access-Control-Allow-Headers", requestedHeaders);
|
||||
}
|
||||
|
||||
myHeaders.delete("X-Content-Type-Options"); // Remove X-Content-Type-Options header
|
||||
headers.delete("X-Content-Type-Options"); // Remove X-Content-Type-Options header
|
||||
}
|
||||
return myHeaders;
|
||||
return headers;
|
||||
}
|
||||
|
||||
// Extract the fetch URL from the query parameter of the origin URL
|
||||
var fetch_url = decodeURIComponent(decodeURIComponent(origin_url.search.substr(1)));
|
||||
const targetUrl = decodeURIComponent(decodeURIComponent(originUrl.search.substr(1)));
|
||||
|
||||
// Extract the Origin and CF-Connecting-IP headers from the incoming request
|
||||
var orig = event.request.headers.get("Origin");
|
||||
var remIp = event.request.headers.get("CF-Connecting-IP");
|
||||
const originHeader = event.request.headers.get("Origin");
|
||||
const connectingIp = event.request.headers.get("CF-Connecting-IP");
|
||||
|
||||
// Check if the fetch URL is not blacklisted and the origin is whitelisted
|
||||
if ((!isListed(fetch_url, blacklist)) && (isListed(orig, whitelist))) {
|
||||
// Extract additional custom headers (x-cors-headers) from the incoming request
|
||||
xheaders = event.request.headers.get("x-cors-headers");
|
||||
if ((!isListedInWhitelist(targetUrl, blacklistUrls)) && (isListedInWhitelist(originHeader, whitelistOrigins))) {
|
||||
let customHeaders = event.request.headers.get("x-cors-headers");
|
||||
|
||||
// Parse the x-cors-headers if present
|
||||
if (xheaders != null) {
|
||||
if (customHeaders !== null) {
|
||||
try {
|
||||
xheaders = JSON.parse(xheaders);
|
||||
customHeaders = JSON.parse(customHeaders);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// Handle different scenarios based on the query parameters of the origin URL
|
||||
if (origin_url.search.startsWith("?")) {
|
||||
// Construct new headers excluding certain headers from the original request
|
||||
recv_headers = {};
|
||||
for (var pair of event.request.headers.entries()) {
|
||||
if (originUrl.search.startsWith("?")) {
|
||||
const filteredHeaders = {};
|
||||
for (const [key, value] of event.request.headers.entries()) {
|
||||
if (
|
||||
(pair[0].match("^origin") == null) &&
|
||||
(pair[0].match("eferer") == null) &&
|
||||
(pair[0].match("^cf-") == null) &&
|
||||
(pair[0].match("^x-forw") == null) &&
|
||||
(pair[0].match("^x-cors-headers") == null)
|
||||
(key.match("^origin") === null) &&
|
||||
(key.match("eferer") === null) &&
|
||||
(key.match("^cf-") === null) &&
|
||||
(key.match("^x-forw") === null) &&
|
||||
(key.match("^x-cors-headers") === null)
|
||||
) {
|
||||
recv_headers[pair[0]] = pair[1];
|
||||
filteredHeaders[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Append x-cors-headers to the received headers if present
|
||||
if (xheaders != null) {
|
||||
Object.entries(xheaders).forEach((c) => (recv_headers[c[0]] = c[1]));
|
||||
if (customHeaders !== null) {
|
||||
Object.entries(customHeaders).forEach((entry) => (filteredHeaders[entry[0]] = entry[1]));
|
||||
}
|
||||
|
||||
// Create a new request based on the modified headers
|
||||
newreq = new Request(event.request, {
|
||||
const newRequest = new Request(event.request, {
|
||||
redirect: "follow",
|
||||
headers: recv_headers
|
||||
headers: filteredHeaders
|
||||
});
|
||||
|
||||
// Perform the fetch operation to the specified fetch_url
|
||||
var response = await fetch(fetch_url, newreq);
|
||||
var myHeaders = new Headers(response.headers);
|
||||
cors_headers = [];
|
||||
allh = {};
|
||||
for (var pair of response.headers.entries()) {
|
||||
cors_headers.push(pair[0]);
|
||||
allh[pair[0]] = pair[1];
|
||||
const response = await fetch(targetUrl, newRequest);
|
||||
const responseHeaders = new Headers(response.headers);
|
||||
const exposedHeaders = [];
|
||||
const allResponseHeaders = {};
|
||||
for (const [key, value] of response.headers.entries()) {
|
||||
exposedHeaders.push(key);
|
||||
allResponseHeaders[key] = value;
|
||||
}
|
||||
cors_headers.push("cors-received-headers");
|
||||
myHeaders = fix(myHeaders);
|
||||
exposedHeaders.push("cors-received-headers");
|
||||
responseHeaders = setupCORSHeaders(responseHeaders);
|
||||
|
||||
// Manipulate response headers to include CORS-related headers
|
||||
myHeaders.set("Access-Control-Expose-Headers", cors_headers.join(","));
|
||||
myHeaders.set("cors-received-headers", JSON.stringify(allh));
|
||||
responseHeaders.set("Access-Control-Expose-Headers", exposedHeaders.join(","));
|
||||
responseHeaders.set("cors-received-headers", JSON.stringify(allResponseHeaders));
|
||||
|
||||
// Prepare the final response with appropriate status and body
|
||||
var init = {
|
||||
headers: myHeaders,
|
||||
status: isOPTIONS ? 200 : response.status,
|
||||
statusText: isOPTIONS ? "OK" : response.statusText
|
||||
const responseBody = isPreflightRequest ? null : await response.arrayBuffer();
|
||||
|
||||
const responseInit = {
|
||||
headers: responseHeaders,
|
||||
status: isPreflightRequest ? 200 : response.status,
|
||||
statusText: isPreflightRequest ? "OK" : response.statusText
|
||||
};
|
||||
return new Response(body, init);
|
||||
return new Response(responseBody, responseInit);
|
||||
|
||||
} else {
|
||||
// Generate a response when no query parameter is specified in the origin URL
|
||||
var myHeaders = new Headers();
|
||||
myHeaders = fix(myHeaders);
|
||||
const responseHeaders = new Headers();
|
||||
responseHeaders = setupCORSHeaders(responseHeaders);
|
||||
|
||||
// Extract country and datacenter information from Cloudflare if available
|
||||
if (typeof event.request.cf != "undefined") {
|
||||
var country = event.request.cf.country || false;
|
||||
var colo = event.request.cf.colo || false;
|
||||
} else {
|
||||
var country = false;
|
||||
var colo = false;
|
||||
let country = false;
|
||||
let colo = false;
|
||||
if (typeof event.request.cf !== "undefined") {
|
||||
country = event.request.cf.country || false;
|
||||
colo = event.request.cf.colo || false;
|
||||
}
|
||||
|
||||
// Return a response with CORS-related information
|
||||
return new Response(
|
||||
"CLOUDFLARE-CORS-ANYWHERE\n\n" +
|
||||
"Source:\nhttps://github.com/Zibri/cloudflare-cors-anywhere\n\n" +
|
||||
"Usage:\n" +
|
||||
origin_url.origin + "/?uri\n\n" +
|
||||
originUrl.origin + "/?uri\n\n" +
|
||||
"Donate:\nhttps://paypal.me/Zibri/5\n\n" +
|
||||
"Limits: 100,000 requests/day\n" +
|
||||
" 1,000 requests/10 minutes\n\n" +
|
||||
(orig != null ? "Origin: " + orig + "\n" : "") +
|
||||
"Ip: " + remIp + "\n" +
|
||||
(originHeader !== null ? "Origin: " + originHeader + "\n" : "") +
|
||||
"IP: " + connectingIp + "\n" +
|
||||
(country ? "Country: " + country + "\n" : "") +
|
||||
(colo ? "Datacenter: " + colo + "\n" : "") +
|
||||
"\n" +
|
||||
(xheaders != null ? "\nx-cors-headers: " + JSON.stringify(xheaders) : ""),
|
||||
(customHeaders !== null ? "\nx-cors-headers: " + JSON.stringify(customHeaders) : ""),
|
||||
{
|
||||
status: 200,
|
||||
headers: myHeaders
|
||||
headers: responseHeaders
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Return a forbidden response for requests that are not allowed
|
||||
return new Response(
|
||||
"Create your own CORS proxy</br>\n" +
|
||||
"<a href='https://github.com/Zibri/cloudflare-cors-anywhere'>https://github.com/Zibri/cloudflare-cors-anywhere</a></br>\n" +
|
||||
|
|
Loading…
Reference in New Issue