/ background.js
background.js
1 'use strict'; 2 var ext_api = (typeof browser === 'object') ? browser : chrome; 3 var url_loc = (typeof browser === 'object') ? 'firefox' : 'chrome'; 4 var manifestData = ext_api.runtime.getManifest(); 5 var ext_name = manifestData.name; 6 var ext_version = manifestData.version; 7 var navigator_ua = navigator.userAgent; 8 var navigator_ua_mobile = navigator_ua.toLowerCase().includes('mobile'); 9 var kiwi_browser = navigator_ua_mobile && (url_loc === 'chrome') && !navigator_ua.toLowerCase().includes('yabrowser'); 10 11 if (typeof ext_api.action !== 'object') { 12 ext_api.action = ext_api.browserAction; 13 } 14 15 var dompurify_sites = []; 16 var optin_setcookie = false; 17 var optin_update = true; 18 var blocked_referer = false; 19 20 // defaultSites are loaded from sites.js at installation extension 21 22 var restrictions = { 23 'bloomberg.com': /^((?!\.bloomberg\.com\/news\/terminal\/).)*$/, 24 'bloombergadria.com': /^((?!\.bloombergadria\.com\/video\/).)*$/, 25 'dailywire.com': /^((?!\.dailywire\.com\/(episode|show|videos|watch)).)*$/, 26 'economictimes.com': /\.economictimes\.com($|\/($|(__assets|prime)(\/.+)?|.+\.cms))/, 27 'elespanol.com': /^((?!\/cronicaglobal\.elespanol\.com\/).)*$/, 28 'espn.com': /^((?!espn\.com\/watch).)*$/, 29 'esquire.com': /^((?!\/classic\.esquire\.com\/).)*$/, 30 'foreignaffairs.com': /^((?!\/reader\.foreignaffairs\.com\/).)*$/, 31 'hilltimes.com': /^((?!hilltimes\.com\/slideshow\/).)*$/, 32 'nytimes.com': /^((?!\/timesmachine\.nytimes\.com\/).)*$/, 33 'science.org': /^((?!\.science\.org\/doi\/).)*$/, 34 'timesofindia.com': /\.timesofindia\.com($|\/($|toi-plus(\/.+)?|.+\.cms))/, 35 'quora.com': /^((?!quora\.com\/search\?q=).)*$/, 36 'seekingalpha.com': /\/seekingalpha\.com($|\/($|(amp\/)?(article|news)\/|samw\/))/, 37 'statista.com': /^((?!\.statista\.com\/study\/).)*$/, 38 'techinasia.com': /\.techinasia\.com\/.+/, 39 'theatlantic.com': /^((?!\/newsletters\.theatlantic\.com\/).)*$/, 40 'thetimes.co.uk': /^((?!epaper\.thetimes\.co\.uk).)*$/, 41 'timeshighereducation.com': /\.timeshighereducation\.com\/((features|news|people)\/|.+((\w)+(\-)+){3,}.+|sites\/default\/files\/)/, 42 'uol.com.br': /^((?!(conta|email)\.uol\.com\.br).)*$/, 43 } 44 45 for (let domain of au_news_corp_domains) 46 restrictions[domain] = new RegExp('^((?!todayspaper\\.' + domain.replace(/\./g, '\\.') + '\\/).)*$'); 47 if (typeof browser !== 'object') { 48 for (let domain of []) 49 restrictions[domain] = new RegExp('((\\/|\\.)' + domain.replace(/\./g, '\\.') + '\\/$|' + restrictions[domain].toString().replace(/(^\/|\/$)/g, '') + ')'); 50 } 51 52 // Don't remove cookies before/after page load 53 var allow_cookies = []; 54 var remove_cookies = []; 55 // select specific cookie(s) to hold/drop from remove_cookies domains 56 var remove_cookies_select_hold, remove_cookies_select_drop; 57 58 // Set User-Agent 59 var use_google_bot, use_bing_bot, use_facebook_bot; 60 // Set Referer 61 var use_facebook_referer, use_google_referer, use_twitter_referer; 62 // Set random IP-address 63 var random_ip = {}; 64 var use_random_ip = []; 65 // concat all sites with change of headers (useragent, referer or random ip) 66 var change_headers; 67 68 // block paywall-scripts 69 var blockedRegexes = {}; 70 var blockedRegexesDomains = []; 71 var blockedRegexesGeneral = {}; 72 var blockedJsInline = {}; 73 var blockedJsInlineDomains = []; 74 75 // unhide text on amp-page 76 var amp_unhide; 77 // redirect to amp-page 78 var amp_redirect; 79 // code for contentScript 80 var cs_code; 81 // load text from json (script[type="application/ld+json"]) 82 var ld_json; 83 // load text from json (script#__NEXT_DATA__) 84 var ld_json_next; 85 // load text from Google webcache 86 var ld_google_webcache; 87 // add external link to article 88 var add_ext_link; 89 90 // custom: block javascript 91 var block_js_custom = []; 92 var block_js_custom_ext = []; 93 94 function initSetRules() { 95 allow_cookies = []; 96 remove_cookies = []; 97 remove_cookies_select_drop = {}; 98 remove_cookies_select_hold = {}; 99 use_google_bot = []; 100 use_bing_bot = []; 101 use_facebook_bot = []; 102 use_facebook_referer = []; 103 use_google_referer = []; 104 use_twitter_referer = []; 105 random_ip = {}; 106 change_headers = []; 107 amp_unhide = []; 108 amp_redirect = {}; 109 cs_code = {}; 110 ld_json = {}; 111 ld_json_next = {}; 112 ld_google_webcache = {}; 113 add_ext_link = {}; 114 block_js_custom = []; 115 block_js_custom_ext = []; 116 blockedRegexes = {}; 117 blockedRegexesDomains = []; 118 blockedRegexesGeneral = {}; 119 blockedJsInline = {}; 120 blockedJsInlineDomains = []; 121 init_custom_flex_domains(); 122 } 123 124 const userAgentDesktopG = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"; 125 const userAgentMobileG = "Chrome/80.0.3987.92 Mobile Safari/537.36 (compatible ; Googlebot/2.1 ; +http://www.google.com/bot.html)"; 126 127 const userAgentDesktopB = "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"; 128 const userAgentMobileB = "Chrome/80.0.3987.92 Mobile Safari/537.36 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"; 129 130 const userAgentDesktopF = 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)'; 131 132 var enabledSites = []; 133 var disabledSites = []; 134 var optionSites = {}; 135 var customSites = {}; 136 var customSites_domains = []; 137 var updatedSites = {}; 138 var updatedSites_new = []; 139 var updatedSites_domains_new = []; 140 var excludedSites = []; 141 142 function setDefaultOptions() { 143 ext_api.storage.local.set({ 144 sites: filterObject(defaultSites, function (val, key) { 145 return val.domain && !val.domain.match(/^(###$|#options_(disable|optin)_)/) 146 }, 147 function (val, key) { 148 return [key, val.domain] 149 }) 150 }, function () { 151 ext_api.runtime.openOptionsPage(); 152 }); 153 } 154 155 function check_sites_updated() { 156 let sites_updated_json = 'https://gitlab.com/magnolia1234/bypass-paywalls-' + url_loc + '-clean/-/raw/master/sites_updated.json'; 157 fetch(sites_updated_json) 158 .then(response => { 159 if (response.ok) { 160 response.json().then(json => { 161 expandSiteRules(json, true); 162 ext_api.storage.local.set({ 163 sites_updated: json 164 }); 165 }) 166 } 167 }).catch(function (err) { 168 false; 169 }); 170 } 171 172 function clear_sites_updated() { 173 ext_api.storage.local.set({ 174 sites_updated: {} 175 }); 176 } 177 178 function prep_regex_str(str, domain = '') { 179 if (domain) 180 str = str.replace(/{domain}/g, domain.replace(/\./g, '\\.')); 181 return str.replace(/^\//, '').replace(/\/\//g, '/').replace(/([^\\])\/$/, "$1") 182 } 183 184 function addRules(domain, rule) { 185 if (rule.hasOwnProperty('remove_cookies_select_drop') || rule.hasOwnProperty('remove_cookies_select_hold')) { 186 rule.allow_cookies = 1; 187 rule.remove_cookies = 1; 188 } 189 if (rule.allow_cookies > 0 && !allow_cookies.includes(domain)) 190 allow_cookies.push(domain); 191 if (rule.remove_cookies > 0 && !remove_cookies.includes(domain)) 192 remove_cookies.push(domain); 193 if (rule.hasOwnProperty('remove_cookies_select_drop')) 194 remove_cookies_select_drop[domain] = rule.remove_cookies_select_drop; 195 if (rule.hasOwnProperty('remove_cookies_select_hold')) 196 remove_cookies_select_hold[domain] = rule.remove_cookies_select_hold; 197 if (rule.hasOwnProperty('block_regex')) { 198 if (rule.block_regex instanceof RegExp) 199 blockedRegexes[domain] = rule.block_regex; 200 else { 201 try { 202 blockedRegexes[domain] = new RegExp(prep_regex_str(rule.block_regex, domain)); 203 } catch (e) { 204 console.log(`regex not valid, error: ${e}`); 205 } 206 } 207 } 208 if (rule.hasOwnProperty('block_regex_general')) { 209 if (rule.block_regex_general instanceof RegExp) 210 blockedRegexesGeneral[domain] = {block_regex: rule.block_regex_general}; 211 else { 212 try { 213 blockedRegexesGeneral[domain] = {block_regex: new RegExp(prep_regex_str(rule.block_regex_general, domain))}; 214 } catch (e) { 215 console.log(`regex not valid, error: ${e}`); 216 } 217 } 218 blockedRegexesGeneral[domain]['excluded_domains'] = rule.excluded_domains ? rule.excluded_domains : []; 219 } 220 if (rule.hasOwnProperty('block_js_inline')) { 221 if (rule.block_js_inline instanceof RegExp) 222 blockedJsInline[domain] = rule.block_js_inline; 223 else { 224 try { 225 blockedJsInline[domain] = new RegExp(prep_regex_str(rule.block_js_inline, domain)); 226 } catch (e) { 227 console.log(`regex not valid, error: ${e}`); 228 } 229 } 230 } 231 if (rule.useragent) { 232 switch (rule.useragent) { 233 case 'googlebot': 234 if (!use_google_bot.includes(domain)) 235 use_google_bot.push(domain); 236 break; 237 case 'bingbot': 238 if (!use_bing_bot.includes(domain)) 239 use_bing_bot.push(domain); 240 break; 241 case 'facebookbot': 242 if (!use_facebook_bot.includes(domain)) 243 use_facebook_bot.push(domain); 244 break; 245 } 246 } 247 if (rule.referer) { 248 switch (rule.referer) { 249 case 'facebook': 250 if (!use_facebook_referer.includes(domain)) 251 use_facebook_referer.push(domain); 252 break; 253 case 'google': 254 if (!use_google_referer.includes(domain)) 255 use_google_referer.push(domain); 256 break; 257 case 'twitter': 258 if (!use_twitter_referer.includes(domain)) 259 use_twitter_referer.push(domain); 260 break; 261 } 262 } 263 if (rule.random_ip) { 264 random_ip[domain] = rule.random_ip; 265 } 266 if (rule.amp_unhide > 0 && !amp_unhide.includes(domain)) 267 amp_unhide.push(domain); 268 if (rule.amp_redirect) 269 amp_redirect[domain] = rule.amp_redirect.paywall ? rule.amp_redirect : {paywall: rule.amp_redirect}; 270 if (rule.cs_code) { 271 if (typeof rule.cs_code === 'string') { 272 try { 273 rule.cs_code = JSON.parse(rule.cs_code); 274 } catch (e) { 275 console.log(`cs_code not valid: ${rule.cs_code} error: ${e}`); 276 } 277 } 278 if (typeof rule.cs_code === 'object') 279 cs_code[domain] = rule.cs_code; 280 } 281 if (rule.ld_json) 282 ld_json[domain] = rule.ld_json; 283 if (rule.ld_json_next) 284 ld_json_next[domain] = rule.ld_json_next; 285 if (rule.ld_google_webcache) 286 ld_google_webcache[domain] = rule.ld_google_webcache; 287 if (rule.ld_json || rule.ld_json_next || rule.ld_google_webcache || rule.cs_dompurify) 288 if (!dompurify_sites.includes(domain)) 289 dompurify_sites.push(domain); 290 if (rule.add_ext_link && rule.add_ext_link_type) 291 add_ext_link[domain] = {css: rule.add_ext_link, type: rule.add_ext_link_type}; 292 293 // custom 294 if (rule.googlebot > 0) 295 use_google_bot.push(domain); // legacy 296 if (rule.block_js > 0 || rule.block_javascript > 0) 297 block_js_custom.push(domain); 298 if (rule.block_js_ext > 0 || rule.block_javascript_ext > 0) 299 block_js_custom_ext.push(domain); 300 } 301 302 function customFlexAddRules(custom_domain, rule) { 303 addRules(custom_domain, rule); 304 if (blockedRegexes[custom_domain]) 305 blockedRegexesDomains.push(custom_domain); 306 if (blockedJsInline[custom_domain]) { 307 blockedJsInlineDomains.push(custom_domain); 308 disableJavascriptInline(); 309 } 310 if (rule.useragent || rule.referer || rule.random_ip) 311 change_headers.push(custom_domain); 312 if (rule.random_ip) 313 use_random_ip.push(custom_domain); 314 ext_api.tabs.reload({bypassCache: true}); 315 } 316 317 function set_rules(sites, sites_updated, sites_custom) { 318 initSetRules(); 319 for (let site in sites) { 320 let site_domain = sites[site].toLowerCase(); 321 let custom = false; 322 if (!site_domain.match(/^(###$|#options_)/)) { 323 let rule = {}; 324 let site_default = defaultSites.hasOwnProperty(site) ? site : Object.keys(defaultSites).find(default_key => compareKey(default_key, site)); 325 if (site_default) { 326 rule = defaultSites[site_default]; 327 let site_updated = Object.keys(sites_updated).find(updated_key => compareKey(updated_key, site)); 328 if (site_updated && !(sites_updated[site_updated].new_site || (sites_updated[site_updated].upd_version && (sites_updated[site_updated].upd_version <= ext_version)))) 329 rule = sites_updated[site_updated]; 330 } else if (sites_updated.hasOwnProperty(site)) { // updated (new) sites 331 rule = sites_updated[site]; 332 } else if (sites_custom.hasOwnProperty(site)) { // custom (new) sites 333 rule = sites_custom[site]; 334 custom = true; 335 } else 336 continue; 337 let domains = [site_domain]; 338 let group = false; 339 if (rule.hasOwnProperty('group')) { 340 domains = rule.group; 341 group = true; 342 } 343 let rule_default = {}; 344 if (rule.hasOwnProperty('exception')) { 345 for (let key in rule) 346 rule_default[key] = rule[key]; 347 } 348 for (let domain of domains) { 349 let custom_in_group = false; 350 if (rule_default.hasOwnProperty('exception')) { 351 let exception_rule = rule_default.exception.filter(x => domain === x.domain || (typeof x.domain !== 'string' && x.domain.includes(domain))); 352 if (exception_rule.length > 0) 353 rule = exception_rule[0]; 354 else 355 rule = rule_default; 356 } 357 // custom domain for default site(group) 358 if (!custom) { 359 let isCustomSite = matchDomain(customSites_domains, domain); 360 let customSite_title = isCustomSite ? Object.keys(customSites).find(key => customSites[key].domain === isCustomSite) : ''; 361 if (customSite_title && !(rule.add_ext_link || ['swarajyamag.com'].includes(isCustomSite))) { 362 // add default block_regex 363 let block_regex_default = ''; 364 if (rule.hasOwnProperty('block_regex')) 365 block_regex_default = rule.block_regex; 366 rule = {}; 367 for (let key in sites_custom[customSite_title]) 368 rule[key] = sites_custom[customSite_title][key]; 369 if (block_regex_default) { 370 if (rule.hasOwnProperty('block_regex')) { 371 if (block_regex_default instanceof RegExp) 372 block_regex_default = block_regex_default.source; 373 rule.block_regex = '(' + block_regex_default + '|' + prep_regex_str(rule.block_regex, domain) + ')'; 374 } else 375 rule.block_regex = block_regex_default; 376 } 377 if (group) 378 custom_in_group = true; 379 else 380 custom = true; 381 } 382 } 383 addRules(domain, rule); 384 } 385 } 386 } 387 blockedRegexesDomains = Object.keys(blockedRegexes); 388 blockedJsInlineDomains = Object.keys(blockedJsInline); 389 disableJavascriptInline(); 390 use_random_ip = Object.keys(random_ip); 391 change_headers = use_google_bot.concat(use_bing_bot, use_facebook_bot, use_facebook_referer, use_google_referer, use_twitter_referer, use_random_ip); 392 } 393 394 // add grouped sites to en/disabledSites (and exclude sites) 395 function add_grouped_enabled_domains(groups) { 396 for (let key in groups) { 397 if (enabledSites.includes(key)) 398 enabledSites = enabledSites.concat(groups[key]); 399 else 400 disabledSites = disabledSites.concat(groups[key]); 401 for (let site of excludedSites) { 402 if (enabledSites.includes(site)) { 403 enabledSites.splice(enabledSites.indexOf(site), 1); 404 disabledSites.push(site); 405 } 406 } 407 } 408 } 409 410 // Get the enabled sites (from local storage) & set_rules for sites 411 ext_api.storage.local.get({ 412 sites: {}, 413 sites_default: Object.keys(defaultSites).filter(x => defaultSites[x].domain && !defaultSites[x].domain.match(/^(#options_|###$)/)), 414 sites_custom: {}, 415 sites_updated: {}, 416 sites_excluded: [], 417 ext_version_old: '2.3.9.0', 418 optIn: false, 419 optInUpdate: true 420 }, function (items) { 421 var sites = items.sites; 422 optionSites = sites; 423 var sites_default = items.sites_default; 424 customSites = items.sites_custom; 425 customSites = filterObject(customSites, function (val, key) { 426 return !(val.add_ext_link && (!val.add_ext_link_type || val.add_ext_link_type === 'google_search_tool')) 427 }); 428 customSites_domains = Object.values(customSites).map(x => x.domain); 429 updatedSites = items.sites_updated; 430 updatedSites_domains_new = Object.values(updatedSites).filter(x => (x.domain && !defaultSites_domains.includes(x.domain) || x.group)).map(x => x.group ? x.group.filter(y => !defaultSites_domains.includes(y)) : x.domain).flat(); 431 var ext_version_old = items.ext_version_old; 432 optin_setcookie = items.optIn; 433 optin_update = items.optInUpdate; 434 excludedSites = items.sites_excluded; 435 436 enabledSites = Object.values(sites).filter(function (val) { 437 return (val && val !== '###' && (defaultSites_domains.concat(customSites_domains, updatedSites_domains_new).includes(val))); 438 }).map(function (val) { 439 return val.toLowerCase(); 440 }); 441 442 // Enable new sites by default (opt-in) 443 updatedSites_new = Object.keys(updatedSites).filter(x => updatedSites[x].domain && !defaultSites_domains.includes(updatedSites[x].domain) && updatedSites[x].domain !== '###_usa_theathletic'); 444 for (let site_updated_new of updatedSites_new) 445 defaultSites[site_updated_new] = updatedSites[site_updated_new]; 446 if (ext_version > ext_version_old || updatedSites_new.length > 0) { 447 if (enabledSites.includes('#options_enable_new_sites')) { 448 let sites_new = Object.keys(defaultSites).filter(x => defaultSites[x].domain && !defaultSites[x].domain.match(/^(#options_|###$)/) && !sites_default.some(key => compareKey(key, x))); 449 for (let site_new of sites_new) 450 sites[site_new] = defaultSites[site_new].domain; 451 // reset ungrouped sites 452 let ungrouped_sites = { 453 'The Athletic': 'theathletic.com' 454 }; 455 for (let key in ungrouped_sites) { 456 if (sites[key] && sites[key] !== ungrouped_sites[key]) 457 sites[key] = ungrouped_sites[key]; 458 } 459 ext_api.storage.local.set({ 460 sites: sites 461 }); 462 } else { 463 ext_api.management.getSelf(function (result) { 464 if ((result.installType === 'development' || (result.installType !== 'development' && !enabledSites.includes('#options_on_update')))) { 465 let new_groups = ['###_de_mhs', '###_nl_eu_ftm']; 466 let open_options = new_groups.some(group => !enabledSites.includes(group) && grouped_sites[group].some(domain => enabledSites.includes(domain) && !customSites_domains.includes(domain))); 467 if (open_options) 468 ext_api.runtime.openOptionsPage(); 469 } 470 }); 471 } 472 sites_default = Object.keys(defaultSites).filter(x => defaultSites[x].domain && !defaultSites[x].domain.match(/^(#options_|###$)/)); 473 ext_api.storage.local.set({ 474 sites_default: sites_default, 475 ext_version_old: ext_version 476 }); 477 } 478 479 disabledSites = defaultSites_grouped_domains.concat(customSites_domains).filter(x => !enabledSites.includes(x)); 480 add_grouped_enabled_domains(grouped_sites); 481 set_rules(sites, updatedSites, customSites); 482 if (enabledSites.includes('#options_optin_update_rules')) { 483 check_sites_updated(); 484 sites_custom_ext_json = 'https://gitlab.com/magnolia1234/bypass-paywalls-' + url_loc + '-clean/-/raw/master/custom/sites_custom.json'; 485 } 486 check_sites_custom_ext(); 487 if (optin_update) 488 check_update(); 489 }); 490 491 // Listen for changes to options 492 ext_api.storage.onChanged.addListener(function (changes, namespace) { 493 if (namespace === 'sync') 494 return; 495 for (let key in changes) { 496 var storageChange = changes[key]; 497 if (key === 'sites') { 498 var sites = storageChange.newValue; 499 optionSites = sites; 500 enabledSites = Object.values(sites).filter(function (val) { 501 return (val && val !== '###' && (defaultSites_domains.concat(customSites_domains, updatedSites_domains_new).includes(val))); 502 }).map(function (val) { 503 return val.toLowerCase(); 504 }); 505 disabledSites = defaultSites_grouped_domains.concat(customSites_domains).filter(x => !enabledSites.includes(x)); 506 add_grouped_enabled_domains(grouped_sites); 507 set_rules(sites, updatedSites, customSites); 508 } 509 if (key === 'sites_custom') { 510 var sites_custom = storageChange.newValue ? storageChange.newValue : {}; 511 var sites_custom_old = storageChange.oldValue ? storageChange.oldValue : {}; 512 customSites = sites_custom; 513 customSites_domains = Object.values(sites_custom).map(x => x.domain); 514 515 // add/remove custom sites in options (not for default site(group)) 516 var sites_custom_added = Object.keys(sites_custom).filter(x => !Object.keys(sites_custom_old).includes(x) && !defaultSites.hasOwnProperty(x) && !defaultSites_domains.includes(sites_custom[x].domain)); 517 var sites_custom_removed = Object.keys(sites_custom_old).filter(x => !Object.keys(sites_custom).includes(x) && !defaultSites.hasOwnProperty(x) && !defaultSites_domains.includes(sites_custom_old[x].domain)); 518 519 ext_api.storage.local.get({ 520 sites: {} 521 }, function (items) { 522 var sites = items.sites; 523 if (sites_custom_added.concat(sites_custom_removed).length > 0) { 524 for (let key of sites_custom_added) 525 sites[key] = sites_custom[key].domain; 526 for (let key of sites_custom_removed) 527 delete sites[key]; 528 529 ext_api.storage.local.set({ 530 sites: sites 531 }, function () { 532 true; 533 }); 534 } else 535 set_rules(sites, updatedSites, customSites); 536 }); 537 } 538 if (key === 'sites_updated') { 539 var sites_updated = storageChange.newValue ? storageChange.newValue : {}; 540 updatedSites = sites_updated; 541 updatedSites_domains_new = Object.values(updatedSites).filter(x => (x.domain && !defaultSites_domains.includes(x.domain) || x.group)).map(x => x.group ? x.group.filter(y => !defaultSites_domains.includes(y)) : x.domain).flat(); 542 updatedSites_new = Object.keys(updatedSites).filter(x => updatedSites[x].domain && !defaultSites_domains.includes(updatedSites[x].domain) && updatedSites[x].domain !== '###_usa_theathletic'); 543 if (updatedSites_new.length > 0) { 544 if (enabledSites.includes('#options_enable_new_sites')) { 545 for (let site_updated_new of updatedSites_new) 546 optionSites[site_updated_new] = updatedSites[site_updated_new].domain; 547 ext_api.storage.local.set({ 548 sites: optionSites 549 }); 550 } 551 } else 552 set_rules(optionSites, updatedSites, customSites); 553 } 554 if (key === 'sites_excluded') { 555 var sites_excluded = storageChange.newValue ? storageChange.newValue : []; 556 var sites_excluded_old = storageChange.oldValue ? storageChange.oldValue : []; 557 excludedSites = sites_excluded; 558 559 // add/remove excluded sites in en/disabledSites 560 var sites_excluded_added = sites_excluded.filter(x => !sites_excluded_old.includes(x)); 561 var sites_excluded_removed = sites_excluded_old.filter(x => !sites_excluded.includes(x)); 562 563 for (let site of sites_excluded_added) { 564 if (enabledSites.includes(site)) { 565 enabledSites.splice(enabledSites.indexOf(site), 1); 566 disabledSites.push(site); 567 } 568 } 569 for (let site of sites_excluded_removed) { 570 if (disabledSites.includes(site)) { 571 disabledSites.splice(disabledSites.indexOf(site), 1); 572 enabledSites.push(site); 573 } 574 } 575 } 576 if (key === 'ext_version_new') { 577 ext_version_new = storageChange.newValue; 578 } 579 if (key === 'optIn') { 580 optin_setcookie = storageChange.newValue; 581 } 582 if (key === 'optInUpdate') { 583 optin_update = storageChange.newValue; 584 } 585 } 586 }); 587 588 // Set and show default options on install 589 ext_api.runtime.onInstalled.addListener(function (details) { 590 if (details.reason == "install") { 591 setDefaultOptions(); 592 } else if (details.reason == "update") { 593 ext_api.management.getSelf(function (result) { 594 if (enabledSites.includes('#options_on_update') && result.installType !== 'development') 595 ext_api.runtime.openOptionsPage(); // User updated extension (non-developer mode) 596 }); 597 } 598 }); 599 600 // Google AMP cache redirect 601 ext_api.webRequest.onBeforeRequest.addListener(function (details) { 602 var url = details.url.split('?')[0]; 603 var updatedUrl; 604 if (matchUrlDomain('cdn.ampproject.org', url)) 605 updatedUrl = 'https://' + url.split(/cdn\.ampproject\.org\/[a-z]\/s\//)[1]; 606 else if (matchUrlDomain('google.com', url)) 607 updatedUrl = 'https://' + url.split(/\.google\.com\/amp\/s\//)[1]; 608 return { redirectUrl: decodeURIComponent(updatedUrl) }; 609 }, 610 {urls:["*://*.cdn.ampproject.org/*/s/*", "*://*.google.com/amp/s/*"], types:["main_frame"]}, 611 ["blocking"] 612 ); 613 614 // inkl bypass 615 ext_api.webRequest.onBeforeRequest.addListener(function (details) { 616 if (!isSiteEnabled(details)) { 617 return; 618 } 619 var updatedUrl = details.url.replace(/etok=[\w]*&/, ''); 620 if (details.url.includes('/signin?') && details.url.includes('redirect_to=')) 621 updatedUrl = 'https://www.inkl.com' + decodeURIComponent(updatedUrl.split('redirect_to=')[1]); 622 return { redirectUrl: updatedUrl }; 623 }, 624 {urls:["*://*.inkl.com/*"], types:["main_frame"]}, 625 ["blocking"] 626 ); 627 628 // m.faz.net set user-agent to mobile 629 const userAgentMobile = "Mozilla/5.0 (Linux; Android 12) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Mobile Safari/537.36"; 630 ext_api.webRequest.onBeforeSendHeaders.addListener(function (details) { 631 if (!isSiteEnabled(details)) { 632 return; 633 } 634 let headers = details.requestHeaders; 635 headers = headers.map(function (header) { 636 if (header.name.toLowerCase() === 'user-agent') 637 header.value = userAgentMobile; 638 return header; 639 }); 640 return { 641 requestHeaders: headers 642 }; 643 }, { 644 urls: ["*://m.faz.net/*"], 645 types: ["xmlhttprequest"] 646 }, 647 ["blocking", "requestHeaders"]); 648 649 // webcache.googleusercontent.com set user-agent to Chrome (on Firefox for Android) 650 if ((typeof browser !== 'object') && navigator_ua_mobile) { 651 ext_api.webRequest.onBeforeSendHeaders.addListener(function (details) { 652 let headers = details.requestHeaders; 653 headers = headers.map(function (header) { 654 if (header.name.toLowerCase() === 'user-agent') 655 header.value = userAgentMobile; 656 return header; 657 }); 658 return { 659 requestHeaders: headers 660 }; 661 }, { 662 urls: ["*://webcache.googleusercontent.com/*"], 663 types: ["main_frame", "xmlhttprequest"] 664 }, 665 ["blocking", "requestHeaders"]); 666 } 667 668 // economictimes redirect 669 ext_api.webRequest.onBeforeRequest.addListener(function (details) { 670 if (!isSiteEnabled(details) || details.url.includes('.com/epaper/') || !navigator_ua_mobile) { 671 return; 672 } 673 var updatedUrl = details.url.split('?')[0].replace('economictimes.indiatimes.com', 'm.economictimes.com'); 674 return { redirectUrl: updatedUrl }; 675 }, 676 {urls:["*://economictimes.indiatimes.com/*?from=mdr"], types:["main_frame"]}, 677 ["blocking"] 678 ); 679 680 // infzm.com redirect to wap (mobile) 681 ext_api.webRequest.onBeforeRequest.addListener(function (details) { 682 if (!isSiteEnabled(details)) { 683 return; 684 } 685 var updatedUrl = details.url.replace('.com/contents/', '.com/wap/#/content/'); 686 return { redirectUrl: updatedUrl }; 687 }, 688 {urls:["*://www.infzm.com/contents/*"], types:["main_frame"]}, 689 ["blocking"] 690 ); 691 692 // telegraaf.nl redirect error-page 693 ext_api.webRequest.onBeforeRequest.addListener(function (details) { 694 if (!isSiteEnabled(details)) { 695 return; 696 } 697 let updatedUrl = details.url.split('&')[0].replace('error?ref=/', '');; 698 return { redirectUrl: updatedUrl }; 699 }, 700 {urls:["*://www.telegraaf.nl/error?ref=/*"], types:["main_frame"]}, 701 ["blocking"] 702 ); 703 704 // Australia News Corp redirect subscribe to amp 705 var au_news_corp_no_amp_fix = ['codesports.com.au']; 706 var au_news_corp_subscr = au_news_corp_domains.filter(domain => !au_news_corp_no_amp_fix.includes(domain)).map(domain => '*://www.' + domain + '/subscribe/*'); 707 ext_api.webRequest.onBeforeRequest.addListener(function (details) { 708 if (!isSiteEnabled(details) || details.url.includes('/digitalprinteditions') || !(details.url.includes('dest=') && details.url.split('dest=')[1].split('&')[0])) { 709 return; 710 } 711 var updatedUrl = decodeURIComponent(details.url.split('dest=')[1].split('&')[0]) + '?amp'; 712 return { 713 redirectUrl: updatedUrl 714 }; 715 }, { 716 urls: au_news_corp_subscr, 717 types: ["main_frame"] 718 }, 719 ["blocking"]); 720 721 // fix nytimes x-frame-options (hidden iframe content) 722 ext_api.webRequest.onHeadersReceived.addListener(function (details) { 723 if (!isSiteEnabled(details)) { 724 return; 725 } 726 var headers = details.responseHeaders; 727 headers = headers.map(function (header) { 728 if (header.name === 'x-frame-options') 729 header.value = 'SAMEORIGIN'; 730 return header; 731 }); 732 return { 733 responseHeaders: headers 734 }; 735 }, { 736 urls: ["*://*.nytimes.com/*"] 737 }, 738 ['blocking', 'responseHeaders']); 739 740 function blockJsInlineListener(details) { 741 let domain = matchUrlDomain(blockedJsInlineDomains, details.url); 742 let matched = domain && details.url.match(blockedJsInline[domain]); 743 if (matched && optin_setcookie && ['uol.com.br'].includes(domain)) 744 matched = false; 745 if (!isSiteEnabled(details) || !matched) 746 return; 747 var headers = details.responseHeaders; 748 headers.push({ 749 'name': 'Content-Security-Policy', 750 'value': "script-src *;" 751 }); 752 return { 753 responseHeaders: headers 754 }; 755 } 756 757 function disableJavascriptInline() { 758 // block inline script 759 ext_api.webRequest.onHeadersReceived.removeListener(blockJsInlineListener); 760 var block_js_inline_urls = []; 761 for (let domain in blockedJsInline) 762 block_js_inline_urls.push("*://*." + domain + "/*"); 763 if (block_js_inline_urls.length) 764 ext_api.webRequest.onHeadersReceived.addListener(blockJsInlineListener, { 765 'types': ['main_frame', 'sub_frame'], 766 'urls': block_js_inline_urls 767 }, 768 ['blocking', 'responseHeaders']); 769 } 770 771 if (typeof browser !== 'object') { 772 var focus_changed = false; 773 ext_api.windows.onFocusChanged.addListener((windowId) => { 774 if (windowId > 0) 775 focus_changed = true; 776 }); 777 } 778 779 function runOnTab(tab) { 780 let tabId = tab.id; 781 let url = tab.url; 782 let rc_domain = matchUrlDomain(remove_cookies, url); 783 let rc_domain_enabled = rc_domain && enabledSites.includes(rc_domain); 784 let lib_file = 'lib/empty.js'; 785 if (matchUrlDomain(dompurify_sites, url)) 786 lib_file = 'lib/purify.min.js'; 787 var bg2csData = {}; 788 if (optin_setcookie && matchUrlDomain(['###'], url)) 789 bg2csData.optin_setcookie = 1; 790 if (matchUrlDomain(amp_unhide, url)) 791 bg2csData.amp_unhide = 1; 792 let amp_redirect_domain = ''; 793 if (amp_redirect_domain = matchUrlDomain(Object.keys(amp_redirect), url)) 794 bg2csData.amp_redirect = amp_redirect[amp_redirect_domain]; 795 let cs_code_domain = ''; 796 if (cs_code_domain = matchUrlDomain(Object.keys(cs_code), url)) 797 bg2csData.cs_code = cs_code[cs_code_domain]; 798 let ld_json_domain = ''; 799 if (ld_json_domain = matchUrlDomain(Object.keys(ld_json), url)) 800 bg2csData.ld_json = ld_json[ld_json_domain]; 801 let ld_json_next_domain = ''; 802 if (ld_json_next_domain = matchUrlDomain(Object.keys(ld_json_next), url)) 803 bg2csData.ld_json_next = ld_json_next[ld_json_next_domain]; 804 let ld_google_webcache_domain = ''; 805 if (ld_google_webcache_domain = matchUrlDomain(Object.keys(ld_google_webcache), url)) 806 bg2csData.ld_google_webcache = ld_google_webcache[ld_google_webcache_domain]; 807 let add_ext_link_domain = ''; 808 if (add_ext_link_domain = matchUrlDomain(Object.keys(add_ext_link), url)) 809 bg2csData.add_ext_link = add_ext_link[add_ext_link_domain]; 810 let tab_runs = 5; 811 for (let n = 0; n < tab_runs; n++) { 812 setTimeout(function () { 813 // run contentScript.js on page 814 ext_api.tabs.executeScript(tabId, { 815 file: lib_file, 816 runAt: 'document_start' 817 }, function (res) { 818 if (ext_api.runtime.lastError) 819 return; 820 ext_api.tabs.executeScript(tabId, { 821 file: 'contentScript.js', 822 runAt: 'document_start' 823 }, function (res) { 824 if (ext_api.runtime.lastError || res[0]) { 825 return; 826 } 827 }) 828 }); 829 // send bg2csData to contentScript.js 830 if (Object.keys(bg2csData).length) { 831 setTimeout(function () { 832 ext_api.tabs.sendMessage(tabId, {msg: "bg2cs", data: bg2csData}); 833 }, 500); 834 } 835 // remove cookies after page load 836 if (rc_domain_enabled) { 837 remove_cookies_fn(rc_domain, true); 838 } 839 }, n * 200); 840 } 841 } 842 843 function runOnTab_once(tab) { 844 let tabId = tab.id; 845 let url = tab.url; 846 // load contentScript_once.js to identify custom site (flex) of group 847 if (!(matchUrlDomain(custom_flex_domains.concat(custom_flex_not_domains, customSites_domains, updatedSites_domains_new, excludedSites, nofix_sites), url) || matchUrlDomain(defaultSites_domains, url))) { 848 ext_api.tabs.executeScript(tabId, { 849 file: 'contentScript_once.js', 850 runAt: 'document_start' 851 }, function (res) { 852 if (ext_api.runtime.lastError || res[0]) { 853 return; 854 } 855 }); 856 } 857 // load toggleIcon.js (icon for dark or incognito mode in Chrome)) 858 if (typeof browser !== 'object') { 859 ext_api.tabs.executeScript(tabId, { 860 file: 'options/toggleIcon.js', 861 runAt: 'document_start' 862 }, function (res) { 863 if (ext_api.runtime.lastError || res[0]) { 864 return; 865 } 866 }); 867 } 868 } 869 870 var set_var_sites = ['nzherald.co.nz', 'theglobeandmail.com'].concat(de_madsack_domains); 871 function runOnTab_once_var(tab) { 872 let tabId = tab.id; 873 let url = tab.url; 874 let domain = matchUrlDomain(set_var_sites, url); 875 // load contentScript_once_var.js to set variables for site 876 if (domain && enabledSites.includes(domain)) { 877 ext_api.tabs.executeScript(tabId, { 878 file: 'contentScript_once_var.js', 879 runAt: 'document_start' 880 }, function (res) { 881 if (ext_api.runtime.lastError || res[0]) { 882 return; 883 } 884 }); 885 } 886 } 887 888 ext_api.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { 889 let tab_status = changeInfo.status; 890 if (/^http/.test(tab.url)) { 891 if ((tab_status && tab_status === 'complete') || (changeInfo.url)) { 892 let timeout = changeInfo.url ? 500 : 0; 893 setTimeout(function () { 894 if (matchUrlDomain(enabledSites, tab.url)) { 895 runOnTab(tab); 896 } 897 runOnTab_once(tab); 898 }, timeout); 899 } 900 runOnTab_once_var(tab); 901 } 902 }); 903 904 setInterval(function () { 905 let current_date_str = currentDateStr(); 906 if (last_date_str < current_date_str) { 907 bpc_count_daily_users(current_date_str); 908 last_date_str = current_date_str; 909 } 910 }, 60 * 60 * 1000); 911 912 var extraInfoSpec = ['blocking', 'requestHeaders']; 913 if (ext_api.webRequest.OnBeforeSendHeadersOptions.hasOwnProperty('EXTRA_HEADERS')) 914 extraInfoSpec.push('extraHeaders'); 915 916 ext_api.webRequest.onBeforeSendHeaders.addListener(function(details) { 917 var requestHeaders = details.requestHeaders; 918 919 var header_referer = ''; 920 if (details.originUrl) 921 header_referer = details.originUrl; 922 else { 923 for (let n in requestHeaders) { 924 if (requestHeaders[n].name.toLowerCase() == 'referer') { 925 header_referer = requestHeaders[n].value; 926 break; 927 } 928 } 929 var blocked_referer_domains = ['timeshighereducation.com']; 930 if (!header_referer && details.initiator) { 931 header_referer = details.initiator; 932 if (!blocked_referer && matchUrlDomain(blocked_referer_domains, details.url) && ['script', 'xmlhttprequest'].includes(details.type)) { 933 for (let domain of blocked_referer_domains) 934 restrictions[domain] = new RegExp('((\\/|\\.)' + domain.replace(/\./g, '\\.') + '($|\\/$)|' + restrictions[domain].toString().replace(/(^\/|\/$)/g, '') + ')'); 935 blocked_referer = true; 936 } 937 } 938 } 939 940 // block external javascript for custom sites (optional) 941 if (['script'].includes(details.type)) { 942 let domain_blockjs_ext = matchUrlDomain(block_js_custom_ext, header_referer); 943 if (domain_blockjs_ext && !matchUrlDomain(domain_blockjs_ext, details.url) && isSiteEnabled({url: header_referer})) 944 return { cancel: true }; 945 } 946 947 // check for blocked regular expression: domain enabled, match regex, block on an internal or external regex 948 if (['script', 'xmlhttprequest'].includes(details.type)) { 949 let domain = matchUrlDomain(blockedRegexesDomains, header_referer); 950 if (domain && details.url.match(blockedRegexes[domain]) && isSiteEnabled({url: header_referer})) 951 return { cancel: true }; 952 } 953 954 // block general paywall scripts 955 if (['script', 'xmlhttprequest'].includes(details.type)) { 956 for (let domain in blockedRegexesGeneral) { 957 if (details.url.match(blockedRegexesGeneral[domain].block_regex) && !(matchUrlDomain(excludedSites.concat(disabledSites, blockedRegexesGeneral[domain].excluded_domains), header_referer))) 958 return { cancel: true }; 959 } 960 } 961 962 if (!isSiteEnabled(details)) { 963 return; 964 } 965 966 // block javascript of (sub)domain for custom sites (optional) 967 var domain_blockjs = matchUrlDomain(block_js_custom, details.url); 968 if (domain_blockjs && matchUrlDomain(domain_blockjs, details.url) && details.type === 'script') { 969 return { cancel: true }; 970 } 971 972 var useUserAgentMobile = false; 973 var setReferer = false; 974 975 var ignore_types = ['font', 'image', 'stylesheet']; 976 if (matchUrlDomain(au_news_corp_domains, details.url)) 977 ignore_types = ['font', 'image', 'stylesheet', 'other', 'script', 'xmlhttprequest']; 978 979 if (matchUrlDomain(change_headers, details.url) && !ignore_types.includes(details.type)) { 980 var mobile = details.requestHeaders.filter(x => x.name.toLowerCase() === "user-agent" && x.value.toLowerCase().includes("mobile")).length; 981 var googlebotEnabled = matchUrlDomain(use_google_bot, details.url) && 982 !(matchUrlDomain(es_grupo_vocento_domains, details.url) && mobile) && 983 !(matchUrlDomain('barrons.com', details.url) && enabledSites.includes('#options_disable_gb_barrons')) && 984 !(matchUrlDomain(['economictimes.com', 'economictimes.indiatimes.com'], details.url) && !details.url.split(/\?|#/)[0].endsWith('.cms')) && 985 !(matchUrlDomain(au_news_corp_domains, details.url) && (details.url.includes('?amp') || (!matchUrlDomain(au_news_corp_no_amp_fix, details.url) && enabledSites.includes('#options_disable_gb_au_news_corp')))) && 986 !(matchUrlDomain('uol.com.br', details.url) && !matchUrlDomain('folha.uol.com.br', details.url)) && 987 !(matchUrlDomain('wsj.com', details.url) && (enabledSites.includes('#options_disable_gb_wsj') || (!details.url.includes('/articles/') && details.type === 'main_frame' && mobile))); 988 var bingbotEnabled = matchUrlDomain(use_bing_bot, details.url); 989 var facebookbotEnabled = matchUrlDomain(use_facebook_bot, details.url); 990 991 // if referer exists, set it 992 requestHeaders = requestHeaders.map(function (requestHeader) { 993 if (requestHeader.name === 'Referer') { 994 if (googlebotEnabled || matchUrlDomain(use_google_referer, details.url)) { 995 requestHeader.value = 'https://www.google.com/'; 996 } else if (matchUrlDomain(use_facebook_referer, details.url)) { 997 requestHeader.value = 'https://www.facebook.com/'; 998 } else if (matchUrlDomain(use_twitter_referer, details.url)) { 999 requestHeader.value = 'https://t.co/'; 1000 } 1001 setReferer = true; 1002 } 1003 if (requestHeader.name === 'User-Agent') { 1004 useUserAgentMobile = requestHeader.value.toLowerCase().includes("mobile") && !matchUrlDomain(['telerama.fr'], details.url); 1005 } 1006 return requestHeader; 1007 }); 1008 1009 // otherwise add it 1010 if (!setReferer) { 1011 if (googlebotEnabled || matchUrlDomain(use_google_referer, details.url)) { 1012 requestHeaders.push({ 1013 name: 'Referer', 1014 value: 'https://www.google.com/' 1015 }); 1016 } else if (matchUrlDomain(use_facebook_referer, details.url)) { 1017 requestHeaders.push({ 1018 name: 'Referer', 1019 value: 'https://www.facebook.com/' 1020 }); 1021 } else if (matchUrlDomain(use_twitter_referer, details.url)) { 1022 requestHeaders.push({ 1023 name: 'Referer', 1024 value: 'https://t.co/' 1025 }); 1026 } 1027 } 1028 1029 // override User-Agent to use Googlebot 1030 if (googlebotEnabled) { 1031 requestHeaders.push({ 1032 "name": "User-Agent", 1033 "value": useUserAgentMobile ? userAgentMobileG : userAgentDesktopG 1034 }) 1035 requestHeaders.push({ 1036 "name": "X-Forwarded-For", 1037 "value": "66.249.66.1" 1038 }) 1039 } 1040 1041 // override User-Agent to use Bingbot 1042 if (bingbotEnabled) { 1043 requestHeaders.push({ 1044 "name": "User-Agent", 1045 "value": useUserAgentMobile ? userAgentMobileB : userAgentDesktopB 1046 }) 1047 } 1048 1049 // override User-Agent to use Facebookbot 1050 if (facebookbotEnabled) { 1051 requestHeaders.push({ 1052 "name": "User-Agent", 1053 "value": userAgentDesktopF 1054 }) 1055 } 1056 1057 // random IP for sites in use_random_ip 1058 let domain_random; 1059 if (domain_random = matchUrlDomain(use_random_ip, details.url)) { 1060 let randomIP_val; 1061 if (random_ip[domain_random] === 'eu') 1062 randomIP_val = randomIP(185, 185); 1063 else 1064 randomIP_val = randomIP(); 1065 requestHeaders.push({ 1066 "name": "X-Forwarded-For", 1067 "value": randomIP_val 1068 }) 1069 } 1070 } 1071 1072 // remove cookies before page load 1073 if (!matchUrlDomain(allow_cookies, details.url)) { 1074 requestHeaders = requestHeaders.map(function(requestHeader) { 1075 if (requestHeader.name === 'Cookie') { 1076 requestHeader.value = ''; 1077 } 1078 return requestHeader; 1079 }); 1080 } 1081 1082 if (kiwi_browser) { 1083 let tabId = details.tabId; 1084 if (tabId !== -1) { 1085 if (['main_frame', 'sub_frame', 'xmlhttprequest'].includes(details.type)) { 1086 ext_api.tabs.get(tabId, function (tab) { 1087 if (!ext_api.runtime.lastError && tab && isSiteEnabled(tab)) { 1088 runOnTab(tab); 1089 } 1090 runOnTab_once(tab); 1091 runOnTab_once_var(tab); 1092 }); 1093 } 1094 } else { 1095 if (['xmlhttprequest'].includes(details.type)) { 1096 ext_api.tabs.query({ 1097 active: true, 1098 currentWindow: true 1099 }, function (tabs) { 1100 if (tabs && tabs[0] && /^http/.test(tabs[0].url)) { 1101 let tab = tabs[0]; 1102 if (isSiteEnabled(tab)) { 1103 runOnTab(tab); 1104 } 1105 runOnTab_once(tab); 1106 runOnTab_once_var(tab); 1107 } 1108 }); 1109 } 1110 } 1111 } 1112 1113 return { requestHeaders: requestHeaders }; 1114 }, { 1115 urls: ['*://*/*'] 1116 }, extraInfoSpec); 1117 // extraInfoSpec is ['blocking', 'requestHeaders'] + possible 'extraHeaders' 1118 1119 function check_sites_custom_ext() { 1120 fetch(sites_custom_ext_json) 1121 .then(response => { 1122 if (response.ok) { 1123 response.json().then(json => { 1124 customSitesExt = Object.values(json).map(x => x.domain); 1125 }) 1126 } 1127 }).catch(function (err) { 1128 false; 1129 }); 1130 } 1131 1132 var customSitesExt = []; 1133 var sites_custom_ext_json = 'custom/sites_custom.json'; 1134 1135 ext_api.tabs.onUpdated.addListener(function (tabId, info, tab) { updateBadge(tab); }); 1136 ext_api.tabs.onActivated.addListener(function (activeInfo) { if (activeInfo.tabId) ext_api.tabs.get(activeInfo.tabId, updateBadge); }); 1137 1138 function updateBadge(activeTab) { 1139 if (ext_api.runtime.lastError || !activeTab || (activeTab.url && urlHost(activeTab.url).match(/^archive\.[a-z]{2}$/))) 1140 return; 1141 let badgeText = ''; 1142 let color = 'red'; 1143 let currentUrl = activeTab.url; 1144 if (currentUrl) { 1145 if (isSiteEnabled({url: currentUrl})) { 1146 badgeText = 'ON'; 1147 color = 'red'; 1148 } else if (matchUrlDomain(enabledSites, currentUrl)) { 1149 badgeText = 'ON-'; 1150 color = 'orange'; 1151 } else if (matchUrlDomain(disabledSites, currentUrl)) { 1152 badgeText = 'OFF'; 1153 color = 'blue'; 1154 } else if (matchUrlDomain(nofix_sites, currentUrl)) { 1155 badgeText = 'X'; 1156 color = 'silver'; 1157 } 1158 if (matchUrlDomain('webcache.googleusercontent.com', currentUrl)) 1159 badgeText = ''; 1160 if (ext_version_new) 1161 badgeText = '^' + badgeText; 1162 let isDefaultSite = matchUrlDomain(defaultSites_domains, currentUrl); 1163 let isCustomSite = matchUrlDomain(customSites_domains, currentUrl); 1164 let isUpdatedSite = matchUrlDomain(updatedSites_domains_new, currentUrl); 1165 if (!isDefaultSite && (isCustomSite || isUpdatedSite)) { 1166 ext_api.permissions.contains({ 1167 origins: ['*://*.' + (isCustomSite || isUpdatedSite) + '/*'] 1168 }, function (result) { 1169 if (!result) 1170 badgeText = enabledSites.includes(isCustomSite || isUpdatedSite) ? 'C' : ''; 1171 if (color && badgeText) 1172 ext_api.action.setBadgeBackgroundColor({color: color}); 1173 ext_api.action.setBadgeText({text: badgeText}); 1174 }); 1175 } else { 1176 if (!badgeText && matchUrlDomain(customSitesExt, currentUrl)) 1177 badgeText = '+C'; 1178 if (color && badgeText) 1179 ext_api.action.setBadgeBackgroundColor({color: color}); 1180 ext_api.action.setBadgeText({text: badgeText}); 1181 } 1182 } else 1183 ext_api.action.setBadgeText({text: badgeText}); 1184 } 1185 1186 var ext_version_new; 1187 function check_update() { 1188 let manifest_new = 'https://gitlab.com/magnolia1234/bypass-paywalls-' + url_loc + '-clean/raw/master/manifest.json'; 1189 fetch(manifest_new) 1190 .then(response => { 1191 if (response.ok) { 1192 response.json().then(json => { 1193 ext_api.management.getSelf(function (result) { 1194 var installType = result.installType; 1195 var ext_version_len = (installType === 'development') ? 7 : 5; 1196 ext_version_new = json['version']; 1197 if (ext_version_new.substring(0, ext_version_len) <= ext_version.substring(0, ext_version_len)) 1198 ext_version_new = ''; 1199 ext_api.storage.local.set({ 1200 ext_version_new: ext_version_new 1201 }); 1202 }); 1203 }) 1204 } 1205 }).catch(function (err) { 1206 false; 1207 }); 1208 } 1209 1210 function site_switch() { 1211 ext_api.tabs.query({ 1212 active: true, 1213 currentWindow: true 1214 }, function (tabs) { 1215 if (tabs && tabs[0] && /^http/.test(tabs[0].url)) { 1216 let currentUrl = tabs[0].url; 1217 let isDefaultSite = matchUrlDomain(defaultSites_grouped_domains, currentUrl); 1218 if (!isDefaultSite) { 1219 let isDefaultSiteGroup = matchUrlDomain(defaultSites_domains, currentUrl); 1220 if (isDefaultSiteGroup) 1221 isDefaultSite = Object.keys(grouped_sites).find(key => grouped_sites[key].includes(isDefaultSiteGroup)); 1222 } 1223 if (!isDefaultSite) { 1224 let sites_updated_domains_new = Object.values(updatedSites).filter(x => x.domain && !defaultSites_domains.includes(x.domain)); 1225 let isUpdatedSite = matchUrlDomain(sites_updated_domains_new, currentUrl); 1226 if (isUpdatedSite) 1227 isDefaultSite = isUpdatedSite; 1228 } 1229 let defaultSite_title = isDefaultSite ? Object.keys(defaultSites).find(key => defaultSites[key].domain === isDefaultSite) : ''; 1230 let isCustomSite = matchUrlDomain(Object.values(customSites_domains), currentUrl); 1231 let customSite_title = isCustomSite ? Object.keys(customSites).find(key => customSites[key].domain === isCustomSite) : ''; 1232 let site_title = defaultSite_title || customSite_title; 1233 let domain = isDefaultSite || isCustomSite; 1234 if (domain && site_title) { 1235 let added_site = []; 1236 let removed_site = []; 1237 if (enabledSites.includes(domain)) 1238 removed_site.push(site_title); 1239 else 1240 added_site.push(site_title); 1241 ext_api.storage.local.get({ 1242 sites: {} 1243 }, function (items) { 1244 var sites = items.sites; 1245 for (let key of added_site) 1246 sites[key] = domain; 1247 for (let key of removed_site) { 1248 key = Object.keys(sites).find(sites_key => compareKey(sites_key, key)); 1249 delete sites[key]; 1250 } 1251 ext_api.storage.local.set({ 1252 sites: sites 1253 }, function () { 1254 ext_api.tabs.reload({bypassCache: true}); 1255 }); 1256 }); 1257 } 1258 } 1259 }); 1260 } 1261 1262 function remove_cookies_fn(domainVar, exclusions = false) { 1263 ext_api.cookies.getAllCookieStores(function (cookieStores) { 1264 ext_api.tabs.query({ 1265 active: true, 1266 currentWindow: true 1267 }, function (tabs) { 1268 if (!ext_api.runtime.lastError && tabs && tabs[0] && /^http/.test(tabs[0].url)) { 1269 let tabId = tabs[0].id; 1270 let storeId = '0'; 1271 for (let store of cookieStores) { 1272 if (store.tabIds.includes(tabId)) 1273 storeId = store.id; 1274 } 1275 storeId = storeId.toString(); 1276 if (domainVar === 'asia.nikkei.com') 1277 domainVar = 'nikkei.com'; 1278 var cookie_get_options = { 1279 domain: domainVar 1280 }; 1281 if (storeId !== 'null') 1282 cookie_get_options.storeId = storeId; 1283 var cookie_remove_options = {}; 1284 ext_api.cookies.getAll(cookie_get_options, function (cookies) { 1285 for (let cookie of cookies) { 1286 if (exclusions) { 1287 var rc_domain = cookie.domain.replace(/^(\.?www\.|\.)/, ''); 1288 // hold specific cookie(s) from remove_cookies domains 1289 if ((rc_domain in remove_cookies_select_hold) && remove_cookies_select_hold[rc_domain].includes(cookie.name)) { 1290 continue; // don't remove specific cookie 1291 } 1292 // drop only specific cookie(s) from remove_cookies domains 1293 if ((rc_domain in remove_cookies_select_drop) && !(remove_cookies_select_drop[rc_domain].includes(cookie.name))) { 1294 continue; // only remove specific cookie 1295 } 1296 // hold on to consent-cookie 1297 if (cookie.name.match(/(consent|^optanon)/i)) { 1298 continue; 1299 } 1300 } 1301 cookie.domain = cookie.domain.replace(/^\./, ''); 1302 cookie_remove_options = { 1303 url: (cookie.secure ? "https://" : "http://") + cookie.domain + cookie.path, 1304 name: cookie.name 1305 }; 1306 if (storeId !== 'null') 1307 cookie_remove_options.storeId = storeId; 1308 ext_api.cookies.remove(cookie_remove_options); 1309 } 1310 }); 1311 } 1312 }); 1313 }) 1314 } 1315 1316 function clear_cookies() { 1317 ext_api.tabs.query({ 1318 active: true, 1319 currentWindow: true 1320 }, function (tabs) { 1321 if (tabs && tabs[0] && /^http/.test(tabs[0].url)) { 1322 ext_api.tabs.executeScript({ 1323 file: 'options/clearCookies.js', 1324 runAt: 'document_start' 1325 }, function (res) { 1326 if (ext_api.runtime.lastError || res[0]) { 1327 return; 1328 } 1329 }); 1330 ext_api.tabs.update(tabs[0].id, { 1331 url: tabs[0].url 1332 }); 1333 } 1334 }); 1335 } 1336 1337 var chrome_scheme = 'light'; 1338 ext_api.runtime.onMessage.addListener(function (message, sender) { 1339 if (message.request === 'clear_cookies') { 1340 clear_cookies(); 1341 } 1342 // clear cookies for domain 1343 if (message.request === 'clear_cookies_domain' && message.data) { 1344 remove_cookies_fn(message.data.domain); 1345 } 1346 if (message.request === 'custom_domain' && message.data && message.data.domain) { 1347 let custom_domain = message.data.domain; 1348 let group = message.data.group; 1349 if (group) { 1350 let nofix_groups = ['###_be_mediahuis', '###_ch_tamedia', '###_de_rp_aachen_medien', '###_fi_alma_talent', '###_it_citynews', '###_nl_vmnmedia', '###_substack_custom']; 1351 if (!custom_flex_domains.includes(custom_domain)) { 1352 if (enabledSites.includes(group)) { 1353 let rules = Object.values(defaultSites).filter(x => x.domain === group)[0]; 1354 if (rules) { 1355 if (group === '###_de_madsack') { 1356 if (!set_var_sites.includes(custom_domain)) 1357 set_var_sites.push(custom_domain); 1358 } else if (group === '###_usa_townnews') { 1359 if (!dompurify_sites.includes(custom_domain)) 1360 dompurify_sites.push(custom_domain); 1361 if (['berkshireeagle.com'].includes(custom_domain)) 1362 rules.useragent = 'googlebot'; 1363 } 1364 } else 1365 rules = Object.values(customSites).filter(x => x.domain === group)[0]; 1366 if (rules) { 1367 custom_flex_domains.push(custom_domain); 1368 if (!enabledSites.includes(custom_domain)) 1369 enabledSites.push(custom_domain); 1370 customFlexAddRules(custom_domain, rules); 1371 } 1372 } else if (disabledSites.includes(group)) 1373 custom_flex_not_domains.push(custom_domain); 1374 else if (nofix_groups.includes(group)) 1375 nofix_sites.push(custom_domain); 1376 } 1377 } else 1378 custom_flex_not_domains.push(custom_domain); 1379 } 1380 if (message.request === 'site_switch') { 1381 site_switch(); 1382 } 1383 if (message.request === 'check_sites_updated') { 1384 check_sites_updated(); 1385 } 1386 if (message.request === 'clear_sites_updated') { 1387 clear_sites_updated(); 1388 } 1389 if (message.request === 'popup_show_toggle') { 1390 ext_api.tabs.query({ 1391 active: true, 1392 currentWindow: true 1393 }, function (tabs) { 1394 if (tabs && tabs[0] && /^http/.test(tabs[0].url)) { 1395 let currentUrl = tabs[0].url; 1396 let domain; 1397 let isExcludedSite = matchUrlDomain(excludedSites, currentUrl); 1398 if (!isExcludedSite) { 1399 let isDefaultSite = matchUrlDomain(defaultSites_domains, currentUrl); 1400 let isCustomSite = matchUrlDomain(Object.values(customSites_domains), currentUrl); 1401 domain = isDefaultSite || isCustomSite; 1402 if (domain) 1403 ext_api.runtime.sendMessage({ 1404 msg: "popup_show_toggle", 1405 data: { 1406 domain: domain, 1407 enabled: enabledSites.includes(domain) 1408 } 1409 }); 1410 } 1411 } 1412 }); 1413 } 1414 if (message.request === 'refreshCurrentTab') { 1415 ext_api.tabs.reload({bypassCache: true}); 1416 } 1417 if (message.request === 'getExtSrc' && message.data) { 1418 fetch(message.data.url) 1419 .then(response => { 1420 if (response.ok) { 1421 response.text().then(html => { 1422 if (message.data.base64) { 1423 html = decode_utf8(atob(html)); 1424 message.data.selector_source = 'body'; 1425 } 1426 message.data.html = html; 1427 if (typeof DOMParser === 'function') { 1428 let parser = new DOMParser(); 1429 let doc = parser.parseFromString(html, 'text/html'); 1430 let article_new = doc.querySelector(message.data.selector_source); 1431 if (article_new) 1432 message.data.html = article_new.outerHTML; 1433 } 1434 ext_api.tabs.query({ 1435 active: true, 1436 currentWindow: true 1437 }, function (tabs) { 1438 if (tabs && tabs[0] && /^http/.test(tabs[0].url)) { 1439 ext_api.tabs.sendMessage(sender.tab.id, {msg: "showExtSrc", data: message.data}); 1440 } 1441 }); 1442 }); 1443 } 1444 }).catch(function (err) { 1445 message.data.html = ''; 1446 ext_api.tabs.query({ 1447 active: true, 1448 currentWindow: true 1449 }, function (tabs) { 1450 if (tabs && tabs[0] && /^http/.test(tabs[0].url)) { 1451 ext_api.tabs.sendMessage(sender.tab.id, {msg: "showExtSrc", data: message.data}); 1452 } 1453 }); 1454 }); 1455 } 1456 if (message.scheme && (![chrome_scheme, 'undefined'].includes(message.scheme) || focus_changed)) { 1457 let icon_path = {path: {'128': 'bypass.png'}}; 1458 if (message.scheme === 'dark') 1459 icon_path = {path: {'128': 'bypass-dark.png'}}; 1460 ext_api.action.setIcon(icon_path); 1461 chrome_scheme = message.scheme; 1462 focus_changed = false; 1463 } 1464 }); 1465 1466 // show the opt-in tab on installation 1467 ext_api.storage.local.get(["optInShown", "customShown"], function (result) { 1468 if (!result.optInShown || !result.customShown) { 1469 ext_api.tabs.create({ 1470 url: "options/optin/opt-in.html" 1471 }); 1472 ext_api.storage.local.set({ 1473 "optInShown": true, 1474 "customShown": true 1475 }); 1476 } 1477 }); 1478 1479 function filterObject(obj, filterFn, mapFn = function (val, key) { 1480 return [key, val]; 1481 }) { 1482 return Object.fromEntries(Object.entries(obj). 1483 filter(([key, val]) => filterFn(val, key)).map(([key, val]) => mapFn(val, key))); 1484 } 1485 1486 function compareKey(firstStr, secondStr) { 1487 return firstStr.toLowerCase().replace(/\s\(.*\)/, '') === secondStr.toLowerCase().replace(/\s\(.*\)/, ''); 1488 } 1489 1490 function isSiteEnabled(details) { 1491 var enabledSite = matchUrlDomain(enabledSites, details.url); 1492 if (!ext_name.startsWith('Bypass Paywalls Clean')) 1493 enabledSite = ''; 1494 if (enabledSite in restrictions) { 1495 return restrictions[enabledSite].test(details.url); 1496 } 1497 return !!enabledSite; 1498 } 1499 1500 function matchDomain(domains, hostname = '') { 1501 var matched_domain = false; 1502 if (typeof domains === 'string') 1503 domains = [domains]; 1504 domains.some(domain => (hostname === domain || hostname.endsWith('.' + domain)) && (matched_domain = domain)); 1505 return matched_domain; 1506 } 1507 1508 function urlHost(url) { 1509 if (/^http/.test(url)) { 1510 try { 1511 return new URL(url).hostname; 1512 } catch (e) { 1513 console.log(`url not valid: ${url} error: ${e}`); 1514 } 1515 } 1516 return url; 1517 } 1518 1519 function matchUrlDomain(domains, url) { 1520 return matchDomain(domains, urlHost(url)); 1521 } 1522 1523 function prepHostname(hostname) { 1524 return hostname.replace(/^(www|m|account|amp(\d)?|edition|eu|mobil|wap)\./, ''); 1525 } 1526 1527 function getParameterByName(name, url) { 1528 name = name.replace(/[\[\]]/g, '\\$&'); 1529 var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'), 1530 results = regex.exec(url); 1531 if (!results) return null; 1532 if (!results[2]) return ''; 1533 return decodeURIComponent(results[2].replace(/\+/g, ' ')); 1534 } 1535 1536 function stripQueryStringAndHashFromPath(url) { 1537 return url.split("?")[0].split("#")[0]; 1538 } 1539 1540 function decode_utf8(str) { 1541 return decodeURIComponent(escape(str)); 1542 } 1543 1544 function randomInt(max) { 1545 return Math.floor(Math.random() * Math.floor(max)); 1546 } 1547 1548 function randomIP(range_low = 0, range_high = 223) { 1549 let rndmIP = []; 1550 for (let n = 0; n < 4; n++) { 1551 if (n === 0) 1552 rndmIP.push(range_low + randomInt(range_high - range_low + 1)); 1553 else 1554 rndmIP.push(randomInt(255) + 1); 1555 } 1556 return rndmIP.join('.'); 1557 } 1558 1559 // Refresh the current tab (http) 1560 function refreshCurrentTab() { 1561 ext_api.tabs.query({ 1562 active: true, 1563 currentWindow: true 1564 }, function (tabs) { 1565 if (tabs && tabs[0] && /^http/.test(tabs[0].url)) { 1566 if (ext_api.runtime.lastError) 1567 return; 1568 ext_api.tabs.update(tabs[0].id, { 1569 url: tabs[0].url 1570 }); 1571 } 1572 }); 1573 }