supporting custom ua string per container; part 2
This commit is contained in:
parent
2a317e5aec
commit
92773630cd
4 changed files with 144 additions and 62 deletions
|
@ -3,7 +3,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
const cache = {};
|
const cache = {}; // cache how a tab's request get handled (true, false, object)
|
||||||
const tabs = {};
|
const tabs = {};
|
||||||
const cookieStoreIds = {};
|
const cookieStoreIds = {};
|
||||||
chrome.tabs.onRemoved.addListener(id => {
|
chrome.tabs.onRemoved.addListener(id => {
|
||||||
|
@ -47,22 +47,35 @@ const expand = () => {
|
||||||
};
|
};
|
||||||
expand.rules = {};
|
expand.rules = {};
|
||||||
|
|
||||||
|
const currentCookieStoreId = () => new Promise(resolve => chrome.tabs.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true
|
||||||
|
}, tbs => {
|
||||||
|
resolve((tbs.length ? tbs[0].cookieStoreId : '') || 'firefox-default');
|
||||||
|
}));
|
||||||
|
|
||||||
chrome.storage.local.get(prefs, ps => {
|
chrome.storage.local.get(prefs, ps => {
|
||||||
Object.assign(prefs, ps);
|
Object.assign(prefs, ps);
|
||||||
// update prefs.ua from the managed storage
|
expand();
|
||||||
chrome.storage.managed.get({
|
|
||||||
ua: ''
|
chrome.tabs.query({}, ts => {
|
||||||
}, rps => {
|
ts.forEach(t => {
|
||||||
if (!chrome.runtime.lastError && rps.ua) {
|
tabs[t.id] = t.windowId;
|
||||||
prefs.ua = rps.ua;
|
cookieStoreIds[t.id] = t.cookieStoreId;
|
||||||
}
|
});
|
||||||
expand();
|
|
||||||
chrome.tabs.query({}, ts => {
|
// update prefs.ua from the managed storage
|
||||||
ts.forEach(t => {
|
chrome.storage.managed.get({
|
||||||
tabs[t.id] = t.windowId;
|
ua: ''
|
||||||
cookieStoreIds[t.id] = t.cookieStoreId;
|
}, rps => {
|
||||||
});
|
if (!chrome.runtime.lastError && rps.ua) {
|
||||||
ua.update();
|
chrome.storage.local.set({
|
||||||
|
ua: rps.ua
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ua.update(undefined, undefined, 'firefox-default');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -96,8 +109,17 @@ chrome.storage.local.get(prefs, ps => {
|
||||||
});
|
});
|
||||||
chrome.storage.onChanged.addListener(ps => {
|
chrome.storage.onChanged.addListener(ps => {
|
||||||
Object.keys(ps).forEach(key => prefs[key] = ps[key].newValue);
|
Object.keys(ps).forEach(key => prefs[key] = ps[key].newValue);
|
||||||
|
|
||||||
if (ps.ua || ps.mode) {
|
if (ps.ua || ps.mode) {
|
||||||
ua.update();
|
currentCookieStoreId().then(cookieStoreId => {
|
||||||
|
if (ps.ua) {
|
||||||
|
if (ps.ua.newValue === '') {
|
||||||
|
console.log('delete from onChanged', cookieStoreId);
|
||||||
|
delete ua._obj[cookieStoreId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ua.update(undefined, undefined, cookieStoreId);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (ps.custom) {
|
if (ps.custom) {
|
||||||
expand();
|
expand();
|
||||||
|
@ -176,9 +198,8 @@ const ua = {
|
||||||
log('ua.object is called', tabId, windowId, cookieStoreId);
|
log('ua.object is called', tabId, windowId, cookieStoreId);
|
||||||
|
|
||||||
if (this._obj[cookieStoreId]) {
|
if (this._obj[cookieStoreId]) {
|
||||||
return this._obj[cookieStoreId][windowId] || this._obj[cookieStoreId].global || this._obj['default-container'].global;
|
return this._obj[cookieStoreId][windowId] || this._obj[cookieStoreId].global;
|
||||||
}
|
}
|
||||||
return (this._obj['default-container'] || {}).global;
|
|
||||||
},
|
},
|
||||||
string(str, windowId, cookieStoreId) {
|
string(str, windowId, cookieStoreId) {
|
||||||
log('ua.string is called', str, windowId);
|
log('ua.string is called', str, windowId);
|
||||||
|
@ -219,20 +240,28 @@ const ua = {
|
||||||
windowId
|
windowId
|
||||||
}, tabs => tabs.forEach(tab => {
|
}, tabs => tabs.forEach(tab => {
|
||||||
const tabId = tab.id;
|
const tabId = tab.id;
|
||||||
|
const o = ua.object(null, windowId, tab.cookieStoreId);
|
||||||
chrome.browserAction.setBadgeText({
|
chrome.browserAction.setBadgeText({
|
||||||
tabId,
|
tabId,
|
||||||
text: ua.object(null, windowId, tab.cookieStoreId).platform.substr(0, 3)
|
text: o && o.platform ? o.platform.substr(0, 3) : ''
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
else if (tabId) {
|
else if (tabId) {
|
||||||
|
const o = ua.object(tabId, undefined, cookieStoreId);
|
||||||
chrome.browserAction.setBadgeText({
|
chrome.browserAction.setBadgeText({
|
||||||
tabId,
|
tabId,
|
||||||
text: ua.object(tabId, undefined, cookieStoreId).platform.substr(0, 3)
|
text: o.platform ? o.platform.substr(0, 3) : 'BOT'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update(str = prefs.ua, windowId = 'global', cookieStoreId = 'default-container') {
|
update(str = prefs.ua, windowId = 'global', cookieStoreId = 'default-container') {
|
||||||
|
|
||||||
|
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]);
|
||||||
|
@ -240,8 +269,11 @@ const ua = {
|
||||||
chrome.webRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
chrome.webRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
||||||
chrome.webNavigation.onCommitted.removeListener(onCommitted);
|
chrome.webNavigation.onCommitted.removeListener(onCommitted);
|
||||||
// apply new ones
|
// apply new ones
|
||||||
if (str || prefs.mode === 'custom' || this.windows.length) {
|
if (str || prefs.mode === 'custom' || this.windows.length || Object.keys(this._obj).length) {
|
||||||
ua.string(str, windowId, cookieStoreId);
|
console.log('reinstall');
|
||||||
|
if (str) {
|
||||||
|
ua.string(str, windowId, cookieStoreId);
|
||||||
|
}
|
||||||
chrome.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {
|
chrome.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {
|
||||||
'urls': ['*://*/*']
|
'urls': ['*://*/*']
|
||||||
}, ['blocking', 'requestHeaders']);
|
}, ['blocking', 'requestHeaders']);
|
||||||
|
@ -266,10 +298,26 @@ 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;
|
||||||
Object.keys(ua._obj).forEach(cookieStoreId => {
|
Object.keys(ua._obj).forEach(cookieStoreId => {
|
||||||
delete ua._obj[cookieStoreId][windowId];
|
if (windowId in ua._obj[cookieStoreId]) {
|
||||||
|
console.log('DELETE from windows', cookieStoreId);
|
||||||
|
delete ua._obj[cookieStoreId][windowId];
|
||||||
|
// delete the entire object if it is empty
|
||||||
|
if (Object.keys(ua._obj[cookieStoreId]).length === 0) {
|
||||||
|
delete ua._obj[cookieStoreId];
|
||||||
|
}
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
console.log('upda', update);
|
||||||
|
// if nothing is left to monitor, disable the extension
|
||||||
|
if (update) {
|
||||||
|
currentCookieStoreId().then(cookieStoreId => ua.update(undefined, undefined, cookieStoreId));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,7 +417,6 @@ const onBeforeSendHeaders = d => {
|
||||||
if (type === 'main_frame' || prefs.cache === false) {
|
if (type === 'main_frame' || prefs.cache === false) {
|
||||||
cache[tabId] = match({url, tabId, cookieStoreId});
|
cache[tabId] = match({url, tabId, cookieStoreId});
|
||||||
}
|
}
|
||||||
console.log(cache[tabId]);
|
|
||||||
|
|
||||||
if (cache[tabId] === true) {
|
if (cache[tabId] === true) {
|
||||||
return {};
|
return {};
|
||||||
|
@ -377,7 +424,8 @@ const onBeforeSendHeaders = d => {
|
||||||
if (prefs.protected.some(s => url.indexOf(s) !== -1)) {
|
if (prefs.protected.some(s => url.indexOf(s) !== -1)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const str = (cache[tabId] || ua.object(tabId, undefined, d.cookieStoreId)).userAgent;
|
const o = (cache[tabId] || ua.object(tabId, undefined, d.cookieStoreId));
|
||||||
|
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) {
|
||||||
if (name === 'User-Agent' || name === 'user-agent') {
|
if (name === 'User-Agent' || name === 'user-agent') {
|
||||||
|
|
|
@ -190,11 +190,14 @@ select {
|
||||||
background-color: #4d72b7;
|
background-color: #4d72b7;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
[data-cmd="container"],
|
[data-cmd="container"] {
|
||||||
|
background-color: #92773c;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
[data-cmd="window"],
|
[data-cmd="window"],
|
||||||
[data-cmd="apply"] {
|
[data-cmd="apply"] {
|
||||||
color: #fff;
|
|
||||||
background-color: #3c923c;
|
background-color: #3c923c;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-cmd="reset"] {
|
[data-cmd="reset"] {
|
||||||
|
@ -242,3 +245,7 @@ body[data-android="true"] [data-cmd="window"] {
|
||||||
#toast:empty {
|
#toast:empty {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
<td>userAgent</td>
|
<td>userAgent</td>
|
||||||
<td colspan="3">
|
<td colspan="3">
|
||||||
<div hbox>
|
<div hbox>
|
||||||
<input id="ua" type="text" placeholder="Your preferred user-agent string" title="To set a blank user-agent string, use the 'empty' keyword. To construct a custom user-agent string based on the current browser's navigator object, use ${} notation. Whatever is inside this notation is read from the 'navigator' object. For instance, to append a string to the default user-agent, use '${userAgent} THIS IS THE APPENDED STRING'">
|
<input id="ua" type="text" autofocus placeholder="Your preferred user-agent string" title="To set a blank user-agent string, use the 'empty' keyword. To construct a custom user-agent string based on the current browser's navigator object, use ${} notation. Whatever is inside this notation is read from the 'navigator' object. For instance, to append a string to the default user-agent, use '${userAgent} THIS IS THE APPENDED STRING'">
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -125,11 +125,11 @@
|
||||||
<input type="button" value="Options" title="Open options page" style="margin-left: 2px;" data-cmd="options">
|
<input type="button" value="Options" title="Open options page" style="margin-left: 2px;" data-cmd="options">
|
||||||
<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 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" title="Test your user-agent string" data-cmd="test">
|
||||||
<input type="button" value="Container" title="Set this string as this container's User-Agent string" data-cmd="container">
|
<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="Window" title="Set this string as this window's User-Agent string" data-cmd="window">
|
<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" title="Set this string as the browser's User-Agent string" data-cmd="apply">
|
<input type="button" value="Apply" 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>
|
||||||
|
|
|
@ -2,6 +2,30 @@
|
||||||
|
|
||||||
document.body.dataset.android = navigator.userAgent.indexOf('Android') !== -1;
|
document.body.dataset.android = navigator.userAgent.indexOf('Android') !== -1;
|
||||||
|
|
||||||
|
let tab = {};
|
||||||
|
|
||||||
|
chrome.tabs.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true
|
||||||
|
}, tbs => {
|
||||||
|
if (tbs.length) {
|
||||||
|
tab = tbs[0];
|
||||||
|
if ('cookieStoreId' in tab) {
|
||||||
|
const apply = document.querySelector('[data-cmd="apply"]');
|
||||||
|
apply.value += ' (CNT)';
|
||||||
|
apply.title = 'Set this user-agent string as the current container\'s User-Agent string';
|
||||||
|
|
||||||
|
const w = document.querySelector('[data-cmd="window"]');
|
||||||
|
w.value += ' (CNT)';
|
||||||
|
w.title = 'Set this user-agent string for all tabs inside the current window\'s container';
|
||||||
|
|
||||||
|
const reset = document.querySelector('[data-cmd="reset"]');
|
||||||
|
reset.value += ' (CNT)';
|
||||||
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const map = {};
|
const map = {};
|
||||||
|
|
||||||
function sort(arr) {
|
function sort(arr) {
|
||||||
|
@ -227,37 +251,15 @@ document.addEventListener('click', ({target}) => {
|
||||||
else {
|
else {
|
||||||
msg('User-Agent is Set');
|
msg('User-Agent is Set');
|
||||||
}
|
}
|
||||||
chrome.storage.local.set({
|
if (value !== navigator.userAgent) {
|
||||||
ua: '' // since we set from managed storage, the value might already be this one and hence onChanged is not being called
|
chrome.storage.local.set({
|
||||||
}, () => {
|
ua: value
|
||||||
if (value !== navigator.userAgent) {
|
});
|
||||||
chrome.storage.local.set({
|
}
|
||||||
ua: value
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else if (cmd === 'window' || cmd === 'container') {
|
else if (cmd === 'window') {
|
||||||
const value = document.getElementById('ua').value;
|
const value = document.getElementById('ua').value;
|
||||||
const next = () => chrome.tabs.query({
|
chrome.runtime.getBackgroundPage(bg => bg.ua.update(value, tab.windowId, tab.cookieStoreId));
|
||||||
active: true,
|
|
||||||
currentWindow: true
|
|
||||||
}, ([tab]) => {
|
|
||||||
if (cmd === 'window') {
|
|
||||||
chrome.runtime.getBackgroundPage(bg => bg.ua.update(value, tab.windowId, tab.cookieStoreId));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
chrome.runtime.getBackgroundPage(bg => bg.ua.update(value, undefined, tab.cookieStoreId));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (cmd === 'container') {
|
|
||||||
chrome.permissions.request({
|
|
||||||
permissions: ['cookies']
|
|
||||||
}, granted => granted && next());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (cmd === 'reset') {
|
else if (cmd === 'reset') {
|
||||||
const input = document.querySelector('#list :checked');
|
const input = document.querySelector('#list :checked');
|
||||||
|
@ -267,7 +269,7 @@ document.addEventListener('click', ({target}) => {
|
||||||
chrome.storage.local.set({
|
chrome.storage.local.set({
|
||||||
ua: ''
|
ua: ''
|
||||||
});
|
});
|
||||||
msg('Reset to Default');
|
msg('Disabled. Uses the default user-agent string');
|
||||||
}
|
}
|
||||||
else if (cmd === 'refresh') {
|
else if (cmd === 'refresh') {
|
||||||
chrome.tabs.query({
|
chrome.tabs.query({
|
||||||
|
@ -314,3 +316,28 @@ document.getElementById('ua').addEventListener('input', e => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
document.getElementById('ua').addEventListener('keyup', e => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
document.querySelector('[data-cmd="apply"]').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* container support */
|
||||||
|
document.querySelector('[data-cmd="container"]').addEventListener('click', e => {
|
||||||
|
chrome.permissions.request({
|
||||||
|
permissions: ['cookies']
|
||||||
|
}, granted => {
|
||||||
|
if (granted) {
|
||||||
|
e.target.classList.add('hide');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (/Firefox/.test(navigator.userAgent)) {
|
||||||
|
chrome.permissions.contains({
|
||||||
|
permissions: ['cookies']
|
||||||
|
}, granted => {
|
||||||
|
if (granted === false) {
|
||||||
|
document.querySelector('[data-cmd="container"]').classList.remove('hide');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue