├── .travis.yml ├── Makefile ├── README.md ├── lang ├── README.md ├── de.txt └── en.txt ├── src ├── _locales │ ├── de │ │ └── messages.json │ └── en │ │ └── messages.json ├── background.js ├── icon128.png ├── manifest.json ├── options.css ├── options.html ├── options.js ├── settings.js └── start.js └── test ├── README.md ├── package-lock.json ├── package.json └── test.js /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 11 4 | before_install: 5 | - cd test 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cd src && zip -r ../searchonymous.zip * -x *.DS_Store 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Searchonymous 2 | 3 | [![Build Status](https://travis-ci.org/MorbZ/Searchonymous.svg?branch=master)](https://travis-ci.org/MorbZ/Searchonymous) 4 | 5 | Searchonymous helps to keep your Google searches private: When installed no tracking cookies are sent to Google while searching. That way Google will not be able to connect searches with your account or create a search history. Also you will not receive customized search results. 6 | 7 | When the add-on is active it seems to Google that are logged out of your Google account during searches (see the the "Sign in" button at the top right). However you stay logged in on other Google services such as Youtube or Gmail. 8 | 9 | If you want to change your Google search settings, make sure to allow the "Search Preferences Cookie" in the add-on settings. By default the preferences-cookie will be blocked which effectively discards any changes to your search settings. 10 | 11 | Please note that there are other means of tracking this add-on can't protect you against, such as using your IP address or browser fingerprint. 12 | 13 | **[Help translate Searchonymous](https://poeditor.com/join/project/wbV4rQtHoY)** 14 | 15 | ## Download ## 16 | * [Searchonymous for Firefox](https://addons.mozilla.org/firefox/addon/searchonymous/) 17 | * [Searchonymous for Chrome](https://chrome.google.com/webstore/detail/searchonymous/onhfdppooafpnnigbmnpnnjmbajggekc) 18 | -------------------------------------------------------------------------------- /lang/README.md: -------------------------------------------------------------------------------- 1 | This directory contains localized detailed app descriptions that are used in the Chrome Web Store and Firefox Add-ons page. 2 | -------------------------------------------------------------------------------- /lang/de.txt: -------------------------------------------------------------------------------- 1 | Searchonymous hilft dir, deine Google-Suchen privat zu halten: Wenn installiert, werden bei der Suche keine Tracking-Cookies an Google gesendet. Auf diese Weise kann Google keine Suchanfragen mit deinem Konto verbinden oder einen Suchverlauf erstellen. Außerdem erhälst du keine individuellen Suchergebnisse. 2 | 3 | Wenn das Add-on aktiv ist, scheint es Google, dass du während der Suche von deinem Google-Account abgemeldet bist (siehe den "Anmelden"-Button oben rechts). Du bleibst jedoch bei anderen Google-Diensten wie Youtube oder Google Mail angemeldet. 4 | 5 | Wenn du die Google Sucheinstellungen ändern möchtest, stelle sicher, dass in den Add-On-Einstellungen der "Sucheinstellungen Cookie" erlaubt ist. Standardmäßig wird dieser Cookie blockiert, wodurch Änderungen an deinen Sucheinstellungen verworfen werden. 6 | 7 | Bitte beachte, dass es andere Möglichkeiten des Trackings gibt, gegen die dich dieses Add-on nicht schützen kann, wie z.B. die Verwendung der IP-Adresse oder des Browser-Fingerabdrucks. 8 | -------------------------------------------------------------------------------- /lang/en.txt: -------------------------------------------------------------------------------- 1 | Searchonymous helps to keep your Google searches private: When installed no tracking cookies are sent to Google while searching. That way Google will not be able to connect searches with your account or create a search history. Also you will not receive customized search results. 2 | 3 | When the add-on is active it seems to Google that are logged out of your Google account during searches (see the the "Sign in" button at the top right). However you stay logged in on other Google services such as Youtube or Gmail. 4 | 5 | If you want to change your Google search settings, make sure to allow the "Search Preferences Cookie" in the add-on settings. By default the preferences-cookie will be blocked which effectively discards any changes to your search settings. 6 | 7 | Please note that there are other means of tracking this add-on can't protect you against, such as using your IP address or browser fingerprint. 8 | -------------------------------------------------------------------------------- /src/_locales/de/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appDesc": { 3 | "message": "Hindert Google daran, deine Suchanfragen zu verfolgen." 4 | }, 5 | "optionsHeader": { 6 | "message": "Du kannst Searchonymous erlauben bestimmte Cookies an Google Suchanfragen zu senden, um deine Nutzererfahrung zu verbessern. Cookies, die deine Account-Informationen enthalten, werden von Searchonymous immer blockiert." 7 | }, 8 | "preferencesCookieName": { 9 | "message": "Sucheinstellungen Cookie" 10 | }, 11 | "preferencesCookieDescription": { 12 | "message": "Der \"NID\"-Cookie wird laut Googles [Datenschutzerklärung](https://policies.google.com/technologies/types?hl=de) nur dazu verwendet die Sucheinstellungen zu speichern. Da der Cookie jedoch eine eindeutige ID trägt, ist es für Google damit technisch möglich deine Suchen zu verfolgen. Wenn du deine Sucheinstellungen ändern möchtest, solltest du diesen Cookie erlauben." 13 | }, 14 | "consentCookieName": { 15 | "message": "Einverständnis Cookie" 16 | }, 17 | "consentCookieDescription": { 18 | "message": "Der \"Consent\"-Cookie enthält Informationen darüber, ob du Googles (Datenschutz-)Bestimmungen akzeptiert hast. In einigen Regionen wird eine große Meldung auf der Google-Suchseite angezeigt, wenn dieser Cookie nicht gesendet wird. Da der Cookie keine eindeutige ID trägt, kann er als harmlos angesehen werden was das Tracking betrifft." 19 | }, 20 | "captchaCookieName": { 21 | "message": "Captcha Cookie" 22 | }, 23 | "captchaCookieDescription": { 24 | "message": "Unter bestimmten Umständen muss ein Captcha gelöst werden, um weiter bei Google suchen zu können. Dieser Cookie speichert das erfolgreiche Lösen eines Captchas. Da der Cookie eine kurze Lebensdauer hat und nicht oft vorkommt, wird empfohlen ihn zu erlauben." 25 | }, 26 | "cookieChoicesCookieName": { 27 | "message": "Cookie Auswahl Cookie" 28 | }, 29 | "cookieChoicesCookieDescription": { 30 | "message": "Speichert welche Cookies erlaubt wurden." 31 | }, 32 | "optionsAllow": { 33 | "message": "Erlauben" 34 | }, 35 | "optionsBlock": { 36 | "message": "Blockieren" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appDesc": { 3 | "message": "Prevents Google from tracking your searches." 4 | }, 5 | "optionsHeader": { 6 | "message": "You may allow Searchonymous to send specific cookies to Google searches in order to improve your user experience. Cookies that carry your account information will always be blocked by Searchonymous." 7 | }, 8 | "preferencesCookieName": { 9 | "message": "Search Preferences Cookie" 10 | }, 11 | "preferencesCookieDescription": { 12 | "message": "The \"NID\"-cookie is according to Google's [privacy policy](https://policies.google.com/technologies/types) only used to store your search preferences. However as it carries a unique ID it is technically possible for Google to track your searches. You may want to allow this cookie if you change your search settings." 13 | }, 14 | "consentCookieName": { 15 | "message": "Consent Cookie" 16 | }, 17 | "consentCookieDescription": { 18 | "message": "The consent cookie stores information of whether you accepted Google's (privacy) policies. In some regions a large message box will be shown on the Google search page if this cookie is not set. This cookie doesn't carry a unique ID and is therefore harmless in regards of tracking." 19 | }, 20 | "captchaCookieName": { 21 | "message": "Captcha Cookie" 22 | }, 23 | "captchaCookieDescription": { 24 | "message": "Under certain circumstances a CAPTCHA has to be solved in order to continue searching on Google. This Cookie saves if a CAPTCHA has successfully been solved. Since the cookie is short lived and not too common it is recommended to allow it." 25 | }, 26 | "cookieChoicesCookieName": { 27 | "message": "Cookie Choices Cookie" 28 | }, 29 | "cookieChoicesCookieDescription": { 30 | "message": "Store a user’s state regarding their cookies choices." 31 | }, 32 | "optionsAllow": { 33 | "message": "Allow" 34 | }, 35 | "optionsBlock": { 36 | "message": "Block" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/background.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function start() { 4 | getWhitelist((whitelist) => { 5 | // Listen for changed settings 6 | chrome.runtime.onMessage.addListener((msg) => { 7 | if(msg.action !== undefined && msg.action == 'settingsChanged') { 8 | getWhitelist((wl) => { 9 | whitelist = wl; 10 | }); 11 | } 12 | }); 13 | 14 | // Register header event listener 15 | // For Chrome we have to use "extraHeaders" to get the cookie header 16 | let extraInfoSpec = [ 17 | 'blocking', 18 | 'requestHeaders', 19 | ]; 20 | if(chrome.webRequest.OnBeforeSendHeadersOptions.hasOwnProperty('EXTRA_HEADERS')) { 21 | extraInfoSpec.push('extraHeaders'); 22 | } 23 | chrome.webRequest.onBeforeSendHeaders.addListener( 24 | (details) => { 25 | // Check if search request 26 | if(!isSearchRequest(details)) { 27 | return; 28 | } 29 | 30 | // Get cookie header 31 | let headers = details.requestHeaders; 32 | let c = getHeader(headers, 'Cookie'); 33 | if(c.i == -1) { 34 | return; 35 | } 36 | 37 | // Remove unwanted cookies 38 | headers[c.i].value = getWhitelistedCookies(c.v, whitelist); 39 | return { 40 | requestHeaders: headers 41 | }; 42 | }, 43 | { 44 | urls: [''], 45 | }, 46 | extraInfoSpec, 47 | ); 48 | }); 49 | }; 50 | 51 | /* Settings */ 52 | // Generate whitelist from storage 53 | function getWhitelist(callback) { 54 | let settings = new Settings(); 55 | settings.load(() => { 56 | let whitelist = []; 57 | for(let [name, cookie] of settings.getAll()) { 58 | if(cookie.value == 1) { 59 | whitelist.push(cookie.name); 60 | } 61 | } 62 | callback(whitelist); 63 | }); 64 | } 65 | 66 | /* Cookies */ 67 | function getWhitelistedCookies(cookies, whitelist) { 68 | // Check for empty whitelist 69 | if(whitelist.length == 0) { 70 | return ''; 71 | } 72 | 73 | // Split cookies and check each name (case sensitive) 74 | let parts = cookies.split('; '); 75 | let newParts = []; 76 | for(let part of parts) { 77 | for(let cookie of whitelist) { 78 | if(part.startsWith(cookie+'=')) { 79 | newParts.push(part); 80 | break; 81 | } 82 | } 83 | } 84 | return newParts.join('; '); 85 | } 86 | 87 | // Returns an object where i is header index and v is the header value. If the 88 | // header does not exist, i will be -1. 89 | function getHeader(headers, name) { 90 | name = name.toLowerCase(); 91 | for(let i in headers) { 92 | if(headers[i].name.toLowerCase() == name) { 93 | return {i: i, v: headers[i].value}; 94 | } 95 | } 96 | return {i: -1, v: ''}; 97 | } 98 | 99 | /* URLs */ 100 | function isSearchRequest(details) { 101 | // Block all requests made from a search page. Currently only works in Firefox. 102 | if(details.documentUrl !== undefined) { 103 | if(isSearchUrl(details.documentUrl)) { 104 | return true; 105 | } 106 | } 107 | 108 | // Check for search URL 109 | return isSearchUrl(details.url); 110 | } 111 | 112 | // If URL considered a Google search URL. The rules are too complex for a single regex. 113 | function isSearchUrl(url) { 114 | // Split URL components 115 | let c = splitUrlComponents(url); 116 | if(c === false) { 117 | // No Google domain 118 | return false; 119 | } 120 | 121 | // Check subdomains 122 | if(![ 123 | '', 124 | 'www', 125 | 'images', 126 | 'suggestqueries', 127 | 'search', 128 | 'encrypted', 129 | 'news', 130 | 'video', 131 | 'books', 132 | 'scholar', 133 | ].includes(c.subdomain)) { 134 | return false; 135 | } 136 | 137 | // Remove trailing slash 138 | let path = c.path; 139 | if(path.endsWith('/')) { 140 | path = path.substr(0, path.length-1); 141 | } 142 | 143 | // Check first components 144 | let firstComp = getFirstPart(path, '/'); 145 | if([ 146 | '', // Homepage 147 | 'webhp', // Homepage 148 | 'preferences', // Block for search settings to not get influenced by account settings 149 | 'setprefs', 150 | 'complete', // Autocomplete 151 | 'gen_204', // Tracker, sends ei 152 | 'client_204', // Tracker, sends ei 153 | ].includes(firstComp)) { 154 | return true; 155 | } 156 | 157 | // Check search 158 | let lastComp = getLastPart(path, '/'); 159 | if(lastComp == 'search') { 160 | return true; 161 | } 162 | 163 | // Async 164 | if(firstComp == 'async') { 165 | if([ 166 | 'irc', // Sends query 167 | 'ecr', // Sends ei 168 | 'bgasy', // Sends ei 169 | ].includes(lastComp)) { 170 | return true; 171 | } 172 | } 173 | 174 | // Google News 175 | if(c.subdomain == 'news') { 176 | if(lastComp == 'batchexecute') { 177 | return true; 178 | } 179 | } 180 | 181 | // Google Scholar 182 | if(c.subdomain == 'scholar') { 183 | if([ 184 | 'scholar', 185 | 'scholar_complete', 186 | ].includes(lastComp)) { 187 | return true; 188 | } 189 | } 190 | return false; 191 | } 192 | 193 | // getFirstPart and getLastPart perform better than str.split()... 194 | function getFirstPart(str, sep) { 195 | let i = str.indexOf(sep); 196 | if(i === -1) { 197 | return str 198 | } 199 | return str.substr(0, i); 200 | } 201 | 202 | function getLastPart(str, sep) { 203 | let i = str.lastIndexOf(sep); 204 | if(i === -1) { 205 | return str 206 | } 207 | return str.substr(i+1); 208 | } 209 | 210 | // Splits an URL into subdomain, path and search query components. Only handles Google domains. The 211 | // leading slash for path and question mark for query string are omitted. All returned components 212 | // are in lowercase. 213 | function splitUrlComponents(url) { 214 | url = url.toLowerCase(); 215 | 216 | // Regex: https://regex101.com/r/xArIzJ/6 217 | let re = /^https?:\/\/(?:([a-z]+)\.)?google\.(?:[a-z.]+)\/?(.*?)$/; 218 | let m = re.exec(url); 219 | if(m === null) { 220 | return false; 221 | } 222 | 223 | // Split path and query string 224 | let path = ''; 225 | let query = ''; 226 | let pathquery = m[2]; 227 | let i = pathquery.indexOf('?'); 228 | if(i === -1) { 229 | path = pathquery; 230 | } else { 231 | path = pathquery.substr(0, i); 232 | query = pathquery.substr(i+1); 233 | } 234 | 235 | return { 236 | subdomain: m[1] === undefined ? '' : m[1], 237 | path: path, 238 | query: query, 239 | }; 240 | } 241 | 242 | // Make functions available for tests 243 | if(typeof(module) !== 'undefined') { 244 | module.exports.getWhitelistedCookies = getWhitelistedCookies; 245 | module.exports.isSearchUrl = isSearchUrl; 246 | } 247 | -------------------------------------------------------------------------------- /src/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MorbZ/Searchonymous/94d36dd589197088a3764809a725caa0c402417f/src/icon128.png -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "Searchonymous", 4 | "version": "1.1.2", 5 | "description": "__MSG_appDesc__", 6 | "default_locale": "en", 7 | "homepage_url": "https://github.com/MorbZ/Searchonymous", 8 | "applications": { 9 | "gecko": { 10 | "id": "jid1-WF1v8esuNM9pRg@jetpack" 11 | } 12 | }, 13 | "icons": { 14 | "128": "icon128.png" 15 | }, 16 | "background": { 17 | "scripts": [ 18 | "settings.js", 19 | "background.js", 20 | "start.js" 21 | ] 22 | }, 23 | "options_ui": { 24 | "page": "options.html" 25 | }, 26 | "permissions": [ 27 | "webRequest", 28 | "webRequestBlocking", 29 | "storage", 30 | "*://*.google.com/*", 31 | "*://*.google.ad/*", 32 | "*://*.google.ae/*", 33 | "*://*.google.com.af/*", 34 | "*://*.google.com.ag/*", 35 | "*://*.google.com.ai/*", 36 | "*://*.google.al/*", 37 | "*://*.google.am/*", 38 | "*://*.google.co.ao/*", 39 | "*://*.google.com.ar/*", 40 | "*://*.google.as/*", 41 | "*://*.google.at/*", 42 | "*://*.google.com.au/*", 43 | "*://*.google.az/*", 44 | "*://*.google.ba/*", 45 | "*://*.google.com.bd/*", 46 | "*://*.google.be/*", 47 | "*://*.google.bf/*", 48 | "*://*.google.bg/*", 49 | "*://*.google.com.bh/*", 50 | "*://*.google.bi/*", 51 | "*://*.google.bj/*", 52 | "*://*.google.com.bn/*", 53 | "*://*.google.com.bo/*", 54 | "*://*.google.com.br/*", 55 | "*://*.google.bs/*", 56 | "*://*.google.bt/*", 57 | "*://*.google.co.bw/*", 58 | "*://*.google.by/*", 59 | "*://*.google.com.bz/*", 60 | "*://*.google.ca/*", 61 | "*://*.google.cd/*", 62 | "*://*.google.cf/*", 63 | "*://*.google.cg/*", 64 | "*://*.google.ch/*", 65 | "*://*.google.ci/*", 66 | "*://*.google.co.ck/*", 67 | "*://*.google.cl/*", 68 | "*://*.google.cm/*", 69 | "*://*.google.cn/*", 70 | "*://*.google.com.co/*", 71 | "*://*.google.co.cr/*", 72 | "*://*.google.com.cu/*", 73 | "*://*.google.cv/*", 74 | "*://*.google.com.cy/*", 75 | "*://*.google.cz/*", 76 | "*://*.google.de/*", 77 | "*://*.google.dj/*", 78 | "*://*.google.dk/*", 79 | "*://*.google.dm/*", 80 | "*://*.google.com.do/*", 81 | "*://*.google.dz/*", 82 | "*://*.google.com.ec/*", 83 | "*://*.google.ee/*", 84 | "*://*.google.com.eg/*", 85 | "*://*.google.es/*", 86 | "*://*.google.com.et/*", 87 | "*://*.google.fi/*", 88 | "*://*.google.com.fj/*", 89 | "*://*.google.fm/*", 90 | "*://*.google.fr/*", 91 | "*://*.google.ga/*", 92 | "*://*.google.ge/*", 93 | "*://*.google.gg/*", 94 | "*://*.google.com.gh/*", 95 | "*://*.google.com.gi/*", 96 | "*://*.google.gl/*", 97 | "*://*.google.gm/*", 98 | "*://*.google.gp/*", 99 | "*://*.google.gr/*", 100 | "*://*.google.com.gt/*", 101 | "*://*.google.gy/*", 102 | "*://*.google.com.hk/*", 103 | "*://*.google.hn/*", 104 | "*://*.google.hr/*", 105 | "*://*.google.ht/*", 106 | "*://*.google.hu/*", 107 | "*://*.google.co.id/*", 108 | "*://*.google.ie/*", 109 | "*://*.google.co.il/*", 110 | "*://*.google.im/*", 111 | "*://*.google.co.in/*", 112 | "*://*.google.iq/*", 113 | "*://*.google.is/*", 114 | "*://*.google.it/*", 115 | "*://*.google.je/*", 116 | "*://*.google.com.jm/*", 117 | "*://*.google.jo/*", 118 | "*://*.google.co.jp/*", 119 | "*://*.google.co.ke/*", 120 | "*://*.google.com.kh/*", 121 | "*://*.google.ki/*", 122 | "*://*.google.kg/*", 123 | "*://*.google.co.kr/*", 124 | "*://*.google.com.kw/*", 125 | "*://*.google.kz/*", 126 | "*://*.google.la/*", 127 | "*://*.google.com.lb/*", 128 | "*://*.google.li/*", 129 | "*://*.google.lk/*", 130 | "*://*.google.co.ls/*", 131 | "*://*.google.lt/*", 132 | "*://*.google.lu/*", 133 | "*://*.google.lv/*", 134 | "*://*.google.com.ly/*", 135 | "*://*.google.co.ma/*", 136 | "*://*.google.md/*", 137 | "*://*.google.me/*", 138 | "*://*.google.mg/*", 139 | "*://*.google.mk/*", 140 | "*://*.google.ml/*", 141 | "*://*.google.com.mm/*", 142 | "*://*.google.mn/*", 143 | "*://*.google.ms/*", 144 | "*://*.google.com.mt/*", 145 | "*://*.google.mu/*", 146 | "*://*.google.mv/*", 147 | "*://*.google.mw/*", 148 | "*://*.google.com.mx/*", 149 | "*://*.google.com.my/*", 150 | "*://*.google.co.mz/*", 151 | "*://*.google.com.na/*", 152 | "*://*.google.com.nf/*", 153 | "*://*.google.com.ng/*", 154 | "*://*.google.com.ni/*", 155 | "*://*.google.ne/*", 156 | "*://*.google.nl/*", 157 | "*://*.google.no/*", 158 | "*://*.google.com.np/*", 159 | "*://*.google.nr/*", 160 | "*://*.google.nu/*", 161 | "*://*.google.co.nz/*", 162 | "*://*.google.com.om/*", 163 | "*://*.google.com.pa/*", 164 | "*://*.google.com.pe/*", 165 | "*://*.google.com.pg/*", 166 | "*://*.google.com.ph/*", 167 | "*://*.google.com.pk/*", 168 | "*://*.google.pl/*", 169 | "*://*.google.pn/*", 170 | "*://*.google.com.pr/*", 171 | "*://*.google.ps/*", 172 | "*://*.google.pt/*", 173 | "*://*.google.com.py/*", 174 | "*://*.google.com.qa/*", 175 | "*://*.google.ro/*", 176 | "*://*.google.ru/*", 177 | "*://*.google.rw/*", 178 | "*://*.google.com.sa/*", 179 | "*://*.google.com.sb/*", 180 | "*://*.google.sc/*", 181 | "*://*.google.se/*", 182 | "*://*.google.com.sg/*", 183 | "*://*.google.sh/*", 184 | "*://*.google.si/*", 185 | "*://*.google.sk/*", 186 | "*://*.google.com.sl/*", 187 | "*://*.google.sn/*", 188 | "*://*.google.so/*", 189 | "*://*.google.sm/*", 190 | "*://*.google.sr/*", 191 | "*://*.google.st/*", 192 | "*://*.google.com.sv/*", 193 | "*://*.google.td/*", 194 | "*://*.google.tg/*", 195 | "*://*.google.co.th/*", 196 | "*://*.google.com.tj/*", 197 | "*://*.google.tk/*", 198 | "*://*.google.tl/*", 199 | "*://*.google.tm/*", 200 | "*://*.google.tn/*", 201 | "*://*.google.to/*", 202 | "*://*.google.com.tr/*", 203 | "*://*.google.tt/*", 204 | "*://*.google.com.tw/*", 205 | "*://*.google.co.tz/*", 206 | "*://*.google.com.ua/*", 207 | "*://*.google.co.ug/*", 208 | "*://*.google.co.uk/*", 209 | "*://*.google.com.uy/*", 210 | "*://*.google.co.uz/*", 211 | "*://*.google.com.vc/*", 212 | "*://*.google.co.ve/*", 213 | "*://*.google.vg/*", 214 | "*://*.google.co.vi/*", 215 | "*://*.google.com.vn/*", 216 | "*://*.google.vu/*", 217 | "*://*.google.ws/*", 218 | "*://*.google.rs/*", 219 | "*://*.google.co.za/*", 220 | "*://*.google.co.zm/*", 221 | "*://*.google.co.zw/*", 222 | "*://*.google.cat/*" 223 | ] 224 | } 225 | -------------------------------------------------------------------------------- /src/options.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | } 4 | 5 | p.header { 6 | font-weight: bold; 7 | font-size: 1.2em; 8 | } 9 | 10 | div.option { 11 | border: 1px solid rgba(12, 12, 13, 0.3); 12 | border-radius: 2px; 13 | padding: 15px 20px; 14 | margin-top: 10px; 15 | } 16 | 17 | div.option p { 18 | line-height: 1.4em; 19 | } 20 | 21 | h2 { 22 | margin: 0; 23 | margin-bottom: 3px; 24 | font-weight: normal; 25 | display: inline; 26 | } 27 | 28 | span.info { 29 | font-size: 0.9em; 30 | color: #888; 31 | float: right; 32 | } 33 | 34 | label { 35 | font-weight: bold; 36 | font-size: 1.1em; 37 | margin-right: 10px; 38 | } 39 | -------------------------------------------------------------------------------- /src/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |

10 |
11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/options.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function ready(fn) { 4 | if(document.attachEvent ? document.readyState === 'complete' : document.readyState !== 'loading') { 5 | fn(); 6 | } else { 7 | document.addEventListener('DOMContentLoaded', fn); 8 | } 9 | } 10 | 11 | ready(() => { 12 | localize(); 13 | initOptions(); 14 | }); 15 | 16 | function initOptions() { 17 | let settings = new Settings(); 18 | settings.load(() => { 19 | // Create cookie option boxes 20 | let wrapper = document.querySelector('.wrapper'); 21 | for(let [name, cookie] of settings.getAll()) { 22 | /* 23 | Template: 24 |
25 | {Cookie} 26 |

{Name}

27 |

{Description}

28 | 29 | 30 | 31 |
32 | */ 33 | 34 | // Box 35 | let div = document.createElement('div'); 36 | div.classList.add('option'); 37 | wrapper.appendChild(div); 38 | 39 | // Cookie name 40 | let span = document.createElement('span'); 41 | span.classList.add('info'); 42 | appendText(span, `Name: ${cookie.name}`); 43 | div.appendChild(span); 44 | 45 | // Title 46 | let h2 = document.createElement('h2'); 47 | appendLocaleText(h2, cookie.locale+'Name'); 48 | div.appendChild(h2); 49 | 50 | // Description 51 | let p = document.createElement('p'); 52 | appendLocaleText(p, cookie.locale+'Description'); 53 | div.appendChild(p); 54 | 55 | // Radio buttons 56 | for(let button of [ 57 | [1, 'allow', 'optionsAllow'], 58 | [0, 'block', 'optionsBlock'], 59 | ]) { 60 | // Label 61 | let label = document.createElement('label'); 62 | div.appendChild(label); 63 | 64 | // Radio button 65 | let value = button[0]; 66 | let radio = document.createElement('input'); 67 | radio.type = 'radio'; 68 | radio.value = value; 69 | radio.name = name; 70 | if(cookie.value == value) { 71 | radio.checked = true; 72 | } 73 | radio.addEventListener('change', () => { 74 | settings.update(name, value); 75 | }); 76 | label.appendChild(radio); 77 | 78 | // Text 79 | appendText(label, ' '); 80 | appendLocaleText(label, button[2]); 81 | } 82 | } 83 | }); 84 | } 85 | 86 | /* Localization */ 87 | function localize() { 88 | for(let loc of [ 89 | // [selector, message name] 90 | ['p.header', 'optionsHeader'], 91 | ]) { 92 | // Apply locale messages to elements 93 | for(let elem of document.querySelectorAll(loc[0])) { 94 | appendLocaleText(elem, loc[1]); 95 | } 96 | } 97 | } 98 | 99 | // Avoid unsafe assignment to innerHTML by manually creating DOM elements. 100 | // Uses Markdown syntax for replacing "[name](url)" with a HTML link. 101 | function appendLocaleText(elem, name) { 102 | // Get message 103 | let str = chrome.i18n.getMessage(name); 104 | 105 | // Regex: https://regex101.com/r/214K89/2 106 | let re = /\[(.*?)\]\((.*?)\)/g; 107 | let i = 0; 108 | let m; 109 | while((m = re.exec(str)) != null) { 110 | // Add text 111 | appendText(elem, str.substr(i, m.index-i)); 112 | i = m.index + m[0].length; 113 | 114 | // Add link 115 | let a = document.createElement('a'); 116 | a.href = m[2]; 117 | appendText(a, m[1]); 118 | elem.appendChild(a); 119 | } 120 | 121 | // Add remaining text 122 | appendText(elem, str.substr(i)); 123 | } 124 | 125 | function appendText(elem, str) { 126 | if(str.length > 0) { 127 | elem.appendChild(document.createTextNode(str)); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/settings.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Persistant storage of user settings 4 | class Settings { 5 | constructor() { 6 | this.s = new Map([ 7 | [ 8 | 'allowNid', 9 | { 10 | locale: 'preferencesCookie', 11 | name: 'NID', 12 | value: 0, 13 | }, 14 | ], 15 | [ 16 | 'allowConsent', 17 | { 18 | locale: 'consentCookie', 19 | name: 'CONSENT', 20 | value: 1, 21 | }, 22 | ], 23 | [ 24 | 'allowAbuseExemption', 25 | { 26 | locale: 'captchaCookie', 27 | name: 'GOOGLE_ABUSE_EXEMPTION', 28 | value: 1, 29 | } 30 | ], 31 | [ 32 | 'allowCookieChoices', 33 | { 34 | locale: 'cookieChoicesCookie', 35 | name: 'SOCS', 36 | value: 1, 37 | } 38 | ] 39 | ]); 40 | } 41 | 42 | // Update value and send a notification 43 | update(name, value) { 44 | this.set(name, value); 45 | this.setStorage(name, value, () => { 46 | // Send notification 47 | chrome.runtime.sendMessage({action: 'settingsChanged'}); 48 | }); 49 | } 50 | 51 | // Update storage. Callback is called after value has been stored. 52 | setStorage(name, value, callback = () => {}) { 53 | let item = {}; 54 | item[name] = value; 55 | chrome.storage.sync.set(item, callback); 56 | } 57 | 58 | // Update local map 59 | set(name, value) { 60 | let cookie = this.s.get(name); 61 | cookie.value = value; 62 | this.s.set(name, cookie); 63 | } 64 | 65 | get(name) { 66 | return this.s.get(name); 67 | } 68 | 69 | // Returns key/value tuples for setting 70 | getAll() { 71 | return this.s.entries(); 72 | } 73 | 74 | // Load the settings. Setting values are available after callback is called. 75 | load(callback) { 76 | chrome.storage.sync.get(null, (items) => { 77 | for(let [name, cookie] of this.s) { 78 | if(items[name] !== undefined) { 79 | // Use value that has already been stored 80 | this.set(name, items[name]); 81 | } else { 82 | // Initialize default value on storage 83 | this.setStorage(name, cookie.value); 84 | } 85 | } 86 | callback(); 87 | }); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/start.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | start(); 4 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | To run the tests: 2 | `cd` into this directory 3 | `$ npm install` 4 | `$ npm test` 5 | -------------------------------------------------------------------------------- /test/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "assert": { 6 | "version": "1.4.1", 7 | "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", 8 | "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", 9 | "dev": true, 10 | "requires": { 11 | "util": "0.10.3" 12 | } 13 | }, 14 | "balanced-match": { 15 | "version": "1.0.0", 16 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 17 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 18 | "dev": true 19 | }, 20 | "brace-expansion": { 21 | "version": "1.1.11", 22 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 23 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 24 | "dev": true, 25 | "requires": { 26 | "balanced-match": "^1.0.0", 27 | "concat-map": "0.0.1" 28 | } 29 | }, 30 | "browser-stdout": { 31 | "version": "1.3.1", 32 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 33 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 34 | "dev": true 35 | }, 36 | "commander": { 37 | "version": "2.15.1", 38 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", 39 | "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", 40 | "dev": true 41 | }, 42 | "concat-map": { 43 | "version": "0.0.1", 44 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 45 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 46 | "dev": true 47 | }, 48 | "debug": { 49 | "version": "3.1.0", 50 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 51 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 52 | "dev": true, 53 | "requires": { 54 | "ms": "2.0.0" 55 | } 56 | }, 57 | "diff": { 58 | "version": "3.5.0", 59 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 60 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 61 | "dev": true 62 | }, 63 | "escape-string-regexp": { 64 | "version": "1.0.5", 65 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 66 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 67 | "dev": true 68 | }, 69 | "fs.realpath": { 70 | "version": "1.0.0", 71 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 72 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 73 | "dev": true 74 | }, 75 | "glob": { 76 | "version": "7.1.2", 77 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 78 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 79 | "dev": true, 80 | "requires": { 81 | "fs.realpath": "^1.0.0", 82 | "inflight": "^1.0.4", 83 | "inherits": "2", 84 | "minimatch": "^3.0.4", 85 | "once": "^1.3.0", 86 | "path-is-absolute": "^1.0.0" 87 | } 88 | }, 89 | "growl": { 90 | "version": "1.10.5", 91 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 92 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 93 | "dev": true 94 | }, 95 | "has-flag": { 96 | "version": "3.0.0", 97 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 98 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 99 | "dev": true 100 | }, 101 | "he": { 102 | "version": "1.1.1", 103 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 104 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 105 | "dev": true 106 | }, 107 | "inflight": { 108 | "version": "1.0.6", 109 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 110 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 111 | "dev": true, 112 | "requires": { 113 | "once": "^1.3.0", 114 | "wrappy": "1" 115 | } 116 | }, 117 | "inherits": { 118 | "version": "2.0.3", 119 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 120 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 121 | "dev": true 122 | }, 123 | "minimatch": { 124 | "version": "3.0.4", 125 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 126 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 127 | "dev": true, 128 | "requires": { 129 | "brace-expansion": "^1.1.7" 130 | } 131 | }, 132 | "minimist": { 133 | "version": "0.0.8", 134 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 135 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 136 | "dev": true 137 | }, 138 | "mkdirp": { 139 | "version": "0.5.1", 140 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 141 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 142 | "dev": true, 143 | "requires": { 144 | "minimist": "0.0.8" 145 | } 146 | }, 147 | "mocha": { 148 | "version": "5.2.0", 149 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", 150 | "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", 151 | "dev": true, 152 | "requires": { 153 | "browser-stdout": "1.3.1", 154 | "commander": "2.15.1", 155 | "debug": "3.1.0", 156 | "diff": "3.5.0", 157 | "escape-string-regexp": "1.0.5", 158 | "glob": "7.1.2", 159 | "growl": "1.10.5", 160 | "he": "1.1.1", 161 | "minimatch": "3.0.4", 162 | "mkdirp": "0.5.1", 163 | "supports-color": "5.4.0" 164 | } 165 | }, 166 | "ms": { 167 | "version": "2.0.0", 168 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 169 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 170 | "dev": true 171 | }, 172 | "once": { 173 | "version": "1.4.0", 174 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 175 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 176 | "dev": true, 177 | "requires": { 178 | "wrappy": "1" 179 | } 180 | }, 181 | "path-is-absolute": { 182 | "version": "1.0.1", 183 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 184 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 185 | "dev": true 186 | }, 187 | "supports-color": { 188 | "version": "5.4.0", 189 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", 190 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", 191 | "dev": true, 192 | "requires": { 193 | "has-flag": "^3.0.0" 194 | } 195 | }, 196 | "util": { 197 | "version": "0.10.3", 198 | "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", 199 | "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", 200 | "dev": true, 201 | "requires": { 202 | "inherits": "2.0.1" 203 | }, 204 | "dependencies": { 205 | "inherits": { 206 | "version": "2.0.1", 207 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", 208 | "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", 209 | "dev": true 210 | } 211 | } 212 | }, 213 | "wrappy": { 214 | "version": "1.0.2", 215 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 216 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 217 | "dev": true 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "test": "mocha" 4 | }, 5 | "devDependencies": { 6 | "assert": "^1.4.1", 7 | "mocha": "^5.2.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let assert = require('assert'); 4 | let searchonymous = require('../src/background.js'); 5 | 6 | describe('Whitelist Cookie', () => { 7 | let tests = [ 8 | /*[ 9 | Name, 10 | Whitelist, 11 | Input cookies, 12 | Expected output cookies, 13 | ],*/ 14 | [ 15 | 'Empty whitelist', 16 | [], 17 | 'CONSENT=WP.276asd; 1P_JAR=2019-2-17-20; NID=160=ZFBK', 18 | '', 19 | ], 20 | [ 21 | 'Empty string', 22 | ['NID', 'CONSENT'], 23 | '', 24 | '', 25 | ], 26 | [ 27 | 'Only NID and CONSENT', 28 | ['NID', 'CONSENT'], 29 | 'CONSENT=WP.276asd; 1P_JAR=2019-2-17-20; NID=160=ZFBK', 30 | 'CONSENT=WP.276asd; NID=160=ZFBK', 31 | ], 32 | [ 33 | 'Semicolon', 34 | ['COOK1', 'COOK2', 'asd'], 35 | 'COOK1=hello; COOK2=worl;d; asd=dsa', 36 | 'COOK1=hello; COOK2=worl;d; asd=dsa', 37 | ], 38 | [ 39 | 'Same name', 40 | ['COOK'], 41 | 'COOK=hello; COOK=worl;d; COOK=dsa', 42 | 'COOK=hello; COOK=worl;d; COOK=dsa', 43 | ], 44 | ]; 45 | for(let test of tests) { 46 | it(test[0], () => { 47 | assert.equal(searchonymous.getWhitelistedCookies(test[2], test[1]), test[3]); 48 | }); 49 | } 50 | }); 51 | 52 | describe('Google search URL', () => { 53 | let tests = [ 54 | /*[ 55 | Name, 56 | URL, 57 | Is Google search URL, 58 | ],*/ 59 | [ 60 | 'Homepage', 61 | 'https://www.google.com/', 62 | true, 63 | ], 64 | [ 65 | 'Homepage', 66 | 'https://video.google.com/webhp?asd', 67 | true, 68 | ], 69 | [ 70 | 'Homepage False', 71 | 'https://video.google.com/webhptest?asd', 72 | false, 73 | ], 74 | [ 75 | 'Homepage', 76 | 'http://google.com', 77 | true, 78 | ], 79 | [ 80 | 'Search', 81 | 'https://www.google.com/search?q=adads', 82 | true, 83 | ], 84 | [ 85 | 'Search', 86 | 'https://www.google.com/search/?q=adads', 87 | true, 88 | ], 89 | [ 90 | 'Search False', 91 | 'https://www.google.com/searchtest?q=adads', 92 | false, 93 | ], 94 | [ 95 | 'Images Home', 96 | 'https://images.google.com/', 97 | true, 98 | ], 99 | [ 100 | 'Images Autocomplete', 101 | 'https://images.google.com/complete/search?q=asd&psi=123', 102 | true, 103 | ], 104 | [ 105 | 'Favicon', 106 | 'https://www.google.com/favicon.ico', 107 | false, 108 | ], 109 | [ 110 | 'Consent', 111 | 'https://consent.google.com/status?continue=https://www.google.com&pc=s×tamp=123&gl=DE', 112 | false, 113 | ], 114 | [ 115 | 'Image', 116 | 'https://encrypted-tbn0.gstatic.com/images?q=tbn:asd-asd', 117 | false, 118 | ], 119 | [ 120 | 'Asset', 121 | 'https://www.google.de/images/nav_logo242.png', 122 | false, 123 | ], 124 | [ 125 | 'Preferences', 126 | 'https://www.google.de/preferences?hl=de&prev=https://www.google.de/search?source', 127 | true, 128 | ], 129 | [ 130 | 'Set Preferences', 131 | 'https://www.google.com/setprefs?sig=123=&submit2=Save+Preferences&hl=en&lang=en&lr=lang_en&safeui=images&num=30', 132 | true, 133 | ], 134 | [ 135 | 'Autocomplete', 136 | 'https://www.google.at/complete/search?q&cp=0&client=psy-ab&xssi=t&gs_ri=gws-wiz&hl=de&authuser=0&psi=', 137 | true, 138 | ], 139 | [ 140 | 'Autocomplete False', 141 | 'https://www.google.at/completetest/testsearch?q', 142 | false, 143 | ], 144 | [ 145 | 'Suggest Query', 146 | 'https://suggestqueries.google.com/complete/search?client=books&ds=bo&q=dfs&callback=_callbacks', 147 | true, 148 | ], 149 | [ 150 | 'Maps', 151 | 'https://www.google.com/maps/vt/pb=!2!1', 152 | false, 153 | ], 154 | [ 155 | 'Searchbox', 156 | 'https://www.google.com/images/searchbox_sprites283_hr.webp', 157 | false, 158 | ], 159 | [ 160 | 'News', // Carries Search parameter in POST 161 | 'https://news.google.com/_/DotsSplashUi/data/batchexecute?rpcids=123&f.sid=123&bl=boq_dotssplashserver_20190208.02_p0&hl=en-US&gl=US&_reqid=123&rt=c', 162 | true, 163 | ], 164 | [ 165 | 'Scholar', 166 | 'https://scholar.google.com/scholar?hl=en&as_sdt=0,5&q=asd&btnG=', 167 | true, 168 | ], 169 | [ 170 | 'Scholar Complete', 171 | 'https://scholar.google.com.bd/scholar_complete?q=asd&hl=en&as_sdt=0,5&btnG=', 172 | true, 173 | ], 174 | [ 175 | 'Scholar False', 176 | 'https://scholar.google.de/gen_nid', 177 | false, 178 | ], 179 | [ 180 | 'Account', 181 | 'https://myaccount.google.com/?pli=1', 182 | false, 183 | ], 184 | [ 185 | 'Mail', 186 | 'https://mail.google.com/mail/u/2', 187 | false, 188 | ], 189 | [ 190 | 'Youtube', 191 | 'https://www.youtube.com/', 192 | false, 193 | ], 194 | [ 195 | 'Webmaster Tools', 196 | 'https://www.google.com/webmasters/tools/home?hl=de', 197 | false, 198 | ], 199 | [ 200 | 'Webmaster Tools Search', 201 | 'https://search.google.com/_/SearchConsoleAggReportUi/mutate?ds.extension=123&sid=123', 202 | false, 203 | ], 204 | [ 205 | 'XHR Async irc', 206 | 'https://www.google.com/async/irc?q=asdd&async=iu:0,_id:irc_async,_pms:s,_fmt:pc', 207 | true, 208 | ], 209 | [ 210 | 'XHR Async bgasy', 211 | 'https://www.google.com/async/bgasy?ei=abc&yv=3&async=_fmt:jspb', 212 | true, 213 | ], 214 | [ 215 | 'XHR Async ecr', 216 | 'https://www.google.com/async/ecr?ei=abc&lei=123&yv=3&async=encoded_cache_key:abc,version_info:123,attempt:1,_fmt:jspb', 217 | true, 218 | ], 219 | [ 220 | 'XHR Async False', 221 | 'https://www.google.com/async/test?123', 222 | false, 223 | ], 224 | [ 225 | 'XHR gen_204', 226 | 'https://www.google.com/gen_204?s=web&t=aft&atyp=csi&ei=abc', 227 | true, 228 | ], 229 | [ 230 | 'XHR client_204', 231 | 'https://www.google.com/client_204?&atyp=i&biw=123&bih=123&ei=abc', 232 | true, 233 | ], 234 | ]; 235 | 236 | for(let test of tests) { 237 | it(test[0], () => { 238 | assert.equal(searchonymous.isSearchUrl(test[1]), test[2]); 239 | }) 240 | }; 241 | }); 242 | --------------------------------------------------------------------------------