version 0.3.3
This commit is contained in:
parent
b99fd158bb
commit
b866177b86
9 changed files with 59 additions and 26 deletions
|
@ -1,2 +1,2 @@
|
||||||
ua-parser.min.js:
|
ua-parser.min.js:
|
||||||
https://github.com/faisalman/ua-parser-js/releases/tag/0.7.19
|
https://github.com/faisalman/ua-parser-js/releases/tag/0.7.20
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
const cache = {};
|
const cache = {};
|
||||||
const tabs = {};
|
const tabs = {};
|
||||||
chrome.tabs.onRemoved.addListener(id => delete cache[id]);
|
chrome.tabs.onRemoved.addListener(id => delete cache[id]);
|
||||||
|
@ -17,10 +18,15 @@ const prefs = {
|
||||||
cache: true,
|
cache: true,
|
||||||
exactMatch: false,
|
exactMatch: false,
|
||||||
protected: ['google.com/recaptcha', 'gstatic.com/recaptcha'],
|
protected: ['google.com/recaptcha', 'gstatic.com/recaptcha'],
|
||||||
parser: {} // maps ua string to a ua object
|
parser: {}, // maps ua string to a ua object,
|
||||||
|
log: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const log = (...args) => prefs.log && console.log(...args);
|
||||||
|
|
||||||
// exand comma-separated keys of prefs.custom
|
// exand comma-separated keys of prefs.custom
|
||||||
const expand = () => {
|
const expand = () => {
|
||||||
|
log('expanding custom rules');
|
||||||
expand.rules = {};
|
expand.rules = {};
|
||||||
for (const key of Object.keys(prefs.custom)) {
|
for (const key of Object.keys(prefs.custom)) {
|
||||||
for (const k of key.split(/\s*,\s*/)) {
|
for (const k of key.split(/\s*,\s*/)) {
|
||||||
|
@ -82,14 +88,18 @@ const ua = {
|
||||||
'global': {}
|
'global': {}
|
||||||
},
|
},
|
||||||
diff(tabId) { // returns true if there is per window object
|
diff(tabId) { // returns true if there is per window object
|
||||||
|
log('ua.diff is called', tabId);
|
||||||
const windowId = tabs[tabId];
|
const windowId = tabs[tabId];
|
||||||
return windowId in this._obj;
|
return windowId in this._obj;
|
||||||
},
|
},
|
||||||
get windows() {
|
get windows() {
|
||||||
|
log('ua.windows is called');
|
||||||
return Object.keys(this._obj).filter(id => id !== 'global').map(s => Number(s));
|
return Object.keys(this._obj).filter(id => id !== 'global').map(s => Number(s));
|
||||||
},
|
},
|
||||||
parse: s => {
|
parse: s => {
|
||||||
|
log('ua.parse is called', s);
|
||||||
if (prefs.parser[s]) {
|
if (prefs.parser[s]) {
|
||||||
|
log('ua.parse is resolved using parser');
|
||||||
return Object.assign({
|
return Object.assign({
|
||||||
userAgent: s
|
userAgent: s
|
||||||
}, prefs.parser[s]);
|
}, prefs.parser[s]);
|
||||||
|
@ -140,10 +150,12 @@ const ua = {
|
||||||
return o;
|
return o;
|
||||||
},
|
},
|
||||||
object(tabId, windowId) {
|
object(tabId, windowId) {
|
||||||
|
log('ua.object is called', tabId, windowId);
|
||||||
windowId = windowId || (tabId ? tabs[tabId] : 'global');
|
windowId = windowId || (tabId ? tabs[tabId] : 'global');
|
||||||
return this._obj[windowId] || this._obj.global;
|
return this._obj[windowId] || this._obj.global;
|
||||||
},
|
},
|
||||||
string(str, windowId) {
|
string(str, windowId) {
|
||||||
|
log('ua.string is called', str, windowId);
|
||||||
if (str) {
|
if (str) {
|
||||||
this._obj[windowId] = this.parse(str);
|
this._obj[windowId] = this.parse(str);
|
||||||
}
|
}
|
||||||
|
@ -152,12 +164,14 @@ const ua = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tooltip(title, tabId) {
|
tooltip(title, tabId) {
|
||||||
|
log('ua.tooltip is called', title, tabId);
|
||||||
chrome.browserAction.setTitle({
|
chrome.browserAction.setTitle({
|
||||||
title,
|
title,
|
||||||
tabId
|
tabId
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
icon(mode, tabId) {
|
icon(mode, tabId) {
|
||||||
|
log('ua.icon is called', mode, tabId);
|
||||||
chrome.browserAction.setIcon({
|
chrome.browserAction.setIcon({
|
||||||
tabId,
|
tabId,
|
||||||
path: {
|
path: {
|
||||||
|
@ -172,6 +186,7 @@ const ua = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
toolbar: ({windowId, tabId}) => {
|
toolbar: ({windowId, tabId}) => {
|
||||||
|
log('ua.toolbar is called', windowId, tabId);
|
||||||
if (windowId) {
|
if (windowId) {
|
||||||
chrome.tabs.query({
|
chrome.tabs.query({
|
||||||
windowId
|
windowId
|
||||||
|
@ -191,9 +206,13 @@ const ua = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update(str = prefs.ua, windowId = 'global') {
|
update(str = prefs.ua, windowId = 'global') {
|
||||||
|
log('ua.update is called', str, windowId);
|
||||||
|
// clear caching
|
||||||
|
Object.keys(cache).forEach(key => delete cache[key]);
|
||||||
|
// remove old listeners
|
||||||
chrome.webRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
chrome.webRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
||||||
chrome.webNavigation.onCommitted.removeListener(onCommitted);
|
chrome.webNavigation.onCommitted.removeListener(onCommitted);
|
||||||
|
// apply new ones
|
||||||
if (str || prefs.mode === 'custom' || this.windows.length) {
|
if (str || prefs.mode === 'custom' || this.windows.length) {
|
||||||
ua.string(str, windowId);
|
ua.string(str, windowId);
|
||||||
chrome.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {
|
chrome.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {
|
||||||
|
@ -224,6 +243,7 @@ if (chrome.windows) { // FF on Android
|
||||||
}
|
}
|
||||||
|
|
||||||
function hostname(url) {
|
function hostname(url) {
|
||||||
|
log('hostname', url);
|
||||||
const s = url.indexOf('//') + 2;
|
const s = url.indexOf('//') + 2;
|
||||||
if (s > 1) {
|
if (s > 1) {
|
||||||
let o = url.indexOf('/', s);
|
let o = url.indexOf('/', s);
|
||||||
|
@ -246,6 +266,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}) {
|
function match({url, tabId}) {
|
||||||
|
log('match', url, tabId);
|
||||||
const h = hostname(url);
|
const h = hostname(url);
|
||||||
|
|
||||||
if (prefs.mode === 'blacklist') {
|
if (prefs.mode === 'blacklist') {
|
||||||
|
@ -364,10 +385,16 @@ const onCommitted = ({frameId, url, tabId}) => {
|
||||||
}\`;
|
}\`;
|
||||||
document.documentElement.appendChild(script);
|
document.documentElement.appendChild(script);
|
||||||
script.remove();
|
script.remove();
|
||||||
|
navigator.userAgent
|
||||||
}`
|
}`
|
||||||
}, () => {
|
}, r => {
|
||||||
if (chrome.runtime.lastError) {
|
const lastError = chrome.runtime.lastError;
|
||||||
|
if (lastError &&
|
||||||
|
lastError.message !== 'No matching message handler' && // Firefox on Windows
|
||||||
|
lastError.message !== 'document.documentElement is null' // Firefox on Windows
|
||||||
|
) {
|
||||||
if (frameId === 0) {
|
if (frameId === 0) {
|
||||||
|
console.log(lastError);
|
||||||
ua.tooltip('[Default] ' + navigator.userAgent, tabId);
|
ua.tooltip('[Default] ' + navigator.userAgent, tabId);
|
||||||
ua.icon('ignored', tabId);
|
ua.icon('ignored', tabId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<table width=100%>
|
<table width=100%>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<label><input type="radio" name="mode" value="blacklist" id="mode-blacklist"> <span class="h">Black-list mode</span>: Apply the custom user-agent string to all tabs except the tabs with the following top-level hostnames (comma-separated list of hostnames). Note that even if a window-based user-agent string is set from the toolbar popup, your browser's default user-agent string is used.</label>
|
<label><input type="radio" name="mode" value="blacklist" id="mode-blacklist"> <span class="h">Black-List Mode</span>: Apply the custom user-agent string to all tabs except the tabs with the following top-level hostnames (comma-separated list of hostnames). Note that even if a window-based user-agent string is set from the toolbar popup, your browser's default user-agent string is used.</label>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<label><input type="radio" name="mode" value="whitelist" id="mode-whitelist"> <span class="h">White-list mode</span>: Only apply the custom user-agent string to the tabs with following top-level hostnames. Note that if a window-based user-agent string is set from the toolbar popup, this user-agent will overwrite the global one.</label>
|
<label><input type="radio" name="mode" value="whitelist" id="mode-whitelist"> <span class="h">White-List Mode</span>: Only apply the custom user-agent string to the tabs with following top-level hostnames. Note that if a window-based user-agent string is set from the toolbar popup, this user-agent will overwrite the global one.</label>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -40,20 +40,12 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<label><input type="radio" name="mode" value="custom" id="mode-custom"> <span class="h">Custom mode</span>: Try to resolve the user-agent string from a JSON object; otherwise either use the default user-agent string or use the one that the user is set from the popup interface. Use "*" as the hostname to match all domains. You can randomly select from multiple user-agent strings by providing an array instead of a fixed string. If there is a "_" key in your JSON object which refers to an array of hostnames, then the extension only randomly selects the user-agent string once for each hostname inside this list. This is useful if you don't want the random user-agent to change until this browser session is over.</label> Press <a href="#" id="sample">here</a> to insert a sample JSON object.
|
<label><input type="radio" name="mode" value="custom" id="mode-custom"> <span class="h">Custom Mode</span>: Try to resolve the user-agent string from a JSON object; otherwise either use the default user-agent string or use the one that the user is set from the popup interface. Use "*" as the hostname to match all domains. You can randomly select from multiple user-agent strings by providing an array instead of a fixed string. If there is a "_" key in your JSON object which refers to an array of hostnames, then the extension only randomly selects the user-agent string once for each hostname inside this list. This is useful if you don't want the random user-agent to change until this browser session is over.</label> Press <a href="#" id="sample">here</a> to insert a sample JSON object.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="spacer"><textarea id="custom" rows="5" wrap="off"></textarea></td>
|
<td class="spacer"><textarea id="custom" rows="5" wrap="off"></textarea></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label><span class="h">Custom user-agent string parsing</span>: A JSON object to bypass the internal user-agent string parsing method. The keys are the actual user-agent strings and the value of each key is an object of the keys that need to be set for the "navigator" object. You can use the "[delete]" keyword if you want a key in the "navigator" object to get deleted.</label> Press <a href="#" id="sample-2">here</a> to insert a sample JSON object.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="spacer"><textarea id="parser" rows="5" wrap="off"></textarea></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="spacer"><label><input type="checkbox" id="cache"> Use caching to improve performance (recommended value is true). Uncheck this option only if you are using the custom mode and also you need the user-agent string to be altered from the provided list on every single request.</label></td>
|
<td class="spacer"><label><input type="checkbox" id="cache"> Use caching to improve performance (recommended value is true). Uncheck this option only if you are using the custom mode and also you need the user-agent string to be altered from the provided list on every single request.</label></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -64,11 +56,22 @@
|
||||||
<td class="spacer"><label><input type="checkbox" id="faqs"> Open FAQs page on updates</label></td>
|
<td class="spacer"><label><input type="checkbox" id="faqs"> Open FAQs page on updates</label></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>A comma-separated list of keywords that the extension should not spoof the user-agent header. Use this list to protect URLs that contain these protected keywords. Each keyword need to be at least 5 char long.</td>
|
<td class="spacer"><label><input type="checkbox" id="log"> Display debuging info in the browser console</label></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="h">Disable Spoofing</span> A comma-separated list of keywords that the extension should not spoof the user-agent header. Use this list to protect URLs that contain these protected keywords. Each keyword need to be at least 5 char long.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><textarea id="protected" rows="3" wrap="off"></textarea></td>
|
<td><textarea id="protected" rows="3" wrap="off"></textarea></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="h">Custom User-Agent Parsing</span>: A JSON object to bypass the internal user-agent string parsing method. The keys are the actual user-agent strings and the value of each key is an object of the keys that need to be set for the "navigator" object. You can use the "[delete]" keyword if you want a key in the "navigator" object to get deleted. Press <a href="#" id="sample-2">here</a> to insert a sample JSON object.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="spacer"><textarea id="parser" rows="5" wrap="off"></textarea></td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -43,6 +43,7 @@ function save() {
|
||||||
chrome.storage.local.set({
|
chrome.storage.local.set({
|
||||||
exactMatch: document.getElementById('exactMatch').checked,
|
exactMatch: document.getElementById('exactMatch').checked,
|
||||||
faqs: document.getElementById('faqs').checked,
|
faqs: document.getElementById('faqs').checked,
|
||||||
|
log: document.getElementById('log').checked,
|
||||||
cache: document.getElementById('cache').checked,
|
cache: document.getElementById('cache').checked,
|
||||||
blacklist: prepare(document.getElementById('blacklist').value),
|
blacklist: prepare(document.getElementById('blacklist').value),
|
||||||
whitelist: prepare(document.getElementById('whitelist').value),
|
whitelist: prepare(document.getElementById('whitelist').value),
|
||||||
|
@ -63,6 +64,7 @@ function restore() {
|
||||||
chrome.storage.local.get({
|
chrome.storage.local.get({
|
||||||
exactMatch: false,
|
exactMatch: false,
|
||||||
faqs: true,
|
faqs: true,
|
||||||
|
log: false,
|
||||||
cache: true,
|
cache: true,
|
||||||
mode: 'blacklist',
|
mode: 'blacklist',
|
||||||
whitelist: [],
|
whitelist: [],
|
||||||
|
@ -73,6 +75,7 @@ function restore() {
|
||||||
}, prefs => {
|
}, prefs => {
|
||||||
document.getElementById('exactMatch').checked = prefs.exactMatch;
|
document.getElementById('exactMatch').checked = prefs.exactMatch;
|
||||||
document.getElementById('faqs').checked = prefs.faqs;
|
document.getElementById('faqs').checked = prefs.faqs;
|
||||||
|
document.getElementById('log').checked = prefs.log;
|
||||||
document.getElementById('cache').checked = prefs.cache;
|
document.getElementById('cache').checked = prefs.cache;
|
||||||
document.querySelector(`[name="mode"][value="${prefs.mode}"`).checked = true;
|
document.querySelector(`[name="mode"][value="${prefs.mode}"`).checked = true;
|
||||||
document.getElementById('blacklist').value = prefs.blacklist.join(', ');
|
document.getElementById('blacklist').value = prefs.blacklist.join(', ');
|
||||||
|
|
|
@ -26,7 +26,7 @@ body {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
font-family: "Helvetica Neue", Helvetica, sans-serif;
|
font-family: "Helvetica Neue", Helvetica, sans-serif;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
width: 650px;
|
min-width: 650px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
table {
|
table {
|
||||||
|
@ -89,10 +89,10 @@ select {
|
||||||
#list {
|
#list {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
height: 200px;
|
height: 268px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
color: #000;
|
color: #000;
|
||||||
background-position: top 88px center;
|
background-position: top 120px center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
@ -210,6 +210,7 @@ body[data-android="true"] [data-cmd="window"] {
|
||||||
}
|
}
|
||||||
#view {
|
#view {
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
|
padding: 5px 0;
|
||||||
}
|
}
|
||||||
#view td {
|
#view td {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
|
|
@ -85,7 +85,6 @@ function update(ua) {
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('change', ({target}) => {
|
document.addEventListener('change', ({target}) => {
|
||||||
console.log(target);
|
|
||||||
if (target.closest('#filter')) {
|
if (target.closest('#filter')) {
|
||||||
localStorage.setItem(target.id, target.value);
|
localStorage.setItem(target.id, target.value);
|
||||||
chrome.storage.local.get({
|
chrome.storage.local.get({
|
||||||
|
|
BIN
extension/extension.zip
Normal file
BIN
extension/extension.zip
Normal file
Binary file not shown.
|
@ -2,7 +2,7 @@
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "User-Agent Switcher and Manager",
|
"name": "User-Agent Switcher and Manager",
|
||||||
"short_name": "useragent-switcher",
|
"short_name": "useragent-switcher",
|
||||||
"version": "0.3.2",
|
"version": "0.3.3",
|
||||||
|
|
||||||
"description": "A highly customizable extension to spoof the User-Agent string of your browser with a new one globally, randomly or per hostname",
|
"description": "A highly customizable extension to spoof the User-Agent string of your browser with a new one globally, randomly or per hostname",
|
||||||
|
|
||||||
|
|
8
extension/ua-parser.min.js
vendored
Executable file → Normal file
8
extension/ua-parser.min.js
vendored
Executable file → Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue