// These are Cloudflare's headers, taken from here: // https://developers.cloudflare.com/fundamentals/reference/http-headers/ const CLOUDFLARE_HEADERS = new Set([ 'cf-connecting-ip', 'cf-connecting-ipv6', 'cf-ew-via', 'cf-pseudo-ipv4', 'cf-ray', 'cf-ipcountry', 'cf-visitor', 'cf-worker' ]); let blockingEnabled = true; let stateLoaded = false; const stateReady = browser.storage.local.get({ blockingEnabled: true }) .then(result => { blockingEnabled = result.blockingEnabled; }) .catch(() => { /* keep the default */ }) .then(() => { stateLoaded = true; }); browser.storage.onChanged.addListener((changes, area) => { if (area === 'local' && changes.blockingEnabled) { blockingEnabled = changes.blockingEnabled.newValue; } }); function blockedPageUrl(header, url) { const query = new URLSearchParams({ name: header.name, value: header.value || '', url: url }).toString(); return browser.runtime.getURL('blocked.html') + '?' + query; } function checkResponse(details) { if (!blockingEnabled) { return {}; } const cfHeader = (details.responseHeaders || []).find(header => CLOUDFLARE_HEADERS.has(header.name.toLowerCase()) ); if (!cfHeader) { return {}; } if (details.type === 'main_frame') { return { redirectUrl: blockedPageUrl(cfHeader, details.url) }; } // Subresource (image, script, stylesheet, font, iframe, fetch...): drop // just that request. The page itself keeps loading without it. // Makes the extension a bit more usable. return { cancel: true }; } browser.webRequest.onHeadersReceived.addListener( details => stateLoaded ? checkResponse(details) : stateReady.then(() => checkResponse(details)), { urls: [''] }, ['blocking', 'responseHeaders'] );