diff --git a/src/_locales/en_US/messages.json b/src/_locales/en_US/messages.json index 68f8a74541..b58aac7a88 100644 --- a/src/_locales/en_US/messages.json +++ b/src/_locales/en_US/messages.json @@ -129,6 +129,14 @@ "message": "Prevent WebRTC from leaking local IP address", "description": "Checkbox label on the general settings page" }, + "options_x_client_data_setting": { + "message": "Remove Chrome-only identifier from being sent on Google sites", + "description": "Checkbox label on the general settings page for removing the x-client-data header on Chrome" + }, + "x_client_data_warning": { + "message": "Chrome HTTP header \"x-client-data\" purportedly used to test new features on Google sites, may cause breakage", + "description": "warning tooltip that appears next to the x-client-data option on the settings page" + }, "intro_welcome": { "message": "Privacy Badger automatically learns to block invisible trackers. Take a minute to see how.", "description": "Intro page welcome paragraph." diff --git a/src/js/background.js b/src/js/background.js index a3cec271b8..c3690c4d0a 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -844,6 +844,7 @@ Badger.prototype = { learnLocally: false, migrationLevel: 0, preventWebRTCIPLeak: false, + removeXClientDataHeader: false, seenComic: false, sendDNTSignal: true, showCounter: true, @@ -1125,6 +1126,12 @@ Badger.prototype = { return this.getSettings().getItem("checkForDNTPolicy"); }, + isRemoveXClientDataHeaderEnabled: function() { + if (!chrome.runtime.getBrowserInfo) { + return this.getSettings().getItem("removeXClientDataHeader"); + } + }, + isFlocOverwriteEnabled: function() { if (document.interestCohort) { return this.getSettings().getItem("disableFloc"); diff --git a/src/js/options.js b/src/js/options.js index 608546e90d..1461b51d12 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -168,6 +168,22 @@ function loadOptions() { }); } + // only show the x-client-data header setting if in Chrome + // TODO: more accurate way to determine this is a Chrome or Chromium browser + if (!chrome.runtime.getBrowserInfo) { + $("#remove-x-client-data-toggle").show(); + $("#toggle-x-client-data-header-mode") + .prop("checked", OPTIONS_DATA.settings.removeXClientDataHeader) + .on("click", function () { + const removeXClientDataHeader = $("#toggle-x-client-data-header-mode").prop("checked"); + + chrome.runtime.sendMessage({ + type: "updateSettings", + data: { removeXClientDataHeader } + }); + }); + } + if (OPTIONS_DATA.webRTCAvailable && OPTIONS_DATA.legacyWebRtcProtectionUser) { $("#webRTCToggle").show(); $("#toggle_webrtc_mode") diff --git a/src/js/webrequest.js b/src/js/webrequest.js index fc043fe4aa..2f38a329d3 100644 --- a/src/js/webrequest.js +++ b/src/js/webrequest.js @@ -203,14 +203,18 @@ function onBeforeSendHeaders(details) { type = details.type, url = details.url; + // option to remove x-client-data headers as well + const removeXClientData = badger.isRemoveXClientDataHeaderEnabled(); + if (_isTabChromeInternal(tab_id)) { // DNT policy requests: strip cookies if (type == "xmlhttprequest" && url.endsWith("/.well-known/dnt-policy.txt")) { // remove Cookie headers let newHeaders = []; + for (let i = 0, count = details.requestHeaders.length; i < count; i++) { let header = details.requestHeaders[i]; - if (header.name.toLowerCase() != "cookie") { + if (header.name.toLowerCase() != "cookie" || (removeXClientData && header.name.toLowerCase() != 'x-client-data')) { newHeaders.push(header); } } @@ -256,10 +260,10 @@ function onBeforeSendHeaders(details) { if (action == constants.COOKIEBLOCK || action == constants.USER_COOKIEBLOCK) { let newHeaders; - // GET requests: remove cookie headers, reduce referrer header to origin + // GET requests: remove cookie (and x-client-data if option is set) headers, reduce referrer header to origin if (details.method == "GET") { newHeaders = details.requestHeaders.filter(header => { - return (header.name.toLowerCase() != "cookie"); + return (header.name.toLowerCase() != "cookie" || (removeXClientData && header.name.toLowerCase() != 'x-client-data')); }).map(header => { if (header.name.toLowerCase() == "referer") { header.value = header.value.slice( @@ -270,10 +274,10 @@ function onBeforeSendHeaders(details) { return header; }); - // remove cookie and referrer headers otherwise + // remove cookie, referrer (and x-client-data if option is set) otherwise } else { newHeaders = details.requestHeaders.filter(header => { - return (header.name.toLowerCase() != "cookie" && header.name.toLowerCase() != "referer"); + return (header.name.toLowerCase() != "cookie" && header.name.toLowerCase() != "referer" && (removeXClientData && header.name.toLowerCase() != 'x-client-data')); }); } diff --git a/src/skin/options.html b/src/skin/options.html index 79ddee605a..cefd9d6376 100644 --- a/src/skin/options.html +++ b/src/skin/options.html @@ -252,6 +252,16 @@
+