version 0.4.9

This commit is contained in:
Ray Lothian 2022-11-16 06:28:54 -05:00
parent 1353e8a110
commit 70a5affd37
11 changed files with 299 additions and 109 deletions

View file

@ -1,4 +1,4 @@
/* globals UAParser */ /* global UAParser */
'use strict'; 'use strict';
@ -544,15 +544,15 @@ const onBeforeSendHeaders = d => {
if (platform.toLowerCase().includes('mac')) { if (platform.toLowerCase().includes('mac')) {
platform = 'macOS'; platform = 'macOS';
} }
else if (platform.toLowerCase().includes('debian')) {
platform = 'Linux';
}
const version = o.userAgentDataBuilder.p?.browser?.major || 107; const version = o.userAgentDataBuilder.p?.browser?.major || 107;
let name = o.userAgentDataBuilder.p?.browser?.name || 'Google Chrome'; let name = o.userAgentDataBuilder.p?.browser?.name || 'Google Chrome';
if (name === 'Chrome') { if (name === 'Chrome') {
name = 'Google Chrome'; name = 'Google Chrome';
} }
else if (name.includes('debian')) {
platform = 'Linux';
}
requestHeaders.push({ requestHeaders.push({
name: 'sec-ch-ua-platform', name: 'sec-ch-ua-platform',

View file

@ -1,7 +1,7 @@
{ {
"manifest_version": 2, "manifest_version": 2,
"name": "__MSG_extensionName__", "name": "__MSG_extensionName__",
"version": "0.4.8", "version": "0.4.9",
"default_locale": "en", "default_locale": "en",
"description": "__MSG_extensionDescription__", "description": "__MSG_extensionDescription__",
"permissions": [ "permissions": [

View file

@ -15,3 +15,5 @@ self.prefs = self.prefs || {
platformVersion: '10.0.0' platformVersion: '10.0.0'
}; };
Object.assign(port.dataset, self.prefs); Object.assign(port.dataset, self.prefs);
port.dataset.enabled = self.ingored ? false : true;

View file

@ -1,6 +1,5 @@
const port = document.getElementById('ua-port-fgTd9n'); const port = document.getElementById('ua-port-fgTd9n');
port.remove(); port.remove();
console.log(12, port);
// overwrite navigator.userAgent // overwrite navigator.userAgent
{ {
@ -8,8 +7,8 @@ console.log(12, port);
Object.defineProperty(Navigator.prototype, 'userAgent', { Object.defineProperty(Navigator.prototype, 'userAgent', {
get: new Proxy(get, { get: new Proxy(get, {
apply() { apply(target, self, args) {
return port.dataset.ua; return port.dataset.enabled === 'true' ? port.dataset.ua : Reflect.apply(target, self, args);
} }
}) })
}); });
@ -31,8 +30,8 @@ if (port.dataset.uad) {
Object.defineProperty(self.NavigatorUAData.prototype, 'brands', { Object.defineProperty(self.NavigatorUAData.prototype, 'brands', {
get: new Proxy(Object.getOwnPropertyDescriptor(self.NavigatorUAData.prototype, 'brands').get, { get: new Proxy(Object.getOwnPropertyDescriptor(self.NavigatorUAData.prototype, 'brands').get, {
apply() { apply(target, self, args) {
return [{ return port.dataset.enabled === 'true' ? [{
brand: port.dataset.name, brand: port.dataset.name,
version: port.dataset.major version: port.dataset.major
}, { }, {
@ -41,62 +40,65 @@ if (port.dataset.uad) {
}, { }, {
brand: 'Not=A?Brand', brand: 'Not=A?Brand',
version: '24' version: '24'
}]; }] : Reflect.apply(target, self, args);
} }
}) })
}); });
Object.defineProperty(self.NavigatorUAData.prototype, 'mobile', { Object.defineProperty(self.NavigatorUAData.prototype, 'mobile', {
get: new Proxy(Object.getOwnPropertyDescriptor(self.NavigatorUAData.prototype, 'mobile').get, { get: new Proxy(Object.getOwnPropertyDescriptor(self.NavigatorUAData.prototype, 'mobile').get, {
apply() { apply(target, self, args) {
return port.dataset.mobile === 'true'; return port.dataset.enabled === 'true' ? port.dataset.mobile === 'true' : Reflect.apply(target, self, args);
} }
}) })
}); });
Object.defineProperty(self.NavigatorUAData.prototype, 'platform', { Object.defineProperty(self.NavigatorUAData.prototype, 'platform', {
get: new Proxy(Object.getOwnPropertyDescriptor(self.NavigatorUAData.prototype, 'platform').get, { get: new Proxy(Object.getOwnPropertyDescriptor(self.NavigatorUAData.prototype, 'platform').get, {
apply() { apply(target, self, args) {
return port.dataset.platform; return port.dataset.enabled === 'true' ? port.dataset.platform : Reflect.apply(target, self, args);
} }
}) })
}); });
self.NavigatorUAData.prototype.toJSON = new Proxy(self.NavigatorUAData.prototype.toJSON, { self.NavigatorUAData.prototype.toJSON = new Proxy(self.NavigatorUAData.prototype.toJSON, {
apply(target, self) { apply(target, self, args) {
return { return port.dataset.enabled === 'true' ? {
brands: self.brands, brands: self.brands,
mobile: self.mobile, mobile: self.mobile,
platform: self.platform platform: self.platform
}; } : Reflect.apply(target, self, args);
} }
}); });
self.NavigatorUAData.prototype.getHighEntropyValues = new Proxy(self.NavigatorUAData.prototype.getHighEntropyValues, { self.NavigatorUAData.prototype.getHighEntropyValues = new Proxy(self.NavigatorUAData.prototype.getHighEntropyValues, {
apply(target, self, args) { apply(target, self, args) {
const hints = args[0]; if (port.dataset.enabled === 'true') {
const hints = args[0];
if (!hints || Array.isArray(hints) === false) { if (!hints || Array.isArray(hints) === false) {
return Promise.reject(Error(`Failed to execute 'getHighEntropyValues' on 'NavigatorUAData'`)); return Promise.reject(Error(`Failed to execute 'getHighEntropyValues' on 'NavigatorUAData'`));
} }
const r = self.toJSON(); const r = self.toJSON();
if (hints.includes('architecture')) { if (hints.includes('architecture')) {
r.architecture = port.dataset.architecture; r.architecture = port.dataset.architecture;
}
if (hints.includes('bitness')) {
r.bitness = port.dataset.bitness;
}
if (hints.includes('model')) {
r.model = '';
}
if (hints.includes('platformVersion')) {
r.platformVersion = port.dataset.platformVersion;
}
if (hints.includes('uaFullVersion')) {
r.uaFullVersion = self.brands[0].version;
}
if (hints.includes('fullVersionList')) {
r.fullVersionList = this.brands;
}
return Promise.resolve(r);
} }
if (hints.includes('bitness')) { return Reflect.apply(target, self, args);
r.bitness = port.dataset.bitness;
}
if (hints.includes('model')) {
r.model = '';
}
if (hints.includes('platformVersion')) {
r.platformVersion = port.dataset.platformVersion;
}
if (hints.includes('uaFullVersion')) {
r.uaFullVersion = self.brands[0].version;
}
if (hints.includes('fullVersionList')) {
r.fullVersionList = this.brands;
}
return Promise.resolve(r);
} }
}); });
} }

2
v3/helper/ReadMe.txt Normal file
View file

@ -0,0 +1,2 @@
ua-parser.min.js:
https://github.com/faisalman/ua-parser-js/releases/tag/1.0.32

4
v3/helper/ua-parser.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -10,6 +10,7 @@
"webNavigation", "webNavigation",
"webRequest", "webRequest",
"declarativeNetRequest", "declarativeNetRequest",
"declarativeNetRequestFeedback",
"contextMenus" "contextMenus"
], ],
"host_permissions": [ "host_permissions": [

74
v3/policy.js Normal file
View file

@ -0,0 +1,74 @@
/* global UAParser */
self.importScripts('./helper/ua-parser.min.js');
const PREFS = {
'enabled': true,
'mode': 'blacklist',
'blacklist-exception-hosts': [],
'whitelist-hosts': [],
'custom-routing': {
'whatismybrowser.com': 'ff'
}
};
const policy = {};
{
const cache = new Map();
policy.parse = d => {
const ua = 'Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36';
if (cache.has(ua)) {
return cache.get(ua);
}
return new Promise(resolve => chrome.storage.local.get({
'userAgentData': true
}, prefs => {
const p = (new UAParser(ua)).getResult();
const r = {
ua
};
r.uad = prefs.userAgentData &&
p.browser && p.browser.major && ['Opera', 'Chrome', 'Edge'].includes(p.browser.name);
if (r.uad) {
r.platform = p?.os?.name || 'Windows';
if (r.platform.toLowerCase().includes('mac')) {
r.platform = 'macOS';
}
else if (r.platform.toLowerCase().includes('debian')) {
r.platform = 'Linux';
}
r.major = p?.browser?.major || 100;
r.name = p?.browser?.name || 'Google Chrome';
if (r.name === 'Chrome') {
r.name = 'Google Chrome';
}
r.mobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
r.architecture = 'x86';
r.bitness = '64';
r.platformVersion = '10.0.0';
}
cache.set(ua, r);
resolve(r);
}));
};
}
policy.configure = (...methods) => new Promise(resolve => chrome.storage.local.get(PREFS, prefs => {
for (const method of methods) {
method(prefs);
}
resolve();
}));

51
v3/request.js Normal file
View file

@ -0,0 +1,51 @@
/* global policy */
const request = {};
request.network = async prefs => {
const p = await policy.parse();
const condition = {
'isUrlFilterCaseSensitive': false,
'resourceTypes': Object.values(chrome.declarativeNetRequest.ResourceType)
};
const one = {
'id': 1,
'priority': 1,
'action': {
'type': 'modifyHeaders',
'requestHeaders': [{
'operation': 'set',
'header': 'user-agent',
'value': p.ua
}]
},
'condition': {
...condition
}
};
const o = {
addRules: [one],
removeRuleIds: (await chrome.declarativeNetRequest.getDynamicRules()).map(o => o.id)
};
if (prefs.enabled) {
if (prefs.mode === 'blacklist') {
one.condition.excludedInitiatorDomains = prefs['blacklist-exception-hosts'];
}
else {
if (prefs['whitelist-hosts'].length) {
one.condition.initiatorDomains = prefs['whitelist-hosts'];
}
else {
console.info('matching list is empty');
o.addRules.length = 0;
}
}
}
chrome.declarativeNetRequest.updateDynamicRules(o);
};
chrome.declarativeNetRequest.onRuleMatchedDebug.addListener(d => console.log(d));

104
v3/scripting.js Normal file
View file

@ -0,0 +1,104 @@
/* global port, policy */
const scripting = {};
scripting.page = async prefs => {
await chrome.scripting.unregisterContentScripts();
if (prefs.enabled) {
const common = {
'allFrames': true,
'matchOriginAsFallback': true,
'runAt': 'document_start'
};
if (prefs.mode === 'blacklist') {
common.matches = ['*://*/*'];
if (prefs['blacklist-exception-hosts'].length) {
common.excludeMatches = prefs['blacklist-exception-hosts'].map(h => [`*://${h}/*`, `*://*.${h}/*`]).flat();
}
}
else if (prefs['whitelist-hosts'].length) {
common.matches = prefs['whitelist-hosts'].map(h => [`*://${h}/*`, `*://*.${h}/*`]).flat();
}
if (common.matches.length) {
await chrome.scripting.registerContentScripts([{
...common,
'id': 'protected',
'js': ['/data/inject/isolated.js'],
'world': 'ISOLATED'
}, {
...common,
'id': 'unprotected',
'js': ['/data/inject/main.js'],
'world': 'MAIN'
}]);
}
else {
console.info('matching list is empty');
}
}
};
// web navigation
{
const onCommitted = async d => {
const p = await policy.parse(d);
if (p) {
chrome.scripting.executeScript({
target: {
tabId: d.tabId,
frameIds: [d.frameId]
},
injectImmediately: true,
func: p => {
if (typeof port === 'undefined') {
self.prefs = p;
}
else {
Object.assign(port.dataset, p);
}
},
args: [p]
});
}
};
const onCommittedIgnore = d => {
chrome.scripting.executeScript({
target: {
tabId: d.tabId,
frameIds: [d.frameId]
},
injectImmediately: true,
func: () => {
if (typeof port === 'undefined') {
port.dataset.enabled = false;
}
else {
self.ingored = true;
}
}
}).catch(() => {});
};
scripting.commit = prefs => {
if (prefs.enabled && prefs.mode === 'blacklist') {
chrome.webNavigation.onCommitted.addListener(onCommitted);
if (prefs['blacklist-exception-hosts'].length) {
chrome.webNavigation.onCommitted.addListener(onCommittedIgnore, {
url: prefs['blacklist-exception-hosts'].map(hostContains => ({
hostContains
}))
});
}
}
else if (prefs['whitelist-hosts'].length) {
chrome.webNavigation.onCommitted.addListener(onCommitted, {
url: prefs['whitelist-hosts'].map(hostContains => ({
hostContains
}))
});
}
};
}

View file

@ -1,72 +1,22 @@
const enable = () => chrome.storage.local.get({ /* global policy, scripting, request */
enabled: true
}, async prefs => {
await chrome.scripting.unregisterContentScripts();
if (prefs.enabled) { self.importScripts('./policy.js');
const common = { self.importScripts('./scripting.js');
'matches': ['*://*/*'], self.importScripts('./request.js');
'allFrames': true,
'matchOriginAsFallback': true,
'runAt': 'document_start'
};
await chrome.scripting.registerContentScripts([{ // run on each wake up
...common, policy.configure(scripting.commit, request.network);
'id': 'protected',
'js': ['/data/inject/isolated.js'], // run once
'world': 'ISOLATED' {
}, { const once = () => policy.configure(scripting.page);
...common,
'id': 'unprotected', chrome.runtime.onStartup.addListener(once);
'js': ['/data/inject/main.js'], chrome.runtime.onInstalled.addListener(once);
'world': 'MAIN' }
}]);
} chrome.storage.onChanged.addListener(ps => {
}); if (ps.enabled || ps.mode || ps['blacklist-exception-hosts'] || ps['whitelist-hosts']) {
chrome.runtime.onStartup.addListener(enable); policy.configure(scripting.commit, scripting.page, request.network);
chrome.runtime.onInstalled.addListener(enable);
const policy = () => ({
ua: 'Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
uad: true,
major: 100,
name: 'Google Chrome',
mobile: false,
platform: 'Windows',
architecture: 'x86',
bitness: '64',
platformVersion: '10.0.0'
});
// web navigation
const onCommitted = d => {
const p = policy(d);
if (p) {
chrome.scripting.executeScript({
target: {
tabId: d.tabId,
frameIds: [d.frameId]
},
injectImmediately: true,
func: p => {
/* global port */
if (typeof port === 'undefined') {
self.prefs = p;
}
else {
Object.assign(port.dataset, p);
}
},
args: [p]
});
}
};
chrome.storage.local.get({
enabled: true
}, prefs => {
if (prefs.enabled) {
chrome.webNavigation.onCommitted.addListener(onCommitted);
} }
}); });