supporting custom ua string per container; part 3; fixes #13
This commit is contained in:
parent
92773630cd
commit
21ba509c50
4 changed files with 74 additions and 39 deletions
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const DCSI = 'firefox-default';
|
||||||
|
|
||||||
const cache = {}; // cache how a tab's request get handled (true, false, object)
|
const cache = {}; // cache how a tab's request get handled (true, false, object)
|
||||||
const tabs = {};
|
const tabs = {};
|
||||||
|
@ -51,7 +52,7 @@ const currentCookieStoreId = () => new Promise(resolve => chrome.tabs.query({
|
||||||
active: true,
|
active: true,
|
||||||
currentWindow: true
|
currentWindow: true
|
||||||
}, tbs => {
|
}, tbs => {
|
||||||
resolve((tbs.length ? tbs[0].cookieStoreId : '') || 'firefox-default');
|
resolve((tbs.length ? tbs[0].cookieStoreId : '') || DCSI);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
chrome.storage.local.get(prefs, ps => {
|
chrome.storage.local.get(prefs, ps => {
|
||||||
|
@ -74,7 +75,7 @@ chrome.storage.local.get(prefs, ps => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ua.update(undefined, undefined, 'firefox-default');
|
ua.update(undefined, undefined, DCSI);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -114,7 +115,6 @@ chrome.storage.onChanged.addListener(ps => {
|
||||||
currentCookieStoreId().then(cookieStoreId => {
|
currentCookieStoreId().then(cookieStoreId => {
|
||||||
if (ps.ua) {
|
if (ps.ua) {
|
||||||
if (ps.ua.newValue === '') {
|
if (ps.ua.newValue === '') {
|
||||||
console.log('delete from onChanged', cookieStoreId);
|
|
||||||
delete ua._obj[cookieStoreId];
|
delete ua._obj[cookieStoreId];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,10 +128,10 @@ chrome.storage.onChanged.addListener(ps => {
|
||||||
|
|
||||||
const ua = {
|
const ua = {
|
||||||
_obj: {},
|
_obj: {},
|
||||||
diff(tabId, cookieStoreId = 'default-container') { // returns true if there is per window object
|
diff(tabId, cookieStoreId = DCSI) { // returns true if there is per window object
|
||||||
log('ua.diff is called', tabId, cookieStoreId);
|
log('ua.diff is called', tabId, cookieStoreId);
|
||||||
const windowId = tabs[tabId];
|
const windowId = tabs[tabId];
|
||||||
return windowId in (this._obj[cookieStoreId] || this._obj['default-container'] || {});
|
return windowId in (this._obj[cookieStoreId] || this._obj[DCSI] || {});
|
||||||
},
|
},
|
||||||
get windows() {
|
get windows() {
|
||||||
log('ua.windows is called');
|
log('ua.windows is called');
|
||||||
|
@ -193,7 +193,7 @@ const ua = {
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
},
|
},
|
||||||
object(tabId, windowId, cookieStoreId = 'default-container') {
|
object(tabId, windowId, cookieStoreId = DCSI) {
|
||||||
windowId = windowId || (tabId ? tabs[tabId] : 'global');
|
windowId = windowId || (tabId ? tabs[tabId] : 'global');
|
||||||
log('ua.object is called', tabId, windowId, cookieStoreId);
|
log('ua.object is called', tabId, windowId, cookieStoreId);
|
||||||
|
|
||||||
|
@ -255,13 +255,7 @@ const ua = {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update(str = prefs.ua, windowId = 'global', cookieStoreId = 'default-container') {
|
update(str = prefs.ua, windowId = 'global', cookieStoreId = DCSI) {
|
||||||
|
|
||||||
console.log(new Error().stack, cookieStoreId);
|
|
||||||
console.log(str, prefs.mode === 'custom', this.windows.length, Object.keys(this._obj).length);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
log('ua.update is called', str, windowId, cookieStoreId);
|
log('ua.update is called', str, windowId, cookieStoreId);
|
||||||
// clear caching
|
// clear caching
|
||||||
Object.keys(cache).forEach(key => delete cache[key]);
|
Object.keys(cache).forEach(key => delete cache[key]);
|
||||||
|
@ -270,7 +264,6 @@ const ua = {
|
||||||
chrome.webNavigation.onCommitted.removeListener(onCommitted);
|
chrome.webNavigation.onCommitted.removeListener(onCommitted);
|
||||||
// apply new ones
|
// apply new ones
|
||||||
if (str || prefs.mode === 'custom' || this.windows.length || Object.keys(this._obj).length) {
|
if (str || prefs.mode === 'custom' || this.windows.length || Object.keys(this._obj).length) {
|
||||||
console.log('reinstall');
|
|
||||||
if (str) {
|
if (str) {
|
||||||
ua.string(str, windowId, cookieStoreId);
|
ua.string(str, windowId, cookieStoreId);
|
||||||
}
|
}
|
||||||
|
@ -298,13 +291,10 @@ const ua = {
|
||||||
window.ua = ua; // using from popup
|
window.ua = ua; // using from popup
|
||||||
// make sure to clean on window removal
|
// make sure to clean on window removal
|
||||||
if (chrome.windows) { // FF on Android
|
if (chrome.windows) { // FF on Android
|
||||||
console.log('windowId');
|
|
||||||
chrome.windows.onRemoved.addListener(windowId => {
|
chrome.windows.onRemoved.addListener(windowId => {
|
||||||
console.log(windowId, Object.keys(ua._obj), ua._obj);
|
|
||||||
let update = false;
|
let update = false;
|
||||||
Object.keys(ua._obj).forEach(cookieStoreId => {
|
Object.keys(ua._obj).forEach(cookieStoreId => {
|
||||||
if (windowId in ua._obj[cookieStoreId]) {
|
if (windowId in ua._obj[cookieStoreId]) {
|
||||||
console.log('DELETE from windows', cookieStoreId);
|
|
||||||
delete ua._obj[cookieStoreId][windowId];
|
delete ua._obj[cookieStoreId][windowId];
|
||||||
// delete the entire object if it is empty
|
// delete the entire object if it is empty
|
||||||
if (Object.keys(ua._obj[cookieStoreId]).length === 0) {
|
if (Object.keys(ua._obj[cookieStoreId]).length === 0) {
|
||||||
|
@ -313,7 +303,6 @@ if (chrome.windows) { // FF on Android
|
||||||
update = true;
|
update = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log('upda', update);
|
|
||||||
// if nothing is left to monitor, disable the extension
|
// if nothing is left to monitor, disable the extension
|
||||||
if (update) {
|
if (update) {
|
||||||
currentCookieStoreId().then(cookieStoreId => ua.update(undefined, undefined, cookieStoreId));
|
currentCookieStoreId().then(cookieStoreId => ua.update(undefined, undefined, cookieStoreId));
|
||||||
|
@ -344,7 +333,7 @@ function hostname(url) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// returns true, false or an object; true: ignore, false: use from ua object.
|
// returns true, false or an object; true: ignore, false: use from ua object.
|
||||||
function match({url, tabId, cookieStoreId = 'default-container'}) {
|
function match({url, tabId, cookieStoreId = DCSI}) {
|
||||||
log('match', url, tabId, cookieStoreId);
|
log('match', url, tabId, cookieStoreId);
|
||||||
const h = hostname(url);
|
const h = hostname(url);
|
||||||
|
|
||||||
|
@ -413,8 +402,11 @@ function match({url, tabId, cookieStoreId = 'default-container'}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const onBeforeSendHeaders = d => {
|
const onBeforeSendHeaders = d => {
|
||||||
const {tabId, url, requestHeaders, type, cookieStoreId} = d;
|
const {tabId, url, requestHeaders, type} = d;
|
||||||
|
const cookieStoreId = d.cookieStoreId || cookieStoreIds[tabId] || DCSI;
|
||||||
|
|
||||||
if (type === 'main_frame' || prefs.cache === false) {
|
if (type === 'main_frame' || prefs.cache === false) {
|
||||||
|
cookieStoreIds[tabId] = cookieStoreId;
|
||||||
cache[tabId] = match({url, tabId, cookieStoreId});
|
cache[tabId] = match({url, tabId, cookieStoreId});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,7 +416,7 @@ const onBeforeSendHeaders = d => {
|
||||||
if (prefs.protected.some(s => url.indexOf(s) !== -1)) {
|
if (prefs.protected.some(s => url.indexOf(s) !== -1)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const o = (cache[tabId] || ua.object(tabId, undefined, d.cookieStoreId));
|
const o = (cache[tabId] || ua.object(tabId, undefined, cookieStoreId));
|
||||||
const str = o ? o.userAgent : '';
|
const str = o ? o.userAgent : '';
|
||||||
if (str) {
|
if (str) {
|
||||||
for (let i = 0, name = requestHeaders[0].name; i < requestHeaders.length; i += 1, name = (requestHeaders[i] || {}).name) {
|
for (let i = 0, name = requestHeaders[0].name; i < requestHeaders.length; i += 1, name = (requestHeaders[i] || {}).name) {
|
||||||
|
@ -440,14 +432,14 @@ const onBeforeSendHeaders = d => {
|
||||||
|
|
||||||
const onCommitted = d => {
|
const onCommitted = d => {
|
||||||
const {frameId, url, tabId} = d;
|
const {frameId, url, tabId} = d;
|
||||||
const cookieStoreId = cookieStoreIds[tabId] || 'default-container';
|
const cookieStoreId = d.cookieStoreId || cookieStoreIds[tabId] || DCSI;
|
||||||
|
|
||||||
if (url && (url.startsWith('http') || url.startsWith('ftp')) || url === 'about:blank') {
|
if (url && (url.startsWith('http') || url.startsWith('ftp')) || url === 'about:blank') {
|
||||||
if (cache[tabId] === true) {
|
if (cache[tabId] === true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const o = cache[tabId] || ua.object(tabId, undefined, cookieStoreId);
|
const o = cache[tabId] || ua.object(tabId, undefined, cookieStoreId);
|
||||||
if (o.userAgent) {
|
if (o && o.userAgent) {
|
||||||
chrome.tabs.executeScript(tabId, {
|
chrome.tabs.executeScript(tabId, {
|
||||||
runAt: 'document_start',
|
runAt: 'document_start',
|
||||||
frameId,
|
frameId,
|
||||||
|
@ -498,6 +490,15 @@ chrome.contextMenus.onClicked.addListener(info => chrome.storage.local.set({
|
||||||
mode: info.menuItemId
|
mode: info.menuItemId
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// restore container agents
|
||||||
|
chrome.storage.local.get({
|
||||||
|
'container-uas': {}
|
||||||
|
}, prefs => {
|
||||||
|
for (const cookieStoreId of Object.keys(prefs['container-uas'])) {
|
||||||
|
ua.string(prefs['container-uas'][cookieStoreId], 'global', cookieStoreId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/* FAQs & Feedback */
|
/* FAQs & Feedback */
|
||||||
{
|
{
|
||||||
const {management, runtime: {onInstalled, setUninstallURL, getManifest}, storage, tabs} = chrome;
|
const {management, runtime: {onInstalled, setUninstallURL, getManifest}, storage, tabs} = chrome;
|
||||||
|
|
|
@ -126,10 +126,10 @@
|
||||||
<input type="button" value="Restart" title="Click to reload the extension. This will cause all the window-based user-agent strings to be cleared" data-cmd="reload">
|
<input type="button" value="Restart" title="Click to reload the extension. This will cause all the window-based user-agent strings to be cleared" data-cmd="reload">
|
||||||
<input type="button" value="Refresh Tab" title="Refresh the current page" data-cmd="refresh">
|
<input type="button" value="Refresh Tab" title="Refresh the current page" data-cmd="refresh">
|
||||||
<input type="button" value="Reset" title="Reset browser's user-agent string to the default one. This will not reset window-based UA strings. To reset them, use the 'Restart' button" data-cmd="reset">
|
<input type="button" value="Reset" title="Reset browser's user-agent string to the default one. This will not reset window-based UA strings. To reset them, use the 'Restart' button" data-cmd="reset">
|
||||||
<input type="button" value="Test" title="Test your user-agent string" data-cmd="test">
|
<input type="button" value="Test UA" title="Test your user-agent string" data-cmd="test">
|
||||||
<input type="button" value="Support Containers" title="Allow the extension to access your browser's containers. If this permission is granted, tabs inside isolated containers do not follow the default container's user-agent string. You need to set this string for each new container." data-cmd="container" class="hide">
|
<input type="button" value="Consider Containers" title="Allow the extension to access your browser's containers. If this permission is granted, tabs inside isolated containers do not follow the default container's user-agent string. You need to set this string for each new container." data-cmd="container" class="hide">
|
||||||
<input type="button" value="Window" title="Set this user-agent string for all tabs inside the current window" data-cmd="window">
|
<input type="button" value="Apply (active window)" title="Set this user-agent string for all tabs inside the current window" data-cmd="window">
|
||||||
<input type="button" value="Apply" title="Set this user-agent string as the browser's User-Agent string" data-cmd="apply">
|
<input type="button" value="Apply (all windows)" title="Set this user-agent string as the browser's User-Agent string" data-cmd="apply">
|
||||||
</div>
|
</div>
|
||||||
<script src="index.js"></script>
|
<script src="index.js"></script>
|
||||||
<script async src="matched.js"></script>
|
<script async src="matched.js"></script>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const DCSI = 'firefox-default';
|
||||||
|
|
||||||
document.body.dataset.android = navigator.userAgent.indexOf('Android') !== -1;
|
document.body.dataset.android = navigator.userAgent.indexOf('Android') !== -1;
|
||||||
|
|
||||||
let tab = {};
|
let tab = {};
|
||||||
|
@ -12,15 +14,15 @@ chrome.tabs.query({
|
||||||
tab = tbs[0];
|
tab = tbs[0];
|
||||||
if ('cookieStoreId' in tab) {
|
if ('cookieStoreId' in tab) {
|
||||||
const apply = document.querySelector('[data-cmd="apply"]');
|
const apply = document.querySelector('[data-cmd="apply"]');
|
||||||
apply.value += ' (CNT)';
|
apply.value = 'Apply (container)';
|
||||||
apply.title = 'Set this user-agent string as the current container\'s User-Agent string';
|
apply.title = 'Set this user-agent string as the current container\'s User-Agent string';
|
||||||
|
|
||||||
const w = document.querySelector('[data-cmd="window"]');
|
const w = document.querySelector('[data-cmd="window"]');
|
||||||
w.value += ' (CNT)';
|
w.value = 'Apply (container on window)';
|
||||||
w.title = 'Set this user-agent string for all tabs inside the current window\'s container';
|
w.title = 'Set this user-agent string for all tabs inside the current window\'s container';
|
||||||
|
|
||||||
const reset = document.querySelector('[data-cmd="reset"]');
|
const reset = document.querySelector('[data-cmd="reset"]');
|
||||||
reset.value += ' (CNT)';
|
reset.value = 'Reset (container)';
|
||||||
reset.title = 'Reset the container\'s user-agent string to the default one. This will not reset window-based UA strings. To reset them, use the \'Restart\' button';
|
reset.title = 'Reset the container\'s user-agent string to the default one. This will not reset window-based UA strings. To reset them, use the \'Restart\' button';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,9 +254,23 @@ document.addEventListener('click', ({target}) => {
|
||||||
msg('User-Agent is Set');
|
msg('User-Agent is Set');
|
||||||
}
|
}
|
||||||
if (value !== navigator.userAgent) {
|
if (value !== navigator.userAgent) {
|
||||||
chrome.storage.local.set({
|
// prevent a container ua string from overwriting the default one
|
||||||
ua: value
|
console.log(tab);
|
||||||
});
|
if ('cookieStoreId' in tab && tab.cookieStoreId !== DCSI) {
|
||||||
|
chrome.runtime.getBackgroundPage(bg => bg.ua.update(value, undefined, tab.cookieStoreId));
|
||||||
|
chrome.storage.local.get({
|
||||||
|
'container-uas': {}
|
||||||
|
}, prefs => {
|
||||||
|
prefs['container-uas'][tab.cookieStoreId] = value;
|
||||||
|
chrome.storage.local.set(prefs);
|
||||||
|
console.log(prefs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
chrome.storage.local.set({
|
||||||
|
ua: value
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cmd === 'window') {
|
else if (cmd === 'window') {
|
||||||
|
@ -266,10 +282,27 @@ document.addEventListener('click', ({target}) => {
|
||||||
if (input) {
|
if (input) {
|
||||||
input.checked = false;
|
input.checked = false;
|
||||||
}
|
}
|
||||||
chrome.storage.local.set({
|
// prevent a container ua string from overwriting the default one
|
||||||
ua: ''
|
if ('cookieStoreId' in tab && tab.cookieStoreId !== DCSI) {
|
||||||
});
|
chrome.runtime.getBackgroundPage(bg => {
|
||||||
msg('Disabled. Uses the default user-agent string');
|
delete bg.ua._obj[tab.cookieStoreId];
|
||||||
|
bg.ua.update('', undefined, tab.cookieStoreId);
|
||||||
|
});
|
||||||
|
chrome.storage.local.get({
|
||||||
|
'container-uas': {}
|
||||||
|
}, prefs => {
|
||||||
|
delete prefs['container-uas'][tab.cookieStoreId];
|
||||||
|
chrome.storage.local.set(prefs);
|
||||||
|
});
|
||||||
|
|
||||||
|
msg('Disabled on this container. Uses the default user-agent string');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
chrome.storage.local.set({
|
||||||
|
ua: ''
|
||||||
|
});
|
||||||
|
msg('Disabled. Uses the default user-agent string');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (cmd === 'refresh') {
|
else if (cmd === 'refresh') {
|
||||||
chrome.tabs.query({
|
chrome.tabs.query({
|
||||||
|
@ -328,7 +361,7 @@ document.querySelector('[data-cmd="container"]').addEventListener('click', e =>
|
||||||
permissions: ['cookies']
|
permissions: ['cookies']
|
||||||
}, granted => {
|
}, granted => {
|
||||||
if (granted) {
|
if (granted) {
|
||||||
e.target.classList.add('hide');
|
window.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -53,7 +53,8 @@
|
||||||
"homepage_url": "https://add0n.com/useragent-switcher.html",
|
"homepage_url": "https://add0n.com/useragent-switcher.html",
|
||||||
"options_ui": {
|
"options_ui": {
|
||||||
"page": "data/options/index.html",
|
"page": "data/options/index.html",
|
||||||
"chrome_style": true
|
"chrome_style": true,
|
||||||
|
"open_in_tab": true
|
||||||
},
|
},
|
||||||
"content_scripts": [{
|
"content_scripts": [{
|
||||||
"all_frames": true,
|
"all_frames": true,
|
||||||
|
|
Loading…
Reference in a new issue