Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions public/sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ const CAPTCHA_DOMAINS = [
"newassets.hcaptcha.com",
"challenges.cloudflare.com",
"cloudflare.com/cdn-cgi/challenge",
"turnstile.cloudflare.com"
"turnstile.cloudflare.com",
"cdn-cgi",
"cf-assets"
];

// Helper function to check if URL is CAPTCHA-related
Expand All @@ -37,11 +39,18 @@ function enhanceCaptchaRequest(request) {
headers.set("Accept", "*/*");
}

// Preserve credentials for CAPTCHA cookies
// Ensure critical headers are preserved
if (request.referrer && !headers.has("Referer")) {
headers.set("Referer", request.referrer);
}

// Preserve credentials for CAPTCHA cookies - don't change mode as it can break cookies
return new Request(request, {
headers: headers,
credentials: "include",
mode: request.mode === "navigate" ? "same-origin" : request.mode
mode: request.mode,
cache: request.cache,
redirect: request.redirect
});
}

Expand All @@ -57,11 +66,24 @@ self.addEventListener("fetch", function (event) {
let request = event.request;
if (isCaptcha) {
request = enhanceCaptchaRequest(event.request);
console.debug("[CAPTCHA] Enhanced request for:", url);
}

if (url.startsWith(location.origin + __uv$config.prefix)) {
// For proxied CAPTCHA requests through UV, create a modified event
if (isCaptcha) {
const modifiedEvent = Object.create(event);
modifiedEvent.request = request;
return await uv.fetch(modifiedEvent);
}
return await uv.fetch(event);
} else if (sj.route(event)) {
// For proxied CAPTCHA requests through Scramjet, create a modified event
if (isCaptcha) {
const modifiedEvent = Object.create(event);
modifiedEvent.request = request;
return await sj.fetch(modifiedEvent);
}
return await sj.fetch(event);
} else {
return await fetch(request);
Expand Down
73 changes: 54 additions & 19 deletions src/utils/captcha-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ const CAPTCHA_DOMAINS = [
"gstatic.com",
"hcaptcha.com",
"cloudflare.com",
"challenges.cloudflare.com"
"challenges.cloudflare.com",
"cdn-cgi",
"cf-assets",
"turnstile"
];

/**
Expand Down Expand Up @@ -78,22 +81,33 @@ function enhanceCookieHandling() {
// Store original cookie descriptor
const originalCookieDescriptor = Object.getOwnPropertyDescriptor(Document.prototype, "cookie");

if (originalCookieDescriptor) {
Object.defineProperty(document, "cookie", {
get() {
return originalCookieDescriptor.get?.call(this) || "";
},
set(value) {
// Ensure SameSite=None for CAPTCHA cookies in cross-origin iframes
if (typeof value === "string" && value.includes("_GRECAPTCHA")) {
if (!value.includes("SameSite")) {
value += "; SameSite=None; Secure";
if (originalCookieDescriptor && originalCookieDescriptor.configurable) {
try {
Object.defineProperty(document, "cookie", {
get() {
return originalCookieDescriptor.get?.call(this) || "";
},
set(value) {
// Ensure SameSite=None for CAPTCHA cookies in cross-origin iframes
if (typeof value === "string") {
// Handle various CAPTCHA-related cookies
const isCaptchaCookie = value.includes("_GRECAPTCHA") ||
value.includes("_hcaptcha") ||
value.includes("cf_clearance") ||
value.includes("__cf_bm");

if (isCaptchaCookie && !value.includes("SameSite")) {
// Add SameSite=None and Secure for cross-origin cookies
value += "; SameSite=None; Secure";
}
}
}
originalCookieDescriptor.set?.call(this, value);
},
configurable: true
});
originalCookieDescriptor.set?.call(this, value);
},
configurable: true
});
} catch (error) {
console.warn("Failed to enhance cookie handling:", error);
}
}
}

Expand All @@ -119,7 +133,7 @@ function enhanceNetworkRequests() {
if (isCaptchaRequest) {
// Ensure credentials are included
init = init || {};
if (!init.credentials) {
if (!init.credentials || init.credentials === "omit") {
init.credentials = "include";
}

Expand All @@ -128,6 +142,11 @@ function enhanceNetworkRequests() {
if (!init.headers.has("Accept")) {
init.headers.set("Accept", "*/*");
}

// Don't override cache mode for CAPTCHA requests
if (!init.cache) {
init.cache = "default";
}
}

return originalFetch.call(this, input, init);
Expand All @@ -142,7 +161,9 @@ function enhanceNetworkRequests() {

// Store original open method
const originalOpen = xhr.open;
xhr.open = function (method: string, url: string | URL, ...args: any[]) {
const originalSend = xhr.send;

xhr.open = function (method: string, url: string | URL, async?: boolean, username?: string | null, password?: string | null) {
const urlStr = url.toString();
const isCaptchaRequest = CAPTCHA_DOMAINS.some((domain) => urlStr.includes(domain));

Expand All @@ -151,7 +172,21 @@ function enhanceNetworkRequests() {
xhr.withCredentials = true;
}

return originalOpen.call(this, method, url, ...args);
if (async !== undefined) {
if (username !== undefined) {
if (password !== undefined) {
return originalOpen.call(this, method, url, async, username, password);
}
return originalOpen.call(this, method, url, async, username);
}
return originalOpen.call(this, method, url, async);
}
return originalOpen.call(this, method, url);
};

// Ensure headers are properly set
xhr.send = function (body?: Document | XMLHttpRequestBodyInit | null) {
return originalSend.call(this, body);
};

return xhr;
Expand Down