var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); // node_modules/await-timeout/src/utils.js var require_utils = __commonJS({ "node_modules/await-timeout/src/utils.js"(exports) { exports.promiseFinally = (promise, fn) => { const success = /* @__PURE__ */ __name((result) => { fn(); return result; }, "success"); const error = /* @__PURE__ */ __name((e) => { fn(); return Promise.reject(e); }, "error"); return Promise.resolve(promise).then(success, error); }; exports.toError = (value) => { value = typeof value === "function" ? value() : value; return typeof value === "string" ? new Error(value) : value; }; } }); // node_modules/await-timeout/src/index.js var require_src = __commonJS({ "node_modules/await-timeout/src/index.js"(exports, module) { var { promiseFinally, toError } = require_utils(); module.exports = class Timeout2 { static { __name(this, "Timeout"); } static set(delay, rejectReason) { return new Timeout2().set(delay, rejectReason); } static wrap(promise, delay, rejectReason) { return new Timeout2().wrap(promise, delay, rejectReason); } constructor() { this._id = null; this._delay = null; } get id() { return this._id; } get delay() { return this._delay; } set(delay, rejectReason = "") { return new Promise((resolve, reject) => { this.clear(); const fn = rejectReason ? () => reject(toError(rejectReason)) : resolve; this._id = setTimeout(fn, delay); this._delay = delay; }); } wrap(promise, delay, rejectReason = "") { const wrappedPromise = promiseFinally(promise, () => this.clear()); const timer = this.set(delay, rejectReason); return Promise.race([ wrappedPromise, timer ]); } clear() { if (this._id) { clearTimeout(this._id); } } }; } }); // helpers/misc.js var helpers = { //List of known static file extensions that should never be subjected to queueing. creativeAssetExtensions: [ "avi", "css", "csv", "eot", "gif", "ico", "jpg", "js", "json", "map", "mov", "mp4", "mpeg", "mpg", "ogg", "ogv", "ott", "pdf", "png", "svg", "ttf", "webmanifest", "wmv", "woff", "woff2", "xml" ], //regex for matching wordpress urls and query strings wordpressExclusions: /(w[cp][-_](?![-_]).*|xmlrpc\.php|readme\.html|license\.txt|trackback|feed(?:\/.*)?|comments\/feed(?:\/.*)?)(\?.*)?/, noCacheHeaders: { "Cache-Control": "no-cache, no-store, must-revalidate", Expires: "Fri, 01 Jan 1970 00:00:00 GMT", Pragma: "no-cache" }, lottery: /* @__PURE__ */ __name(function(roofInteger) { return Math.round(Math.random() * parseInt(roofInteger)); }, "lottery"), parseCookies: /* @__PURE__ */ __name(function(headers) { const parsedCookie = {}; if (headers.cookie) { headers.cookie.split(";").forEach((cookie) => { if (cookie) { const parts = cookie.split("="); parsedCookie[parts[0].trim()] = parts[1].trim(); } }); } return parsedCookie; }, "parseCookies"), queryStringParse: /* @__PURE__ */ __name(function(querystring) { const params = new URLSearchParams(querystring); let qStrObject = {}; for (let item of params) { qStrObject[item[0]] = item[1]; } return qStrObject; }, "queryStringParse") }; var misc_default = helpers; // helpers/http.js var dummyResponseData = { result: { status: 2, token: null, title: null, position: null, live_position: null, promoted: null, urlRedirect: null, onsale: null, message: null, slug: null, priority: null, priorityAvailable: null, logo: null, responseID: null, captchaRequired: null, ttl: null } }; var http_helpers = { processResponse: /* @__PURE__ */ __name(async function(response) { let fetchResponse; let responseObject = {}; fetchResponse = await response; if (!fetchResponse) { responseObject.body = dummyResponseData; responseObject.status = null; responseObject.statusText = "Communication failure between Cloudflare and the CrowdHandler API occured."; responseObject.success = false; return responseObject; } else if (fetchResponse.status !== 200) { responseObject.body = dummyResponseData; } else { responseObject.body = await response.json(); } responseObject.status = fetchResponse.status; responseObject.statusText = fetchResponse.statusText; responseObject.success = fetchResponse.ok; return responseObject; }, "processResponse") }; var http_default = http_helpers; // index.js var import_await_timeout = __toESM(require_src(), 1); async function handleWhitelabelRequest(request, env) { let fallbackPath = `/${request.queryString}`; let slug = request.path.substring(4); let templateContentType = "text/html;charset=UTF-8"; let templateDomain; let devPublicKeys = [ "dba793b5eb837611498d0b809aefdefcb6f113310b272f6114435964670125a1", "04a39378b6abc3e3ee870828471636a9d1e157b1a7720821aed4c260108ebe43" ]; if (devPublicKeys.includes(env.API_KEY)) { templateDomain = "wait-dev.crowdhandler.com"; } else { templateDomain = "wait.crowdhandler.com"; } let templateEndpoint; let templateFetchTimeout = 6e3; if (slug) { templateEndpoint = `https://${templateDomain}/${slug}`; } else { templateEndpoint = `https://${templateDomain}${fallbackPath}`; } let cache = await caches.open("crowdhandler:cache"); let cacheHit = await cache.match(templateEndpoint); if (cacheHit) { console.log("Serving waiting room template from cache."); return { response: cacheHit, useCache: true }; } let httpParams = { headers: { "content-type": templateContentType }, method: "GET" }; async function gatherResponse(response) { const { headers } = response; const contentType = headers.get("content-type") || ""; if (contentType.includes("application/json")) { return JSON.stringify(await response.json()); } else if (contentType.includes("application/text")) { return response.text(); } else if (contentType.includes("text/html")) { return response.text(); } else { return response.text(); } } __name(gatherResponse, "gatherResponse"); let errorState; let fetchCounter = 0; async function fetchTemplate() { let timer = new import_await_timeout.default(); errorState = null; let response; try { fetchCounter++; response = await Promise.race([ fetch(templateEndpoint, httpParams), timer.set(templateFetchTimeout, "API Communication Timed Out!") ]); if (response.status !== 200) { throw `${response.status} ${response.statusText}`; } } catch (error) { errorState = true; console.error("Template Fetch Failure"); console.log(error); } finally { timer.clear(); if (errorState === true && fetchCounter < 3) { console.log("Retrying Template Fetch."); await fetchTemplate(); } return response; } } __name(fetchTemplate, "fetchTemplate"); let templateResponse = await fetchTemplate(); let results; let resultsMeta; if (templateResponse) { results = await gatherResponse(templateResponse); resultsMeta = { headers: { "content-type": templateContentType }, status: templateResponse.status, statusText: templateResponse.statusText }; } else { results = "

Service Temporarily Unavailable

"; resultsMeta = { headers: { "content-type": templateContentType }, status: 503, statusText: "Service Unavailable" }; } return { cache, results, resultsMeta, templateEndpoint }; } __name(handleWhitelabelRequest, "handleWhitelabelRequest"); async function handleRequest(request, env, ctx) { const requestStartTime = Date.now(); const bypassedFileExtensions = misc_default.creativeAssetExtensions; const wordpressExclusions = misc_default.wordpressExclusions; const url = request.url; const urlAttributes = new URL(url); const host = urlAttributes.hostname; const path = urlAttributes.pathname; const requestHeaders = Object.fromEntries(request.headers); const unprocessedQueryString = urlAttributes.search; const IPAddress = requestHeaders["cf-connecting-ip"]; const userAgent = requestHeaders["user-agent"]; const validToken = /(.*\d+.*)/; let language; let waitingRoomDomain; let statusIdentifier = /^\/ch\/status$/; let whiteLabelIdentifier = /^\/ch\/.*/; if (statusIdentifier.test(path) === true) { return new Response( JSON.stringify({ integration: "cloudflare", status: "ok" }), { headers: { "content-type": "text/plain", "cache-control": "public, max-age=60" } } ); } if (whiteLabelIdentifier.test(path) === true) { const whitelabelResponse = await handleWhitelabelRequest({ path, queryString: unprocessedQueryString }, env); try { if (whitelabelResponse.useCache === true) { return whitelabelResponse.response; } } catch (error) { console.log(error); } try { whitelabelResponse.resultsMeta.headers["cache-control"] = "public, max-age=60"; if (whitelabelResponse.resultsMeta.status === 200) { console.log("Storing template in cache"); await whitelabelResponse.cache.put( whitelabelResponse.templateEndpoint, new Response( whitelabelResponse.results, whitelabelResponse.resultsMeta ) ); } } catch (error) { console.log(error); } return new Response( whitelabelResponse.results, whitelabelResponse.resultsMeta ); } try { language = requestHeaders["accept-language"].split(",")[0]; } catch (error) { console.log("Failed to find a valid accept-language value"); console.log(error); } const modifiedRequest = new Request(url, { body: request.body, headers: request.headers, method: request.method, redirect: request.redirect }); if (env.NO_BYPASS) { modifiedRequest.headers.append("x-ch-no-bypass", env.NO_BYPASS); } let failTrust = true; if (env.FAIL_TRUST && env.FAIL_TRUST === "false") { failTrust = false; } let safetyNetSlug; if (env.SAFETY_NET_SLUG) { safetyNetSlug = env.SAFETY_NET_SLUG; } let whitelabel = false; if (env.WHITELABEL && env.WHITELABEL === "true") { whitelabel = true; } if (whitelabel === true) { waitingRoomDomain = `${host}/ch`; } else { waitingRoomDomain = "wait.crowdhandler.com"; } let fileExtension = path.match(/\.(.*)/); if (fileExtension !== null) { fileExtension = fileExtension[1]; } if (bypassedFileExtensions.indexOf(fileExtension) !== -1) { console.log("Static file detected. Going straight to origin."); return await fetch(modifiedRequest); } let queryString; if (unprocessedQueryString) { queryString = misc_default.queryStringParse( decodeURIComponent(unprocessedQueryString) ); } let { "ch-code": chCode, "ch-fresh": chFresh, "ch-id": chID, "ch-id-signature": chIDSignature, "ch-public-key": chPublicKey, "ch-requested": chRequested } = queryString || {}; if (!chCode || chCode === "undefined" || chCode === "null") { chCode = ""; } if (queryString) { delete queryString["ch-code"]; delete queryString["ch-fresh"]; delete queryString["ch-id"]; delete queryString["ch-id-signature"]; delete queryString["ch-public-key"]; delete queryString["ch-requested"]; } if (queryString && Object.keys(queryString).length !== 0) { queryString = Object.keys(queryString).map((key) => key + "=" + queryString[key]).join("&"); queryString = `?${queryString}`; } else { queryString = null; } let origin_type; if (env.ORIGIN_TYPE) { origin_type = env.ORIGIN_TYPE; } if (origin_type === "wordpress") { if (wordpressExclusions.test(path) === true || wordpressExclusions.test(queryString) === true) { console.log("Wordpress exclusion detected. Going straight to origin."); return await fetch(modifiedRequest); } } let targetURL; if (queryString) { targetURL = encodeURIComponent(`https://${host}${path}${queryString}`); } else { targetURL = encodeURIComponent(`https://${host}${path}`); } const parsedCookies = misc_default.parseCookies(requestHeaders); let crowdhandlerCookieValue = parsedCookies["crowdhandler"]; let token; let freshlyPromoted; if (chID) { token = chID; freshlyPromoted = true; } else if (crowdhandlerCookieValue) { token = crowdhandlerCookieValue; } else { token = null; } if (freshlyPromoted) { let setCookie = { "Set-Cookie": `crowdhandler=${token}; path=/; Secure` }; let redirectLocation2; if (queryString) { redirectLocation2 = { Location: `${path}${queryString}` }; } else { redirectLocation2 = { Location: path }; } return new Response(null, { status: 302, headers: Object.assign( misc_default.noCacheHeaders, redirectLocation2, setCookie ) }); } if (validToken.test(token) !== true) { token = null; } const apiHost = env.API_ENDPOINT; const apiTimeout = 4e3; let httpParams = { headers: { "content-type": "application/json", "x-api-key": env.API_KEY }, //choose method dynamically method: void 0 }; let response; let timer = new import_await_timeout.default(); if (token) { httpParams.method = "GET"; try { response = await Promise.race([ fetch( `${apiHost}/requests/${token}?url=${targetURL}&agent=${encodeURIComponent( userAgent )}&ip=${encodeURIComponent(IPAddress)}&lang=${encodeURIComponent( language )}`, httpParams ), timer.set(apiTimeout, "CrowdHandler API request timed out") ]); } catch (error) { console.error("CrowdHandler API GET request failed:", error); response = void 0; } finally { timer.clear(); } } else { httpParams.body = JSON.stringify({ agent: userAgent, ip: IPAddress, lang: language, url }); httpParams.method = "POST"; try { response = await Promise.race([ fetch(`${apiHost}/requests`, httpParams), timer.set(apiTimeout, "CrowdHandler API request timed out") ]); } catch (error) { console.error("CrowdHandler API POST request failed:", error); response = void 0; } finally { timer.clear(); } } const processResponse = http_default.processResponse; const results = await processResponse(response); let responseBody; if (results.success !== true) { console.error( `API response returned a ${results.status} response with error ${results.statusText}` ); responseBody = results.body.result; console.log(responseBody); } else { responseBody = results.body.result; console.log(responseBody); } let redirect; let redirectLocation; let statusCode; if (responseBody.promoted !== 1 && responseBody.status !== 2) { redirect = true; redirectLocation = `https://${waitingRoomDomain}/${responseBody.slug}?url=${targetURL}&ch-code=${chCode}&ch-id=${responseBody.token}&ch-public-key=${env.API_KEY}`; } else if (failTrust !== true && responseBody.promoted !== 1 && responseBody.status === 2) { redirect = true; if (safetyNetSlug) { redirectLocation = `https://${waitingRoomDomain}/${safetyNetSlug}?url=${targetURL}&ch-code=${chCode}&ch-id=${token}&ch-public-key=${env.API_KEY}`; } else { redirectLocation = `https://${waitingRoomDomain}/?url=${targetURL}&ch-code=${chCode}&ch-id=${token}&ch-public-key=${env.API_KEY}`; } } else { redirect = false; } switch (redirect) { case true: { console.log("redirecting..."); if (responseBody.token) { return new Response(null, { status: 302, headers: Object.assign(misc_default.noCacheHeaders, { Location: redirectLocation, "Set-Cookie": `crowdhandler=${responseBody.token}; path=/; Secure` }) }); } else { return new Response(null, { status: 302, headers: Object.assign(misc_default.noCacheHeaders, { Location: redirectLocation }) }); } break; } case false: { console.log("continue..."); break; } default: { break; } } const originResponse = await fetch(modifiedRequest); let modifiedOriginResponse = new Response(originResponse.body, { status: originResponse.status, statusText: originResponse.statusText, headers: originResponse.headers }); if (validToken.test(responseBody.token) === true) { modifiedOriginResponse.headers.append( "set-cookie", `crowdhandler=${responseBody.token}; path=/; Secure` ); } modifiedOriginResponse.headers.append( "set-cookie", `crowdhandler_integration=cloudflare; path=/; Secure` ); const requestEndTime = Date.now(); const responseID = responseBody.responseID; async function sendRequestMeta() { if (responseID && misc_default.lottery(2) === 0) { httpParams.body = JSON.stringify({ httpCode: originResponse.status, sampleRate: 3, time: requestEndTime - requestStartTime }); httpParams.method = "PUT"; response = await fetch(`${apiHost}/responses/${responseID}`, httpParams); const processResponse2 = http_default.processResponse; const results2 = await processResponse2(response); return results2; } } __name(sendRequestMeta, "sendRequestMeta"); ctx.waitUntil(sendRequestMeta()); return modifiedOriginResponse; } __name(handleRequest, "handleRequest"); var index_default = { async fetch(request, env, ctx) { ctx.passThroughOnException(); return await handleRequest(request, env, ctx); } }; export { index_default as default }; //# sourceMappingURL=index.js.map