diff --git a/v2/firefox/_locales/en/messages.json b/v2/firefox/_locales/en/messages.json
index 40d5248..6ef1b38 100644
--- a/v2/firefox/_locales/en/messages.json
+++ b/v2/firefox/_locales/en/messages.json
@@ -43,6 +43,9 @@
"faqs": {
"message": "Open FAQs page on updates"
},
+ "userAgentData": {
+ "message": "Expose \"navigator.userAgentData\" object on Chromium browsers"
+ },
"log": {
"message": "Display debugging info in the browser console"
},
diff --git a/v2/firefox/common.js b/v2/firefox/common.js
index 443efba..b939ad3 100644
--- a/v2/firefox/common.js
+++ b/v2/firefox/common.js
@@ -27,6 +27,7 @@ const prefs = {
'color': '#777',
'cache': true,
'exactMatch': false,
+ 'userAgentData': true,
'protected': [
'google.com/recaptcha',
'gstatic.com/recaptcha',
@@ -161,7 +162,7 @@ chrome.storage.local.get(prefs, ps => {
chrome.storage.onChanged.addListener(ps => {
Object.keys(ps).forEach(key => prefs[key] = ps[key].newValue);
- if (ps.ua || ps.mode) {
+ if (ps.ua || ps.mode || ps.userAgentData) {
currentCookieStoreId().then(cookieStoreId => {
if (ps.ua) {
if (ps.ua.newValue === '') {
@@ -233,6 +234,7 @@ const ua = {
const isCH = /Chrome/.test(s);
const isSF = /Safari/.test(s) && isCH === false;
+
if (isFF) {
o.appVersion = '5.0 ' + o.appVersion.replace('5.0 ', '').split(/[\s;]/)[0] + ')';
}
@@ -252,9 +254,9 @@ const ua = {
if (s.indexOf('Gecko') !== -1) {
o.product = 'Gecko';
}
+ o.userAgentData = '[delete]';
if (isFF) {
o.oscpu = ((p.os.name || '') + ' ' + (p.os.version || '')).trim();
- o.userAgentData = '[delete]';
o.productSub = '20100101';
o.buildID = '20181001000000';
}
@@ -263,36 +265,11 @@ const ua = {
o.buildID = '[delete]';
o.productSub = '20030107';
- if (p.browser && p.browser.major) {
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-UA-Platform
- let platform = 'Unknown';
- if (p.os && p.os.name) {
- const name = p.os.name.toLowerCase();
- if (name.includes('mac')) {
- platform = 'macOS';
- }
- else if (name.includes('debian')) {
- platform = 'Linux';
- }
- else {
- platform = p.os.name;
- }
+ if (prefs.userAgentData && p.browser && p.browser.major) {
+ if (['Opera', 'Chrome', 'Edge', 'Vivaldi'].includes(p.browser.name)) {
+ o.userAgentDataBuilder = {p, ua: s};
+ delete o.userAgentData;
}
-
- o.userAgentData = {
- brands: [{
- brand: 'Not=A?Brand',
- version: '99'
- }, {
- brand: p.browser.name === 'Chrome' ? 'Google Chrome' : p.browser.name,
- version: p.browser.major
- }, {
- brand: 'Chromium',
- version: p.browser.major
- }],
- mobile: /Android|webOS|iPhone|iPad|Mac|Macintosh|iPod|BlackBerry|IEMobile|Opera Mini/i.test(s),
- platform
- };
}
}
@@ -589,6 +566,82 @@ const onCommitted = d => {
document.currentScript.dataset.injected = true;
const o = JSON.parse(decodeURIComponent(escape(atob('${s}'))));
+ if (o.userAgentDataBuilder) {
+ navigator.userAgentData = new class NavigatorUAData {
+ #p;
+
+ constructor({p, ua}) {
+ this.#p = p;
+
+ const version = p.browser.major;
+ const name = p.browser.name === 'Chrome' ? 'Google Chrome' : p.browser.name;
+
+ this.brands = [{
+ brand: name,
+ version
+ }, {
+ brand: 'Chromium',
+ version
+ }, {
+ brand: 'Not=A?Brand',
+ version: '24'
+ }];
+
+ this.mobile = /Android|webOS|iPhone|iPad|Mac|Macintosh|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
+
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-UA-Platform
+ this.platform = 'Unknown';
+ if (p.os && p.os.name) {
+ const name = p.os.name.toLowerCase();
+ if (name.includes('mac')) {
+ this.platform = 'macOS';
+ }
+ else if (name.includes('debian')) {
+ this.platform = 'Linux';
+ }
+ else {
+ this.platform = p.os.name;
+ }
+ }
+ }
+ toJSON() {
+ return {
+ brands: this.brands,
+ mobile: this.mobile,
+ platform: this.platform
+ };
+ }
+ getHighEntropyValues(hints) {
+ if (!hints || Array.isArray(hints) === false) {
+ return Promise.reject(Error("Failed to execute 'getHighEntropyValues' on 'NavigatorUAData'"));
+ }
+
+ const r = this.toJSON();
+
+ if (hints.includes('architecture')) {
+ r.architecture = this.#p?.cpu?.architecture || 'x86';
+ }
+ if (hints.includes('bitness')) {
+ r.bitness = '64';
+ }
+ if (hints.includes('model')) {
+ r.model = '';
+ }
+ if (hints.includes('platformVersion')) {
+ r.platformVersion = this.#p?.os?.version || '10.0.0';
+ }
+ if (hints.includes('uaFullVersion')) {
+ r.uaFullVersion = this.brands[0].version;
+ }
+ if (hints.includes('fullVersionList')) {
+ r.fullVersionList = this.brands;
+ }
+ return Promise.resolve(r);
+ }
+ }(o.userAgentDataBuilder);
+ }
+ delete o.userAgentDataBuilder;
+
for (const key of Object.keys(o)) {
if (o[key] === '[delete]') {
delete Object.getPrototypeOf(window.navigator)[key];
diff --git a/v2/firefox/data/options/index.html b/v2/firefox/data/options/index.html
index 2450e64..d25515d 100644
--- a/v2/firefox/data/options/index.html
+++ b/v2/firefox/data/options/index.html
@@ -36,6 +36,8 @@
+
+
diff --git a/v2/firefox/data/options/index.js b/v2/firefox/data/options/index.js
index 609dc46..7e918a0 100644
--- a/v2/firefox/data/options/index.js
+++ b/v2/firefox/data/options/index.js
@@ -78,6 +78,7 @@ function save() {
chrome.storage.local.set({
exactMatch: document.getElementById('exactMatch').checked,
faqs: document.getElementById('faqs').checked,
+ userAgentData: document.getElementById('userAgentData').checked,
log: document.getElementById('log').checked,
cache: document.getElementById('cache').checked,
blacklist: prepare(document.getElementById('blacklist').value),
@@ -101,6 +102,7 @@ function restore() {
chrome.storage.local.get({
exactMatch: false,
faqs: true,
+ userAgentData: true,
log: false,
cache: true,
mode: 'blacklist',
@@ -119,6 +121,7 @@ function restore() {
}, prefs => {
document.getElementById('exactMatch').checked = prefs.exactMatch;
document.getElementById('faqs').checked = prefs.faqs;
+ document.getElementById('userAgentData').checked = prefs.userAgentData;
document.getElementById('log').checked = prefs.log;
document.getElementById('cache').checked = prefs.cache;
document.querySelector(`[name="mode"][value="${prefs.mode}"`).checked = true;