diff --git a/src/drivers/npm/README.md b/src/drivers/npm/README.md index 3214b693c..964d008c3 100644 --- a/src/drivers/npm/README.md +++ b/src/drivers/npm/README.md @@ -49,7 +49,7 @@ node index.js [url] [options] const Wappalyzer = require('./driver'); const Browser = require('./browsers/zombie'); -const url = 'https://www.wappalyzer.com; +const url = 'https://www.wappalyzer.com'; const options = { debug: false, diff --git a/src/drivers/npm/npm-shrinkwrap.json b/src/drivers/npm/npm-shrinkwrap.json index 13f73e610..591fba283 100644 --- a/src/drivers/npm/npm-shrinkwrap.json +++ b/src/drivers/npm/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "wappalyzer", - "version": "5.6.2", + "version": "5.7.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/drivers/npm/package.json b/src/drivers/npm/package.json index 9f13dce1b..58c102d85 100644 --- a/src/drivers/npm/package.json +++ b/src/drivers/npm/package.json @@ -2,7 +2,7 @@ "name": "wappalyzer", "description": "Uncovers the technologies used on websites", "homepage": "https://github.com/AliasIO/Wappalyzer", - "version": "5.6.3", + "version": "5.7.2", "author": "Elbert Alias", "license": "GPL-3.0", "repository": { diff --git a/src/drivers/webextension/_locales/de/messages.json b/src/drivers/webextension/_locales/de/messages.json index 2406d1ecc..c8b72145d 100644 --- a/src/drivers/webextension/_locales/de/messages.json +++ b/src/drivers/webextension/_locales/de/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "Nichts zu tun." }, "noAppsDetected": { "message": "Keine Applikation entdeckt." }, "categoryPin": { "message": "Immer Icon anzeigen" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "CMS" }, "categoryName2": { "message": "Nachrichten Board" }, "categoryName3": { "message": "Datenbankverwaltung" }, diff --git a/src/drivers/webextension/_locales/el/messages.json b/src/drivers/webextension/_locales/el/messages.json index f55d876e8..f336695de 100644 --- a/src/drivers/webextension/_locales/el/messages.json +++ b/src/drivers/webextension/_locales/el/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "Καμία ενέργεια." }, "noAppsDetected": { "message": "Δεν ανιχνεύθηκαν εφαρμογές." }, "categoryPin": { "message": "Always show icon" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "CMS" }, "categoryName2": { "message": "Διαδικτυακό Φόρουμ" }, "categoryName3": { "message": "Διαχειριστής Βάσης Δεδομένων" }, diff --git a/src/drivers/webextension/_locales/en/messages.json b/src/drivers/webextension/_locales/en/messages.json index e240fa94b..df884a399 100644 --- a/src/drivers/webextension/_locales/en/messages.json +++ b/src/drivers/webextension/_locales/en/messages.json @@ -11,6 +11,9 @@ "nothingToDo": { "message": "Nothing to do here." }, "noAppsDetected": { "message": "No technologies detected." }, "categoryPin": { "message": "Always show icon" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, + "privacyPolicy": { "message": "Privacy policy" }, "categoryName1": { "message": "CMS" }, "categoryName2": { "message": "Message Board" }, "categoryName3": { "message": "Database Manager" }, diff --git a/src/drivers/webextension/_locales/es/messages.json b/src/drivers/webextension/_locales/es/messages.json index 4544705d9..741b88c9a 100644 --- a/src/drivers/webextension/_locales/es/messages.json +++ b/src/drivers/webextension/_locales/es/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "Nada que hacer aquí." }, "noAppsDetected": { "message": "Aplicaciones no detectadas." }, "categoryPin": { "message": "Always show icon" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "Gestor de Contenido" }, "categoryName2": { "message": "Foro" }, "categoryName3": { "message": "Gestor de Bases de Datos" }, diff --git a/src/drivers/webextension/_locales/fa/messages.json b/src/drivers/webextension/_locales/fa/messages.json index 47c3d5cc4..c5b190c30 100644 --- a/src/drivers/webextension/_locales/fa/messages.json +++ b/src/drivers/webextension/_locales/fa/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "هیچ چیز برای انجام اینجا نیست." }, "noAppsDetected": { "message": "هیچ فن آوری شناسایی نشده است." }, "categoryPin": { "message": "همیشه نماد را نشان بده" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "سیستم مدیریت محتوا" }, "categoryName2": { "message": "انجمن پیام" }, "categoryName3": { "message": "مدیر پایگاه داده" }, diff --git a/src/drivers/webextension/_locales/fr/messages.json b/src/drivers/webextension/_locales/fr/messages.json index 2075992f9..a0f34b1ed 100644 --- a/src/drivers/webextension/_locales/fr/messages.json +++ b/src/drivers/webextension/_locales/fr/messages.json @@ -11,6 +11,8 @@ "twitter": { "message": "Suivre Wappalyzer sur Twitter" }, "website": { "message": "Aller sur wappalyzer.com" }, "categoryPin": { "message": " Toujours afficher l'icône" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "CMS" }, "categoryName2": { "message": "Forum" }, "categoryName3": { "message": "Gestionnaire de base de données" }, diff --git a/src/drivers/webextension/_locales/gr/messages.json b/src/drivers/webextension/_locales/gr/messages.json index 25b1ed991..4ea87768e 100644 --- a/src/drivers/webextension/_locales/gr/messages.json +++ b/src/drivers/webextension/_locales/gr/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "Καμία ενέργεια." }, "noAppsDetected": { "message": "Δεν ανιχνεύθηκαν εφαρμογές." }, "categoryPin": { "message": "Always show icon" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "CMS" }, "categoryName2": { "message": "Διαδικτυακό Φόρουμ" }, "categoryName3": { "message": "Διαχειριστής Βάσης Δεδομένων" }, diff --git a/src/drivers/webextension/_locales/id/messages.json b/src/drivers/webextension/_locales/id/messages.json index c701cc5a3..e0b350859 100644 --- a/src/drivers/webextension/_locales/id/messages.json +++ b/src/drivers/webextension/_locales/id/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "Tak ada yang dilakukan disini." }, "noAppsDetected": { "message": "Tidak ada aplikasi yang terdeteksi." }, "categoryPin": { "message": "Always show icon" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "Sistem Pengelola Konten" }, "categoryName2": { "message": "Papan Pesan" }, "categoryName3": { "message": "Pengelola Basis Data" }, diff --git a/src/drivers/webextension/_locales/it/messages.json b/src/drivers/webextension/_locales/it/messages.json index fc5bca2a3..7fba4c39d 100644 --- a/src/drivers/webextension/_locales/it/messages.json +++ b/src/drivers/webextension/_locales/it/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "Niente da fare qui." }, "noAppsDetected": { "message": "Nessuna applicazione rilevata." }, "categoryPin": { "message": "Always show icon" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "CMS" }, "categoryName2": { "message": "Forum" }, "categoryName3": { "message": "Gestore di Database" }, diff --git a/src/drivers/webextension/_locales/pl/messages.json b/src/drivers/webextension/_locales/pl/messages.json index c0bb41051..e6eb2720f 100644 --- a/src/drivers/webextension/_locales/pl/messages.json +++ b/src/drivers/webextension/_locales/pl/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "Nic tu nie ma." }, "noAppsDetected": { "message": "Nie wykryto żadnych aplikacji." }, "categoryPin": { "message": "Zawsze pokazuj tą ikonę" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "System zarządzania treścią" }, "categoryName2": { "message": "Forum" }, "categoryName3": { "message": "Menedżer baz danych" }, diff --git a/src/drivers/webextension/_locales/pt/messages.json b/src/drivers/webextension/_locales/pt/messages.json index 42d670b84..e4ab9fb3c 100644 --- a/src/drivers/webextension/_locales/pt/messages.json +++ b/src/drivers/webextension/_locales/pt/messages.json @@ -11,6 +11,8 @@ "twitter": { "message": "Seguir Wappalyzer no Twitter" }, "website": { "message": "Ir para wappalyzer.com" }, "categoryPin": { "message": "Mostrar sempre ícone" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "CMS" }, "categoryName2": { "message": "Fórum" }, "categoryName3": { "message": "Gestor de Base de Dados" }, diff --git a/src/drivers/webextension/_locales/pt_BR/messages.json b/src/drivers/webextension/_locales/pt_BR/messages.json index 0ff89115f..085701851 100644 --- a/src/drivers/webextension/_locales/pt_BR/messages.json +++ b/src/drivers/webextension/_locales/pt_BR/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "Nada a fazer aqui." }, "noAppsDetected": { "message": "Nenhuma tecnologia identificada." }, "categoryPin": { "message": "Sempre mostrar ícone" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "CMS" }, "categoryName2": { "message": "Fórum" }, "categoryName3": { "message": "Gestão de banco de dados" }, diff --git a/src/drivers/webextension/_locales/ro/messages.json b/src/drivers/webextension/_locales/ro/messages.json index c19f3b3be..09ef0b8b5 100644 --- a/src/drivers/webextension/_locales/ro/messages.json +++ b/src/drivers/webextension/_locales/ro/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "Nimic de făcut pe pagina curentă." }, "noAppsDetected": { "message": "Nici o aplicație detectată." }, "categoryPin": { "message": "Afișează icon tot timpul" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "CMS" }, "categoryName2": { "message": "Forum de discuții" }, "categoryName3": { "message": "Manager baze de date" }, diff --git a/src/drivers/webextension/_locales/ru/messages.json b/src/drivers/webextension/_locales/ru/messages.json index dc7bf4f04..5e165a189 100644 --- a/src/drivers/webextension/_locales/ru/messages.json +++ b/src/drivers/webextension/_locales/ru/messages.json @@ -64,6 +64,8 @@ "twitter": { "message": "Следите за новостями в Твиттере" }, "website": { "message": "Перейти на Wappalyzer.com" }, "categoryPin": { "message": "Always show icon" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName54": { "message": "SEO" }, "categoryName55": { "message": "Бухгалтерский учёт" }, "categoryName56": { "message": "Криптомайнер" }, diff --git a/src/drivers/webextension/_locales/sk/messages.json b/src/drivers/webextension/_locales/sk/messages.json index 3ee7b0574..96eec610c 100644 --- a/src/drivers/webextension/_locales/sk/messages.json +++ b/src/drivers/webextension/_locales/sk/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "Nie je tu čo robiť." }, "noAppsDetected": { "message": "Žiadne aplikácie neboli zistené." }, "categoryPin": { "message": "Always show icon" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "CMS" }, "categoryName2": { "message": "Message Board" }, "categoryName3": { "message": "Správca databáz" }, diff --git a/src/drivers/webextension/_locales/tr/messages.json b/src/drivers/webextension/_locales/tr/messages.json index 8ea12ccb8..1c886d971 100644 --- a/src/drivers/webextension/_locales/tr/messages.json +++ b/src/drivers/webextension/_locales/tr/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "Burada yapacak birşey yok." }, "noAppsDetected": { "message": "Uygulamalar tespit edilemedi." }, "categoryPin": { "message": "Always show icon" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "CMS" }, "categoryName2": { "message": "Mesaj Tahtası" }, "categoryName3": { "message": "Veritabanı Yöneticisi" }, diff --git a/src/drivers/webextension/_locales/uk/messages.json b/src/drivers/webextension/_locales/uk/messages.json index f159d8be5..2f99dbb8c 100644 --- a/src/drivers/webextension/_locales/uk/messages.json +++ b/src/drivers/webextension/_locales/uk/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "Тут нічого робити." }, "noAppsDetected": { "message": "Нічого не знайдено." }, "categoryPin": { "message": "Always show icon" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "CMS" }, "categoryName2": { "message": "Форум" }, "categoryName3": { "message": "Менеджер БД" }, diff --git a/src/drivers/webextension/_locales/uz/messages.json b/src/drivers/webextension/_locales/uz/messages.json index 97b26ce87..ae5e62cdb 100644 --- a/src/drivers/webextension/_locales/uz/messages.json +++ b/src/drivers/webextension/_locales/uz/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "Bu yerda tekshirib bolmaydi." }, "noAppsDetected": { "message": "Hech qanday dastur aniqlanmadi." }, "categoryPin": { "message": "Always show icon" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "CMS (KBT)" }, "categoryName2": { "message": "Forum" }, "categoryName3": { "message": "MB boshqaruvi" }, diff --git a/src/drivers/webextension/_locales/zh_CN/messages.json b/src/drivers/webextension/_locales/zh_CN/messages.json index c37a1799e..86ba50ca1 100644 --- a/src/drivers/webextension/_locales/zh_CN/messages.json +++ b/src/drivers/webextension/_locales/zh_CN/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "这儿啥也没有。" }, "noAppsDetected": { "message": "未检测到任何应用。" }, "categoryPin": { "message": "Always show icon" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "内容管理系统(CMS)" }, "categoryName2": { "message": "消息板" }, "categoryName3": { "message": "数据库管理器" }, diff --git a/src/drivers/webextension/_locales/zh_TW/messages.json b/src/drivers/webextension/_locales/zh_TW/messages.json index 6c543217d..50a094f6e 100644 --- a/src/drivers/webextension/_locales/zh_TW/messages.json +++ b/src/drivers/webextension/_locales/zh_TW/messages.json @@ -11,6 +11,8 @@ "nothingToDo": { "message": "這裡什麼也沒有。" }, "noAppsDetected": { "message": "未識別到技術。" }, "categoryPin": { "message": "永遠顯示圖示" }, + "termsAccept": { "message": "Accept" }, + "termsContent": { "message": "This extension sends anonymous information about websites you visit, including domain name and identified technologies, to wappalyzer.com. This can be disabled in the settings." }, "categoryName1": { "message": "內容管理系統(CMS)" }, "categoryName2": { "message": "留言板/討論區" }, "categoryName3": { "message": "資料庫管理" }, diff --git a/src/drivers/webextension/css/popup.css b/src/drivers/webextension/css/popup.css index b9d7c90fb..bd5efa916 100644 --- a/src/drivers/webextension/css/popup.css +++ b/src/drivers/webextension/css/popup.css @@ -155,3 +155,48 @@ body { .empty__text { } + +.terms { + align-items: center; + display: flex; + flex-direction: column; + justify-content: center; + height: 100%; + width: 100%; +} + +.terms__wrapper { + display: none; + height: 100%; + width: 100%; +} + +.terms__wrapper--active { + display: block; +} + +.terms__content { + font-size: .9rem; + line-height: 150%; + text-align: center; + margin-bottom: 1rem; + width: 80%; +} + +.terms__accept { + background-color: #4608ad; + border: none; + border-radius: 3px; + color: white; + cursor: pointer; + font-size: .9rem; + padding: .8rem 3rem; +} + +.terms__accept:hover { + background-color: #4107a1; +} + +.terms__privacy { + margin-top: 1rem; +} diff --git a/src/drivers/webextension/html/popup.html b/src/drivers/webextension/html/popup.html index b453b70c3..2a7d662dc 100644 --- a/src/drivers/webextension/html/popup.html +++ b/src/drivers/webextension/html/popup.html @@ -17,6 +17,16 @@ -
+
+
+
+
+ + + + +
+
+
diff --git a/src/drivers/webextension/js/content.js b/src/drivers/webextension/js/content.js index f5f350c49..6111d1830 100644 --- a/src/drivers/webextension/js/content.js +++ b/src/drivers/webextension/js/content.js @@ -66,7 +66,7 @@ if (typeof browser !== 'undefined' && typeof document.body !== 'undefined') { postMessage({ id: 'patterns', patterns: response.patterns, - }, '*'); + }, window.location.href); } }); }; diff --git a/src/drivers/webextension/js/driver.js b/src/drivers/webextension/js/driver.js index c1703ed5c..5d8962f17 100644 --- a/src/drivers/webextension/js/driver.js +++ b/src/drivers/webextension/js/driver.js @@ -3,9 +3,10 @@ */ /* eslint-env browser */ -/* global browser, fetch, Wappalyzer */ +/* global browser, chrome, fetch, Wappalyzer */ /** global: browser */ +/** global: chrome */ /** global: fetch */ /** global: Wappalyzer */ @@ -20,6 +21,22 @@ browser.tabs.onRemoved.addListener((tabId) => { tabCache[tabId] = null; }); +function userAgent() { + const url = chrome.extension.getURL('/'); + + if (url.match(/^chrome-/)) { + return 'chrome'; + } + + if (url.match(/^moz-/)) { + return 'firefox'; + } + + if (url.match(/^ms-browser-/)) { + return 'edge'; + } +} + /** * Get a value from localStorage */ @@ -160,6 +177,7 @@ browser.runtime.onMessage.addListener(async (message, sender) => { apps: wappalyzer.apps, categories: wappalyzer.categories, pinnedCategory, + termsAccepted: userAgent() === 'chrome' || await getOption('termsAccepted', false), }; break; @@ -295,8 +313,9 @@ wappalyzer.driver.getRobotsTxt = async (host, secure = false) => { */ wappalyzer.driver.ping = async (hostnameCache = {}, adCache = []) => { const tracking = await getOption('tracking', true); + const termsAccepted = userAgent() === 'chrome' || await getOption('termsAccepted', false); - if (tracking) { + if (tracking && termsAccepted) { if (Object.keys(hostnameCache).length) { post('https://api.wappalyzer.com/ping/v1/', hostnameCache); } diff --git a/src/drivers/webextension/js/inject.js b/src/drivers/webextension/js/inject.js index 1d790efe2..3e9a6658f 100644 --- a/src/drivers/webextension/js/inject.js +++ b/src/drivers/webextension/js/inject.js @@ -53,7 +53,7 @@ } } - postMessage({ id: 'js', js }, '*'); + postMessage({ id: 'js', js }, window.location.href); }; addEventListener('message', onMessage); diff --git a/src/drivers/webextension/js/lib/iframe.js b/src/drivers/webextension/js/lib/iframe.js index 651e9e547..491d26257 100644 --- a/src/drivers/webextension/js/lib/iframe.js +++ b/src/drivers/webextension/js/lib/iframe.js @@ -882,7 +882,7 @@ let win = window; while (win !== win.top) { win = win.parent; - win.postMessage(adData, '*'); + win.postMessage(adData, win.location.href); } } @@ -998,7 +998,7 @@ } if (!adData) return; - + if (adData.postMessageId === POST_MSG_ID) { delete adData.postMessageId; diff --git a/src/drivers/webextension/js/lib/network.js b/src/drivers/webextension/js/lib/network.js index 5831a2e04..ebae3bc7a 100644 --- a/src/drivers/webextension/js/lib/network.js +++ b/src/drivers/webextension/js/lib/network.js @@ -1,795 +1,792 @@ -(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i subjectString.length) { + position = subjectString.length; + } + position -= searchString.length; + const lastIndex = subjectString.indexOf(searchString, position); + return lastIndex !== -1 && lastIndex === position; + }; + } - let browserProxy; + function getFrame(getFrameDetails, callback) { if (isChrome()) { - browserProxy = chrome; - } else { - browserProxy = browser; - } - - const MIN_FF_MAJOR_VERSION = 51; - - const requiredBrowserApis = [ - browserProxy.webNavigation, - browserProxy.tabs, - browserProxy.webRequest, - browserProxy.runtime, - ]; - let areListenersRegistered = false; - const secBefore = 2000; - const secAfter = 5000; - const secBetweenDupAssets = 10e3; - const minVidSize = 500e3; - const maxVidSize = 25e6; - const maxContentRange = 25e6; - const videoExtensions = [ - 'af', '3gp', 'asf', 'avchd', 'avi', 'cam', 'dsh', 'flv', 'm1v', 'm2v', - 'fla', 'flr', 'sol', 'm4v', 'mkv', 'wrap', 'mng', 'mov', 'mpeg', 'mpg', - 'mpe', 'mp4', 'mxf', 'nsv', 'ogg', 'rm', 'svi', 'smi', 'wmv', 'webm', - ]; - const extensionsReg = new RegExp(`\\.${videoExtensions.join('$|\\.')}$`); - const videoContentTypesPrefixes = ['binary/octet-stream', 'video/', 'flv-application/', 'media']; - - const bannedContentTypes = ['video/mp2t', 'video/f4m', 'video/f4f']; - const bannedFiletypes = ['ts']; - const bannedFiletypesReg = new RegExp(`\\.${bannedFiletypes.join('$|\\.')}$`); - const whitelistReqTypes = ['object', 'xmlhttprequest', 'other']; - - const topVideoAssetDomains = [ - '2mdn.net', - 'adap.tv', - 'adnxs.com', - 'adsrvr.org', - 'btrll.com', - 'celtra.com', - 'flashtalking.com', - 'flite.com', - 'innovid.com', - 'jivox.com', - 'mixpo.com', - 'nytimes.com', - 'playwire.com', - 'selectmedia.asia', - 'serving-sys.com', - 'solvemedia.com', - 'spotible.com', - 'teads.tv', - 'tribalfusion.com', - 'tubemogul.com', - 'videologygroup.com', - 'washingtonpost.com', - ]; - - const robotsTxtAllows = wappalyzer.robotsTxtAllows.bind(wappalyzer); - if (!String.prototype.endsWith) { - String.prototype.endsWith = function (searchString, position) { - const subjectString = this.toString(); - if (typeof position !== 'number' || !isFinite(position) - || Math.floor(position) !== position || position > subjectString.length) { - position = subjectString.length; - } - position -= searchString.length; - const lastIndex = subjectString.indexOf(searchString, position); - return lastIndex !== -1 && lastIndex === position; - }; - } - - function getFrame(getFrameDetails, callback) { - if (isChrome()) { - chrome.webNavigation.getFrame(getFrameDetails, callback); - } else if (typeof browser !== 'undefined') { - const gettingFrame = browser.webNavigation.getFrame(getFrameDetails); - gettingFrame.then(callback); - } + chrome.webNavigation.getFrame(getFrameDetails, callback); + } else if (typeof browser !== 'undefined') { + const gettingFrame = browser.webNavigation.getFrame(getFrameDetails); + gettingFrame.then(callback); } + } - function ifBrowserValid(callback, elseCallback) { - if (isChrome()) { - callback(); - } else if (typeof browser !== 'undefined') { - try { - const gettingInfo = browser.runtime.getBrowserInfo(); - gettingInfo.then((browserInfo) => { - const browserVersion = parseInt(browserInfo.version.split('.')[0]); - - if (browserInfo.name === 'Firefox' - && browserVersion >= MIN_FF_MAJOR_VERSION) { - callback(); - } else { - elseCallback(); - } - }); - } catch (err) { - elseCallback(); - } - } else { - elseCallback(); - } - } - - function ifTrackingEnabled(details, ifCallback, elseCallback) { - const fullIfCallback = function () { - allowedByRobotsTxt(details, ifCallback, elseCallback); - }; - - browser.storage.local.get('tracking').then((item) => { - if (item.hasOwnProperty('tracking')) { - if (item.tracking) { - fullIfCallback(); + function ifBrowserValid(callback, elseCallback) { + if (isChrome()) { + callback(); + } else if (typeof browser !== 'undefined') { + try { + const gettingInfo = browser.runtime.getBrowserInfo(); + gettingInfo.then((browserInfo) => { + const browserVersion = parseInt(browserInfo.version.split('.')[0]); + + if (browserInfo.name === 'Firefox' + && browserVersion >= MIN_FF_MAJOR_VERSION) { + callback(); } else { elseCallback(); } - } else { - fullIfCallback(); - } - }); - } - - function allowedByRobotsTxt(details, ifCallback, elseCallback) { - if (details.url && !details.url.startsWith('chrome://')) { - robotsTxtAllows(details.url).then(ifCallback, elseCallback); - } else { + }); + } catch (err) { elseCallback(); } + } else { + elseCallback(); } + } - function isPixelRequest(request) { - return (request.type === 'image' || request.responseStatus === 204) - && request.size <= 1000; - } - - function isVpaidOrVastRequest(request) { - const lowerCaseUrl = request.url.toLowerCase(); - return lowerCaseUrl.indexOf('vpaid') !== -1 || lowerCaseUrl.indexOf('vast') !== -1; - } - - function hasValidRequestType(request) { - return whitelistReqTypes.indexOf(request.type) >= 0; - } - - function stripQueryParams(url) { - return url.split('?', 1)[0]; - } - - function parseHostnameFromUrl(url) { - const parser = document.createElement('a'); - parser.href = url; - return parser.hostname; - } - - function hasDomain(url, domain) { - return parseHostnameFromUrl(url).endsWith(domain); - } + function ifTrackingEnabled(details, ifCallback, elseCallback) { + const fullIfCallback = function () { + allowedByRobotsTxt(details, ifCallback, elseCallback); + }; - function findHeader(headers, key) { - let header; - for (let i = 0; i < headers.length; i += 1) { - header = headers[i]; - if (header.name.toLowerCase() === key) { - return header; + browser.storage.local.get('tracking').then((item) => { + if (item.hasOwnProperty('tracking')) { + if (item.tracking) { + fullIfCallback(); + } else { + elseCallback(); } + } else { + fullIfCallback(); } - return null; - } + }); + } - function validVideoType(vtype) { - const goodType = videoContentTypesPrefixes.some(prefix => vtype.indexOf(prefix) === 0); - return goodType; + function allowedByRobotsTxt(details, ifCallback, elseCallback) { + if (details.url && !details.url.startsWith('chrome://')) { + robotsTxtAllows(details.url).then(ifCallback, elseCallback); + } else { + elseCallback(); } - - function assetMsgKey(assetReq) { - const url = stripQueryParams(assetReq.url); - const key = `${assetReq.frameId}-${url}`; - return key; + } + + function isPixelRequest(request) { + return (request.type === 'image' || request.responseStatus === 204) + && request.size <= 1000; + } + + function isVpaidOrVastRequest(request) { + const lowerCaseUrl = request.url.toLowerCase(); + return lowerCaseUrl.indexOf('vpaid') !== -1 || lowerCaseUrl.indexOf('vast') !== -1; + } + + function hasValidRequestType(request) { + return whitelistReqTypes.indexOf(request.type) >= 0; + } + + function stripQueryParams(url) { + return url.split('?', 1)[0]; + } + + function parseHostnameFromUrl(url) { + const parser = document.createElement('a'); + parser.href = url; + return parser.hostname; + } + + function hasDomain(url, domain) { + return parseHostnameFromUrl(url).endsWith(domain); + } + + function findHeader(headers, key) { + let header; + for (let i = 0; i < headers.length; i += 1) { + header = headers[i]; + if (header.name.toLowerCase() === key) { + return header; + } } + return null; + } + + function validVideoType(vtype) { + const goodType = videoContentTypesPrefixes.some(prefix => vtype.indexOf(prefix) === 0); + return goodType; + } + + function assetMsgKey(assetReq) { + const url = stripQueryParams(assetReq.url); + const key = `${assetReq.frameId}-${url}`; + return key; + } + + const PageNetworkTrafficCollector = function (tabId) { + this.tabId = tabId; + this.displayAdFound = false; + this.requests = {}; + this.msgsBeingSent = {}; + this.assetsSeen = {}; + this.allRedirects = {}; + }; + + var globalPageContainer = { + collectors: {}, + dyingCollectors: {}, + + cleanupCollector(tabId) { + if (tabId in this.collectors) { + delete globalPageContainer.collectors[tabId]; + } + }, + + onNewNavigation(details) { + const tabId = details.tabId; + this.cleanupCollector(tabId); + + ifTrackingEnabled( + details, + () => { + if (!areListenersRegistered) { + registerListeners(); + } + this.collectors[tabId] = new PageNetworkTrafficCollector(tabId); + }, + () => { + if (areListenersRegistered) { + unregisterListeners(); + } + }, + ); + }, - const PageNetworkTrafficCollector = function (tabId) { - this.tabId = tabId; - this.displayAdFound = false; - this.requests = {}; - this.msgsBeingSent = {}; - this.assetsSeen = {}; - this.allRedirects = {}; - }; - - var globalPageContainer = { - collectors: {}, - dyingCollectors: {}, - - cleanupCollector(tabId) { - if (tabId in this.collectors) { - delete globalPageContainer.collectors[tabId]; - } - }, - - onNewNavigation(details) { - const tabId = details.tabId; - this.cleanupCollector(tabId); + onNavigationCommitted(details) { - ifTrackingEnabled( - details, - () => { - if (!areListenersRegistered) { - registerListeners(); - } - this.collectors[tabId] = new PageNetworkTrafficCollector(tabId); - }, - () => { - if (areListenersRegistered) { - unregisterListeners(); - } - }, - ); - }, + }, - onNavigationCommitted(details) { + onNavigationCompleted(details) { - }, + }, - onNavigationCompleted(details) { + onTabClose(tabId, closeInfo) { + this.cleanupCollector(tabId); + delete this.collectors[tabId]; + }, - }, + onDisplayAdFound(tabId) { + this.collectors[tabId].displayAdFound = true; + }, - onTabClose(tabId, closeInfo) { - this.cleanupCollector(tabId); - delete this.collectors[tabId]; - }, + getRandId() { + return String(Math.floor(Math.random() * 1e9)); + }, - onDisplayAdFound(tabId) { - this.collectors[tabId].displayAdFound = true; - }, + getCollector(tabId) { + if (this.collectors.hasOwnProperty(tabId)) { + return this.collectors[tabId]; + } + return null; + }, + + forwardCall(details, collectorMemberFunction) { + const collector = this.getCollector(details.tabId); + if (collector !== null) { + collectorMemberFunction.apply(collector, [details]); + } + }, + }; + + PageNetworkTrafficCollector.prototype.sendLogMessageToTabConsole = function () { + const logMessage = Array.from(arguments).join(' '); + const message = { message: logMessage, event: 'console-log-message' }; + browserProxy.tabs.sendMessage(this.tabId, message); + }; + + PageNetworkTrafficCollector.prototype.sendToTab = function (assetReq, reqs, curPageUrl, adTrackingEvent) { + const msg = {}; + msg.assets = []; + msg.requests = []; + msg.event_data = {}; + msg.event = adTrackingEvent; + if (adTrackingEvent === 'new-video-ad') { + msg.requests = reqs; + msg.requests.sort((reqA, reqB) => reqA.requestTimestamp - reqB.requestTimestamp); + if (assetReq) { + msg.assets = [assetReq]; + } + } else if (adTrackingEvent === 'new-invalid-video-ad') { + msg.requests = reqs.map(request => parseHostnameFromUrl(request.url)); + msg.assets = [{ + + url: parseHostnameFromUrl(assetReq.url), + + contentType: assetReq.contentType, + size: assetReq.size, + }]; + } + msg.origUrl = curPageUrl; + msg.displayAdFound = this.displayAdFound; - getRandId() { - return String(Math.floor(Math.random() * 1e9)); - }, + browserProxy.tabs.sendMessage(this.tabId, msg); + }; - getCollector(tabId) { - if (this.collectors.hasOwnProperty(tabId)) { - return this.collectors[tabId]; - } - return null; - }, + PageNetworkTrafficCollector.prototype.getRedirKey = function (url, frameId) { + return `${url}:${frameId}`; + }; - forwardCall(details, collectorMemberFunction) { - const collector = this.getCollector(details.tabId); - if (collector !== null) { - collectorMemberFunction.apply(collector, [details]); - } - }, + PageNetworkTrafficCollector.prototype.seenBefore = function (request) { + const oldTime = this.assetsSeen[assetMsgKey(request)]; + if (oldTime && (request.requestTimestamp - oldTime < secBetweenDupAssets)) { + return true; + } + return false; + }; + + PageNetworkTrafficCollector.prototype.recordSeenAsset = function (request) { + this.assetsSeen[assetMsgKey(request)] = request.requestTimestamp; + }; + + PageNetworkTrafficCollector.prototype.onBeforeRequest = function (details) { + const req = { + url: details.url, + type: details.type, + httpMethod: details.method, + frameId: details.frameId, + parentFrameId: details.parentFrameId, + requestTimestamp: details.timeStamp, }; + this.requests[details.requestId] = req; + }; + + PageNetworkTrafficCollector.prototype.onSendHeaders = function (details) { + let request, + header; + request = this.requests[details.requestId]; + header = request && findHeader(details.requestHeaders, 'x-requested-with'); + if (header && header.value.toLowerCase().indexOf('flash') > -1) { + request.from_flash = true; + } + }; - PageNetworkTrafficCollector.prototype.sendLogMessageToTabConsole = function () { - const logMessage = Array.from(arguments).join(' '); - const message = { message: logMessage, event: 'console-log-message' }; - browserProxy.tabs.sendMessage(this.tabId, message); + PageNetworkTrafficCollector.prototype.onHeadersReceived = function (details) { + const getFrameDetails = { + tabId: details.tabId, + processId: null, + frameId: details.frameId, }; - - PageNetworkTrafficCollector.prototype.sendToTab = function (assetReq, reqs, curPageUrl, adTrackingEvent) { - const msg = {}; - msg.assets = []; - msg.requests = []; - msg.event_data = {}; - msg.event = adTrackingEvent; - if (adTrackingEvent === 'new-video-ad') { - msg.requests = reqs; - msg.requests.sort((reqA, reqB) => reqA.requestTimestamp - reqB.requestTimestamp); - if (assetReq) { - msg.assets = [assetReq]; - } - } else if (adTrackingEvent === 'new-invalid-video-ad') { - msg.requests = reqs.map(request => parseHostnameFromUrl(request.url)); - msg.assets = [{ - - url: parseHostnameFromUrl(assetReq.url), - - contentType: assetReq.contentType, - size: assetReq.size, - }]; + const pageNetworkTrafficController = this; + getFrame(getFrameDetails, (frameDetails) => { + if (frameDetails && frameDetails.url) { + pageNetworkTrafficController._onHeadersReceived(details, frameDetails); } - msg.origUrl = curPageUrl; - msg.displayAdFound = this.displayAdFound; + }); + }; - browserProxy.tabs.sendMessage(this.tabId, msg); - }; + PageNetworkTrafficCollector.prototype._onHeadersReceived = function (details, frameDetails) { + let contentSize, + contentRange; - PageNetworkTrafficCollector.prototype.getRedirKey = function (url, frameId) { - return `${url}:${frameId}`; - }; + const request = this.requests[details.requestId]; + if (request) { + const redirParent = this.allRedirects[this.getRedirKey(details.url, details.frameId)]; + let header = request && findHeader(details.responseHeaders, 'content-type'); + const contentType = header && header.value.toLowerCase(); - PageNetworkTrafficCollector.prototype.seenBefore = function (request) { - const oldTime = this.assetsSeen[assetMsgKey(request)]; - if (oldTime && (request.requestTimestamp - oldTime < secBetweenDupAssets)) { - return true; + if (contentType) { + request.contentType = contentType; } - return false; - }; - - PageNetworkTrafficCollector.prototype.recordSeenAsset = function (request) { - this.assetsSeen[assetMsgKey(request)] = request.requestTimestamp; - }; - - PageNetworkTrafficCollector.prototype.onBeforeRequest = function (details) { - const req = { - url: details.url, - type: details.type, - httpMethod: details.method, - frameId: details.frameId, - parentFrameId: details.parentFrameId, - requestTimestamp: details.timeStamp, - }; - this.requests[details.requestId] = req; - }; - - PageNetworkTrafficCollector.prototype.onSendHeaders = function (details) { - let request, - header; - request = this.requests[details.requestId]; - header = request && findHeader(details.requestHeaders, 'x-requested-with'); - if (header && header.value.toLowerCase().indexOf('flash') > -1) { - request.from_flash = true; + header = request && findHeader(details.responseHeaders, 'content-length'); + contentSize = header && header.value; + if (contentSize) { + request.size = request.size || 0; + request.size += parseInt(contentSize); + } + header = request && findHeader(details.responseHeaders, 'content-range'); + contentRange = header && header.value; + if (contentRange) { + request.contentRange = parseInt(contentRange.split('/')[1]); } - }; - PageNetworkTrafficCollector.prototype.onHeadersReceived = function (details) { - const getFrameDetails = { - tabId: details.tabId, - processId: null, - frameId: details.frameId, - }; - const pageNetworkTrafficController = this; - getFrame(getFrameDetails, (frameDetails) => { - if (frameDetails && frameDetails.url) { - pageNetworkTrafficController._onHeadersReceived(details, frameDetails); - } - }); - }; + let frameUrl = null; + if (frameDetails && frameDetails.url) { + frameUrl = frameDetails.url; + } + if (!this.bannedRequest(request) + && (this.isVideoReq(frameUrl, request) || (redirParent && redirParent.isVideo))) { + request.isVideo = true; + } + } + }; - PageNetworkTrafficCollector.prototype._onHeadersReceived = function (details, frameDetails) { - let contentSize, - contentRange; + PageNetworkTrafficCollector.prototype.onBeforeRedirect = function (details) { + const request = this.requests[details.requestId]; + if (request) { + if (request.redirects) { + request.redirects.push(details.redirectUrl); + } else { + request.redirects = [details.redirectUrl]; + } + this.allRedirects[this.getRedirKey(details.redirectUrl, details.frameId)] = request; + } + }; + + PageNetworkTrafficCollector.prototype.isYoutubeMastheadRequest = function (url) { + const re = /video_masthead/; + return this.hasYoutubeDomain(url) && re.test(url); + }; + PageNetworkTrafficCollector.prototype.isYoutubeVideoRequest = function (srcUrl, destUrl) { + if (!this.hasYoutubeDomain(srcUrl)) { + return false; + } - const request = this.requests[details.requestId]; + const re = /https?:\/\/r.*?\.googlevideo\.com\/videoplayback\?/; + return re.test(destUrl); + }; + PageNetworkTrafficCollector.prototype.processResponse = function (requestDetails, frameDetails) { + let request; + if (requestDetails) { + request = this.requests[requestDetails.requestId]; if (request) { - const redirParent = this.allRedirects[this.getRedirKey(details.url, details.frameId)]; - let header = request && findHeader(details.responseHeaders, 'content-type'); - const contentType = header && header.value.toLowerCase(); - - if (contentType) { - request.contentType = contentType; - } - header = request && findHeader(details.responseHeaders, 'content-length'); - contentSize = header && header.value; - if (contentSize) { - request.size = request.size || 0; - request.size += parseInt(contentSize); - } - header = request && findHeader(details.responseHeaders, 'content-range'); - contentRange = header && header.value; - if (contentRange) { - request.contentRange = parseInt(contentRange.split('/')[1]); - } + request.responseStatus = requestDetails.statusCode; + request.responseTimestamp = requestDetails.timeStamp; let frameUrl = null; if (frameDetails && frameDetails.url) { frameUrl = frameDetails.url; } - if (!this.bannedRequest(request) - && (this.isVideoReq(frameUrl, request) || (redirParent && redirParent.isVideo))) { - request.isVideo = true; - } - } - }; - PageNetworkTrafficCollector.prototype.onBeforeRedirect = function (details) { - const request = this.requests[details.requestId]; - if (request) { - if (request.redirects) { - request.redirects.push(details.redirectUrl); - } else { - request.redirects = [details.redirectUrl]; + let requestUrl = null; + if (request.url) { + requestUrl = request.url; } - this.allRedirects[this.getRedirKey(details.redirectUrl, details.frameId)] = request; - } - }; - - PageNetworkTrafficCollector.prototype.isYoutubeMastheadRequest = function (url) { - const re = /video_masthead/; - return this.hasYoutubeDomain(url) && re.test(url); - }; - PageNetworkTrafficCollector.prototype.isYoutubeVideoRequest = function (srcUrl, destUrl) { - if (!this.hasYoutubeDomain(srcUrl)) { - return false; - } - - const re = /https?:\/\/r.*?\.googlevideo\.com\/videoplayback\?/; - return re.test(destUrl); - }; - PageNetworkTrafficCollector.prototype.processResponse = function (requestDetails, frameDetails) { - let request; - if (requestDetails) { - request = this.requests[requestDetails.requestId]; - if (request) { - request.responseStatus = requestDetails.statusCode; - request.responseTimestamp = requestDetails.timeStamp; - - let frameUrl = null; - if (frameDetails && frameDetails.url) { - frameUrl = frameDetails.url; - } - let requestUrl = null; - if (request.url) { - requestUrl = request.url; - } - - if (this.isYoutubeAdReq(frameUrl, requestUrl)) { - const destVideoId = this.parseYoutubeVideoIdFromUrl(requestUrl); - const srcVideoId = this.parseYoutubeVideoIdFromUrl(frameUrl); - if (srcVideoId && destVideoId) { - request.isYoutubeAd = true; - request.isVideo = true; - request.rawSrcUrl = frameUrl; - request.rawDestUrl = requestUrl; - request.url = `https://www.youtube.com/watch?v=${this.parseYoutubeVideoIdFromUrl(requestUrl)}`; - } - } else if (!this.bannedRequest(request) - && (this.isVideo || this.isVideoReq(frameUrl, request))) { + if (this.isYoutubeAdReq(frameUrl, requestUrl)) { + const destVideoId = this.parseYoutubeVideoIdFromUrl(requestUrl); + const srcVideoId = this.parseYoutubeVideoIdFromUrl(frameUrl); + if (srcVideoId && destVideoId) { + request.isYoutubeAd = true; request.isVideo = true; + request.rawSrcUrl = frameUrl; + request.rawDestUrl = requestUrl; + request.url = `https://www.youtube.com/watch?v=${this.parseYoutubeVideoIdFromUrl(requestUrl)}`; } - - if (request.isVideo) { - const msgKey = assetMsgKey(request); - this.msgsBeingSent[msgKey] = request; - if (!this.seenBefore(request)) { - this.sendMsgWhenQuiet(msgKey); - } - this.recordSeenAsset(request); - } + } else if (!this.bannedRequest(request) + && (this.isVideo || this.isVideoReq(frameUrl, request))) { + request.isVideo = true; } - } - }; - PageNetworkTrafficCollector.prototype.onResponseStarted = function (responseDetails) { - if (responseDetails.frameId < 0) { - responseDetails.frameId = 99999; - } - const getFrameDetails = { - tabId: responseDetails.tabId, - processId: null, - frameId: responseDetails.frameId, - }; - const pageNetworkTrafficController = this; - getFrame(getFrameDetails, (frameDetails) => { - if (frameDetails && frameDetails.url) { - pageNetworkTrafficController.processResponse(responseDetails, frameDetails); + if (request.isVideo) { + const msgKey = assetMsgKey(request); + this.msgsBeingSent[msgKey] = request; + if (!this.seenBefore(request)) { + this.sendMsgWhenQuiet(msgKey); + } + this.recordSeenAsset(request); } - }); - }; - - PageNetworkTrafficCollector.prototype.hasBannedFiletype = function (request) { - const url = stripQueryParams(request.url); - if (bannedFiletypesReg.exec(url)) { - return true; - } - return false; - }; - - PageNetworkTrafficCollector.prototype.checkContentHeaders = function (request) { - if (request.contentType && validVideoType(request.contentType)) { - return true; - } - return false; - }; - - PageNetworkTrafficCollector.prototype.checkUrlExtension = function (request) { - const url = stripQueryParams(request.url); - if (extensionsReg.exec(url)) { - return true; } - return false; - }; + } + }; - PageNetworkTrafficCollector.prototype.isVideoReq = function (srcUrl, request) { - if (this.isYoutubeVideoRequest(srcUrl, request.url)) { - return false; - } - return this.checkUrlExtension(request) || this.checkContentHeaders(request); - }; - PageNetworkTrafficCollector.prototype.hasYoutubeDomain = function (url) { - const hostname = parseHostnameFromUrl(url); - if (hostname === 'www.youtube.com') { - return true; - } - return false; + PageNetworkTrafficCollector.prototype.onResponseStarted = function (responseDetails) { + if (responseDetails.frameId < 0) { + responseDetails.frameId = 99999; + } + const getFrameDetails = { + tabId: responseDetails.tabId, + processId: null, + frameId: responseDetails.frameId, }; - PageNetworkTrafficCollector.prototype.parseYoutubeVideoIdFromUrl = function (url) { - let re = /^https?:\/\/www\.youtube\.com\/get_video_info.*(?:\?|&)video_id=(.*?)(?:$|&)/; - let match = re.exec(url); - if (match && match.length > 1) { - return match[1]; - } - - re = /^https?:\/\/www\.youtube\.com\/embed\/(.*?)(?:$|\?)/; - match = re.exec(url); - if (match && match.length > 1) { - return match[1]; - } - - re = /^https?:\/\/www\.youtube\.com\/watch.*(\?|&)v=([^&]*)/; - match = re.exec(url); - if (match && match.length > 1) { - return match[1]; + const pageNetworkTrafficController = this; + getFrame(getFrameDetails, (frameDetails) => { + if (frameDetails && frameDetails.url) { + pageNetworkTrafficController.processResponse(responseDetails, frameDetails); } - return null; - }; + }); + }; - PageNetworkTrafficCollector.prototype.isYoutubeGetVideoInfoReq = function (url) { - const re = /^https?:\/\/www\.youtube\.com\/get_video_info\?/; - return re.test(url); - }; - PageNetworkTrafficCollector.prototype.isYoutubeAdReq = function (srcUrl, destUrl) { - if (!this.hasYoutubeDomain(srcUrl) - || !this.isYoutubeGetVideoInfoReq(destUrl)) { - return false; - } - if (this.parseYoutubeVideoIdFromUrl(srcUrl) - === this.parseYoutubeVideoIdFromUrl(destUrl) - && !this.isYoutubeMastheadRequest(destUrl)) { - return false; - } + PageNetworkTrafficCollector.prototype.hasBannedFiletype = function (request) { + const url = stripQueryParams(request.url); + if (bannedFiletypesReg.exec(url)) { return true; - }; + } + return false; + }; - PageNetworkTrafficCollector.prototype.bannedRequest = function (request) { - return this.bannedVideoType(request) || this.hasBannedFiletype(request) || this.bannedVideoSize(request); - }; + PageNetworkTrafficCollector.prototype.checkContentHeaders = function (request) { + if (request.contentType && validVideoType(request.contentType)) { + return true; + } + return false; + }; - PageNetworkTrafficCollector.prototype.bannedVideoType = function (request) { - let badType = false; - if (request.contentType) { - badType = bannedContentTypes.some(prefix => request.contentType.indexOf(prefix) >= 0); - } - return badType; - }; + PageNetworkTrafficCollector.prototype.checkUrlExtension = function (request) { + const url = stripQueryParams(request.url); + if (extensionsReg.exec(url)) { + return true; + } + return false; + }; - PageNetworkTrafficCollector.prototype.bannedVideoSize = function (request) { - if (request.size !== null) { - if (request.size < minVidSize || request.size > maxVidSize || request.contentRange > maxContentRange) { - return true; - } - } + PageNetworkTrafficCollector.prototype.isVideoReq = function (srcUrl, request) { + if (this.isYoutubeVideoRequest(srcUrl, request.url)) { return false; - }; - - PageNetworkTrafficCollector.prototype.grabTagReqs = function (tabRequests, assetRequest) { - let minTimestamp, - maxTimestamp; - minTimestamp = assetRequest.requestTimestamp - secBefore; - maxTimestamp = assetRequest.requestTimestamp + secAfter; - - const filteredRequests = tabRequests.filter(request => (request.requestTimestamp > minTimestamp - && request.requestTimestamp < maxTimestamp - && request.frameId === assetRequest.frameId - && request.url !== assetRequest.url - && (hasValidRequestType(request) - || isPixelRequest(request)))); - - return filteredRequests; - }; - - PageNetworkTrafficCollector.prototype.isValidVideoAd = function (assetRequest, tagRequests) { - const hasVpaidOrVastRequest = tagRequests.some(tagRequest => isVpaidOrVastRequest(tagRequest)); - - if (assetRequest.isYoutubeAd) { - return true; - } - if (hasVpaidOrVastRequest) { - return true; - } - const hasTopVideoAssetDomain = topVideoAssetDomains.some(assetDomain => hasDomain(assetRequest.url, assetDomain)); - - return hasTopVideoAssetDomain; - }; - - PageNetworkTrafficCollector.prototype.sendMsgWhenQuiet = function (msgKey) { - let _this = this, - origPageUrl, - msgAssetReq; - msgAssetReq = this.msgsBeingSent[msgKey]; - browserProxy.tabs.get(this.tabId, (tab) => { origPageUrl = tab.url; }); - - setTimeout(() => { - const rawRequests = []; - if (globalPageContainer.collectors[_this.tabId] === _this) { - for (const reqId in _this.requests) { - rawRequests.push(_this.requests[reqId]); - } - const tagReqs = _this.grabTagReqs(rawRequests, msgAssetReq); - - if (_this.isValidVideoAd(msgAssetReq, tagReqs)) { - _this.sendToTab(msgAssetReq, tagReqs, origPageUrl, 'new-video-ad'); - } else { - _this.sendToTab(msgAssetReq, tagReqs, origPageUrl, 'new-invalid-video-ad'); - } - } else { - - } - delete _this.msgsBeingSent[msgKey]; - }, secAfter + secBefore); - }; - - PageNetworkTrafficCollector.prototype.existingMessage = function (candidateRequest) { - const frameMsg = this.msgsBeingSent[candidateRequest.frameId]; - if (frameMsg) { - return frameMsg; - } - return null; - }; - - function onBeforeRequestListener(details) { - globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onBeforeRequest); } - - function onSendHeadersListener(details) { - globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onSendHeaders); + return this.checkUrlExtension(request) || this.checkContentHeaders(request); + }; + PageNetworkTrafficCollector.prototype.hasYoutubeDomain = function (url) { + const hostname = parseHostnameFromUrl(url); + if (hostname === 'www.youtube.com') { + return true; } - - function onHeadersReceivedListener(details) { - globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onHeadersReceived); + return false; + }; + PageNetworkTrafficCollector.prototype.parseYoutubeVideoIdFromUrl = function (url) { + let re = /^https?:\/\/www\.youtube\.com\/get_video_info.*(?:\?|&)video_id=(.*?)(?:$|&)/; + let match = re.exec(url); + if (match && match.length > 1) { + return match[1]; } - function onBeforeRedirectListener(details) { - globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onBeforeRedirect); + re = /^https?:\/\/www\.youtube\.com\/embed\/(.*?)(?:$|\?)/; + match = re.exec(url); + if (match && match.length > 1) { + return match[1]; } - function onResponseStartedListener(details) { - globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onResponseStarted); + re = /^https?:\/\/www\.youtube\.com\/watch.*(\?|&)v=([^&]*)/; + match = re.exec(url); + if (match && match.length > 1) { + return match[1]; } - - function onCommittedListener(details) { - if (details.frameId === 0) { - globalPageContainer.onNavigationCommitted(details); - } + return null; + }; + + PageNetworkTrafficCollector.prototype.isYoutubeGetVideoInfoReq = function (url) { + const re = /^https?:\/\/www\.youtube\.com\/get_video_info\?/; + return re.test(url); + }; + PageNetworkTrafficCollector.prototype.isYoutubeAdReq = function (srcUrl, destUrl) { + if (!this.hasYoutubeDomain(srcUrl) + || !this.isYoutubeGetVideoInfoReq(destUrl)) { + return false; } - - function onCompletedListener(details) { - if (details.frameId === 0) { - globalPageContainer.onNavigationCompleted(details); - } + if (this.parseYoutubeVideoIdFromUrl(srcUrl) + === this.parseYoutubeVideoIdFromUrl(destUrl) + && !this.isYoutubeMastheadRequest(destUrl)) { + return false; } + return true; + }; - function onRemovedListener(tabId, closeInfo) { - globalPageContainer.onTabClose(tabId, closeInfo); + PageNetworkTrafficCollector.prototype.bannedRequest = function (request) { + return this.bannedVideoType(request) || this.hasBannedFiletype(request) || this.bannedVideoSize(request); + }; + + PageNetworkTrafficCollector.prototype.bannedVideoType = function (request) { + let badType = false; + if (request.contentType) { + badType = bannedContentTypes.some(prefix => request.contentType.indexOf(prefix) >= 0); } + return badType; + }; - function onMessageListener(message, sender, sendResponse) { - if (message.event === 'new-ad' && message.data.event === 'ad') { - const tabId = sender.tab.id; - if (tabId) { - globalPageContainer.onDisplayAdFound(tabId); - } + PageNetworkTrafficCollector.prototype.bannedVideoSize = function (request) { + if (request.size !== null) { + if (request.size < minVidSize || request.size > maxVidSize || request.contentRange > maxContentRange) { + return true; } } + return false; + }; - function registerListeners() { - browserProxy.webRequest.onBeforeRequest.addListener( - onBeforeRequestListener, - { urls: ['http://*/*', 'https://*/*'] }, - [], - ); + PageNetworkTrafficCollector.prototype.grabTagReqs = function (tabRequests, assetRequest) { + let minTimestamp, + maxTimestamp; + minTimestamp = assetRequest.requestTimestamp - secBefore; + maxTimestamp = assetRequest.requestTimestamp + secAfter; - browserProxy.webRequest.onSendHeaders.addListener( - onSendHeadersListener, - { urls: ['http://*/*', 'https://*/*'] }, - ['requestHeaders'], - ); + const filteredRequests = tabRequests.filter(request => (request.requestTimestamp > minTimestamp + && request.requestTimestamp < maxTimestamp + && request.frameId === assetRequest.frameId + && request.url !== assetRequest.url + && (hasValidRequestType(request) + || isPixelRequest(request)))); - browserProxy.webRequest.onHeadersReceived.addListener( - onHeadersReceivedListener, - { urls: ['http://*/*', 'https://*/*'] }, - ['responseHeaders'], - ); + return filteredRequests; + }; - browserProxy.webRequest.onBeforeRedirect.addListener( - onBeforeRedirectListener, - { urls: ['http://*/*', 'https://*/*'] }, - [], - ); + PageNetworkTrafficCollector.prototype.isValidVideoAd = function (assetRequest, tagRequests) { + const hasVpaidOrVastRequest = tagRequests.some(tagRequest => isVpaidOrVastRequest(tagRequest)); - browserProxy.webRequest.onResponseStarted.addListener( - onResponseStartedListener, - { urls: ['http://*/*', 'https://*/*'] }, - ['responseHeaders'], - ); + if (assetRequest.isYoutubeAd) { + return true; + } + if (hasVpaidOrVastRequest) { + return true; + } + const hasTopVideoAssetDomain = topVideoAssetDomains.some(assetDomain => hasDomain(assetRequest.url, assetDomain)); + + return hasTopVideoAssetDomain; + }; + + PageNetworkTrafficCollector.prototype.sendMsgWhenQuiet = function (msgKey) { + let _this = this, + origPageUrl, + msgAssetReq; + msgAssetReq = this.msgsBeingSent[msgKey]; + browserProxy.tabs.get(this.tabId, (tab) => { origPageUrl = tab.url; }); + + setTimeout(() => { + const rawRequests = []; + if (globalPageContainer.collectors[_this.tabId] === _this) { + for (const reqId in _this.requests) { + rawRequests.push(_this.requests[reqId]); + } + const tagReqs = _this.grabTagReqs(rawRequests, msgAssetReq); + + if (_this.isValidVideoAd(msgAssetReq, tagReqs)) { + _this.sendToTab(msgAssetReq, tagReqs, origPageUrl, 'new-video-ad'); + } else { + _this.sendToTab(msgAssetReq, tagReqs, origPageUrl, 'new-invalid-video-ad'); + } + } else { - browserProxy.webNavigation.onCommitted.addListener(onCommittedListener); - browserProxy.webNavigation.onCompleted.addListener(onCompletedListener); - browserProxy.tabs.onRemoved.addListener(onRemovedListener); - browserProxy.runtime.onMessage.addListener(onMessageListener); + } + delete _this.msgsBeingSent[msgKey]; + }, secAfter + secBefore); + }; - areListenersRegistered = true; + PageNetworkTrafficCollector.prototype.existingMessage = function (candidateRequest) { + const frameMsg = this.msgsBeingSent[candidateRequest.frameId]; + if (frameMsg) { + return frameMsg; } + return null; + }; - function unregisterListeners() { - browserProxy.webRequest.onBeforeRequest.removeListener( - onBeforeRequestListener, - ); + function onBeforeRequestListener(details) { + globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onBeforeRequest); + } - browserProxy.webRequest.onSendHeaders.removeListener( - onSendHeadersListener, - ); + function onSendHeadersListener(details) { + globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onSendHeaders); + } - browserProxy.webRequest.onHeadersReceived.removeListener( - onHeadersReceivedListener, - ); + function onHeadersReceivedListener(details) { + globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onHeadersReceived); + } - browserProxy.webRequest.onBeforeRedirect.removeListener( - onBeforeRedirectListener, - ); + function onBeforeRedirectListener(details) { + globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onBeforeRedirect); + } - browserProxy.webRequest.onResponseStarted.removeListener( - onResponseStartedListener, - ); + function onResponseStartedListener(details) { + globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onResponseStarted); + } - browserProxy.webNavigation.onCommitted.removeListener(onCommittedListener); - browserProxy.webNavigation.onCompleted.removeListener(onCompletedListener); - browserProxy.tabs.onRemoved.removeListener(onRemovedListener); - browserProxy.runtime.onMessage.removeListener(onMessageListener); + function onCommittedListener(details) { + if (details.frameId === 0) { + globalPageContainer.onNavigationCommitted(details); + } + } - areListenersRegistered = false; + function onCompletedListener(details) { + if (details.frameId === 0) { + globalPageContainer.onNavigationCompleted(details); } + } + + function onRemovedListener(tabId, closeInfo) { + globalPageContainer.onTabClose(tabId, closeInfo); + } - function areRequiredBrowserApisAvailable() { - return requiredBrowserApis.every(api => typeof api !== 'undefined'); + function onMessageListener(message, sender, sendResponse) { + if (message.event === 'new-ad' && message.data.event === 'ad') { + const tabId = sender.tab.id; + if (tabId) { + globalPageContainer.onDisplayAdFound(tabId); + } } + } + + function registerListeners() { + browserProxy.webRequest.onBeforeRequest.addListener( + onBeforeRequestListener, + { urls: ['http://*/*', 'https://*/*'] }, + [], + ); + + browserProxy.webRequest.onSendHeaders.addListener( + onSendHeadersListener, + { urls: ['http://*/*', 'https://*/*'] }, + ['requestHeaders'], + ); + + browserProxy.webRequest.onHeadersReceived.addListener( + onHeadersReceivedListener, + { urls: ['http://*/*', 'https://*/*'] }, + ['responseHeaders'], + ); + + browserProxy.webRequest.onBeforeRedirect.addListener( + onBeforeRedirectListener, + { urls: ['http://*/*', 'https://*/*'] }, + [], + ); + + browserProxy.webRequest.onResponseStarted.addListener( + onResponseStartedListener, + { urls: ['http://*/*', 'https://*/*'] }, + ['responseHeaders'], + ); + + browserProxy.webNavigation.onCommitted.addListener(onCommittedListener); + browserProxy.webNavigation.onCompleted.addListener(onCompletedListener); + browserProxy.tabs.onRemoved.addListener(onRemovedListener); + browserProxy.runtime.onMessage.addListener(onMessageListener); + + areListenersRegistered = true; + } + + function unregisterListeners() { + browserProxy.webRequest.onBeforeRequest.removeListener( + onBeforeRequestListener, + ); + + browserProxy.webRequest.onSendHeaders.removeListener( + onSendHeadersListener, + ); + + browserProxy.webRequest.onHeadersReceived.removeListener( + onHeadersReceivedListener, + ); + + browserProxy.webRequest.onBeforeRedirect.removeListener( + onBeforeRedirectListener, + ); + + browserProxy.webRequest.onResponseStarted.removeListener( + onResponseStartedListener, + ); + + browserProxy.webNavigation.onCommitted.removeListener(onCommittedListener); + browserProxy.webNavigation.onCompleted.removeListener(onCompletedListener); + browserProxy.tabs.onRemoved.removeListener(onRemovedListener); + browserProxy.runtime.onMessage.removeListener(onMessageListener); + + areListenersRegistered = false; + } + + function areRequiredBrowserApisAvailable() { + return requiredBrowserApis.every(api => typeof api !== 'undefined'); + } + + if (areRequiredBrowserApisAvailable()) { + ifBrowserValid( + () => { + browserProxy.webNavigation.onBeforeNavigate.addListener( + (details) => { + if (details.frameId === 0) { + globalPageContainer.onNewNavigation(details); + } + }, + { + url: [{ urlMatches: 'http://*/*' }, { urlMatches: 'https://*/*' }], + }, + ); + }, () => { + + }, + ); + } - if (areRequiredBrowserApisAvailable()) { + browserProxy.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request === 'is_browser_valid') { ifBrowserValid( - () => { - browserProxy.webNavigation.onBeforeNavigate.addListener( - (details) => { - if (details.frameId === 0) { - globalPageContainer.onNewNavigation(details); - } - }, - { - url: [{ urlMatches: 'http://*/*' }, { urlMatches: 'https://*/*' }], - }, - ); - }, () => { + sendResponse({ browser_valid: true }), + sendResponse({ browser_valid: false }), + ); + } + }); + browserProxy.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request === 'is_tracking_enabled') { + ifTrackingEnabled( + sender.tab, + () => { + try { sendResponse({ tracking_enabled: true }); } catch (err) {} + }, + () => { + try { sendResponse({ tracking_enabled: false }); } catch (err) {} }, ); } - - browserProxy.runtime.onMessage.addListener((request, sender, sendResponse) => { - if (request === 'is_browser_valid') { - ifBrowserValid( - sendResponse({ browser_valid: true }), - sendResponse({ browser_valid: false }), - ); - } - }); - - browserProxy.runtime.onMessage.addListener((request, sender, sendResponse) => { - if (request === 'is_tracking_enabled') { - ifTrackingEnabled( - sender.tab, - () => { - try { sendResponse({ tracking_enabled: true }); } catch (err) {} - }, - () => { - try { sendResponse({ tracking_enabled: false }); } catch (err) {} - }, - ); - } - return true; - }); - }()); -},{}]},{},[1]); + return true; + }); +}()); diff --git a/src/drivers/webextension/js/popup.js b/src/drivers/webextension/js/popup.js index 61e21ec21..58d14867e 100644 --- a/src/drivers/webextension/js/popup.js +++ b/src/drivers/webextension/js/popup.js @@ -6,11 +6,20 @@ /** global: jsonToDOM */ let pinnedCategory = null; +let termsAccepted = false; function slugify(string) { return string.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/--+/g, '-').replace(/(?:^-|-$)/, ''); } +function i18n() { + const nodes = document.querySelectorAll('[data-i18n]'); + + Array.prototype.forEach.call(nodes, (node) => { + node.innerHTML = browser.i18n.getMessage(node.dataset.i18n); + }); +} + function replaceDom(domTemplate) { const container = document.getElementsByClassName('container')[0]; @@ -20,11 +29,7 @@ function replaceDom(domTemplate) { container.appendChild(jsonToDOM(domTemplate, document, {})); - const nodes = document.querySelectorAll('[data-i18n]'); - - Array.prototype.forEach.call(nodes, (node) => { - node.childNodes[0].nodeValue = browser.i18n.getMessage(node.dataset.i18n); - }); + i18n(); Array.from(document.querySelectorAll('.detected__category-pin-wrapper')).forEach((pin) => { pin.addEventListener('click', () => { @@ -188,8 +193,29 @@ const func = (tabs) => { source: 'popup.js', }, (response) => { pinnedCategory = response.pinnedCategory; + termsAccepted = response.termsAccepted; + + if (termsAccepted) { + replaceDomWhenReady(appsToDomTemplate(response)); + } else { + i18n(); + + const wrapper = document.querySelector('.terms__wrapper'); + + document.querySelector('.terms__accept').addEventListener('click', () => { + (chrome || browser).runtime.sendMessage({ + id: 'set_option', + key: 'termsAccepted', + value: true, + }); - replaceDomWhenReady(appsToDomTemplate(response)); + wrapper.classList.remove('terms__wrapper--active'); + + func(tabs); + }); + + wrapper.classList.add('terms__wrapper--active'); + } }); }; diff --git a/src/drivers/webextension/manifest.json b/src/drivers/webextension/manifest.json index 9c71e4ade..d946555f6 100644 --- a/src/drivers/webextension/manifest.json +++ b/src/drivers/webextension/manifest.json @@ -4,7 +4,7 @@ "author": "Elbert Alias", "homepage_url": "https://www.wappalyzer.com", "description": "Identify web technologies", - "version": "5.6.3", + "version": "5.7.2", "default_locale": "en", "manifest_version": 2, "icons": { @@ -77,7 +77,7 @@ "applications": { "gecko": { "id": "wappalyzer@crunchlabz.com", - "strict_min_version": "42.0" + "strict_min_version": "60.0" } } }