diff --git a/src/drivers/webextension/_locales/ca/messages.json b/src/drivers/webextension/_locales/ca/messages.json index ca8f18bd1..cd9a29824 100644 --- a/src/drivers/webextension/_locales/ca/messages.json +++ b/src/drivers/webextension/_locales/ca/messages.json @@ -140,7 +140,7 @@ "categoryName51": { "message": "Creadors de pàgines d'inici" }, "categoryName52": { "message": "Xats en directe" }, "categoryName53": { "message": "CRM" }, - "categoryName54": { "message": "SEO" }, + "categoryName54": { "message": "SEO" }, "categoryName55": { "message": "Comptabilitat" }, "categoryName56": { "message": "Cryptominer" }, "categoryName57": { "message": "Generadors de llocs estàtics" }, @@ -164,5 +164,10 @@ "categoryName75": { "message": "Correus electrònics" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/de/messages.json b/src/drivers/webextension/_locales/de/messages.json index 78a1b5fa3..5cf57f269 100644 --- a/src/drivers/webextension/_locales/de/messages.json +++ b/src/drivers/webextension/_locales/de/messages.json @@ -164,5 +164,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/el/messages.json b/src/drivers/webextension/_locales/el/messages.json index b37696290..65beb7af2 100644 --- a/src/drivers/webextension/_locales/el/messages.json +++ b/src/drivers/webextension/_locales/el/messages.json @@ -160,5 +160,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/en/messages.json b/src/drivers/webextension/_locales/en/messages.json index 49f99bbc3..8da563f58 100644 --- a/src/drivers/webextension/_locales/en/messages.json +++ b/src/drivers/webextension/_locales/en/messages.json @@ -162,5 +162,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/es/messages.json b/src/drivers/webextension/_locales/es/messages.json index 3c35a1e77..50846f876 100644 --- a/src/drivers/webextension/_locales/es/messages.json +++ b/src/drivers/webextension/_locales/es/messages.json @@ -164,5 +164,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/fa/messages.json b/src/drivers/webextension/_locales/fa/messages.json index 5002bcf76..134357541 100644 --- a/src/drivers/webextension/_locales/fa/messages.json +++ b/src/drivers/webextension/_locales/fa/messages.json @@ -164,5 +164,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/fr/messages.json b/src/drivers/webextension/_locales/fr/messages.json index a93ecdac3..f215c1697 100644 --- a/src/drivers/webextension/_locales/fr/messages.json +++ b/src/drivers/webextension/_locales/fr/messages.json @@ -164,5 +164,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/gl_ES/messages.json b/src/drivers/webextension/_locales/gl_ES/messages.json index a917a896f..7db65e573 100644 --- a/src/drivers/webextension/_locales/gl_ES/messages.json +++ b/src/drivers/webextension/_locales/gl_ES/messages.json @@ -164,5 +164,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/gr/messages.json b/src/drivers/webextension/_locales/gr/messages.json index ea9b9cd4c..2e75b9257 100644 --- a/src/drivers/webextension/_locales/gr/messages.json +++ b/src/drivers/webextension/_locales/gr/messages.json @@ -160,5 +160,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/id/messages.json b/src/drivers/webextension/_locales/id/messages.json index 9f3ea0f0e..2451ec79e 100644 --- a/src/drivers/webextension/_locales/id/messages.json +++ b/src/drivers/webextension/_locales/id/messages.json @@ -164,5 +164,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/it/messages.json b/src/drivers/webextension/_locales/it/messages.json index dad875f92..6e5178d06 100644 --- a/src/drivers/webextension/_locales/it/messages.json +++ b/src/drivers/webextension/_locales/it/messages.json @@ -164,5 +164,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/ja/messages.json b/src/drivers/webextension/_locales/ja/messages.json index 810731ca0..14b310c24 100644 --- a/src/drivers/webextension/_locales/ja/messages.json +++ b/src/drivers/webextension/_locales/ja/messages.json @@ -162,5 +162,10 @@ "categoryName75": { "message": "Eメール" }, "categoryName76": { "message": "パーソナライズ" }, "categoryName77": { "message": "リターゲッティング" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/ko/messages.json b/src/drivers/webextension/_locales/ko/messages.json index a95bf3456..85bbadb5b 100644 --- a/src/drivers/webextension/_locales/ko/messages.json +++ b/src/drivers/webextension/_locales/ko/messages.json @@ -162,5 +162,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/pl/messages.json b/src/drivers/webextension/_locales/pl/messages.json index 3b73a7b9d..5abce19fd 100644 --- a/src/drivers/webextension/_locales/pl/messages.json +++ b/src/drivers/webextension/_locales/pl/messages.json @@ -163,5 +163,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/pt/messages.json b/src/drivers/webextension/_locales/pt/messages.json index af8bf56a0..22588deaf 100644 --- a/src/drivers/webextension/_locales/pt/messages.json +++ b/src/drivers/webextension/_locales/pt/messages.json @@ -164,5 +164,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/pt_BR/messages.json b/src/drivers/webextension/_locales/pt_BR/messages.json index bac8dc9ea..2cda152dd 100644 --- a/src/drivers/webextension/_locales/pt_BR/messages.json +++ b/src/drivers/webextension/_locales/pt_BR/messages.json @@ -164,5 +164,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/ro/messages.json b/src/drivers/webextension/_locales/ro/messages.json index 23386a097..70a870844 100644 --- a/src/drivers/webextension/_locales/ro/messages.json +++ b/src/drivers/webextension/_locales/ro/messages.json @@ -160,5 +160,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/ru/messages.json b/src/drivers/webextension/_locales/ru/messages.json index 476c88f5c..10e4f61ad 100644 --- a/src/drivers/webextension/_locales/ru/messages.json +++ b/src/drivers/webextension/_locales/ru/messages.json @@ -162,5 +162,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Персонализация" }, "categoryName77": { "message": "Ретаргетинг" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Геолокация" }, + "categoryName80": { "message": "Шаблон для WordPress" }, + "categoryName81": { "message": "Шаблон для Shopify" }, + "categoryName82": { "message": "Шаблон для Drupal" }, + "categoryName83": { "message": "Отпечатки браузера" } } diff --git a/src/drivers/webextension/_locales/sk/messages.json b/src/drivers/webextension/_locales/sk/messages.json index 76ded4c56..2cc0f8343 100644 --- a/src/drivers/webextension/_locales/sk/messages.json +++ b/src/drivers/webextension/_locales/sk/messages.json @@ -164,5 +164,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/tr/messages.json b/src/drivers/webextension/_locales/tr/messages.json index a3dd84e71..4a07825db 100644 --- a/src/drivers/webextension/_locales/tr/messages.json +++ b/src/drivers/webextension/_locales/tr/messages.json @@ -164,5 +164,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/uk/messages.json b/src/drivers/webextension/_locales/uk/messages.json index 8ae2b4796..f455511d7 100644 --- a/src/drivers/webextension/_locales/uk/messages.json +++ b/src/drivers/webextension/_locales/uk/messages.json @@ -165,5 +165,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/uz/messages.json b/src/drivers/webextension/_locales/uz/messages.json index 07b0f60e6..350b27c94 100644 --- a/src/drivers/webextension/_locales/uz/messages.json +++ b/src/drivers/webextension/_locales/uz/messages.json @@ -164,5 +164,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/zh_CN/messages.json b/src/drivers/webextension/_locales/zh_CN/messages.json index 545093ada..835322922 100644 --- a/src/drivers/webextension/_locales/zh_CN/messages.json +++ b/src/drivers/webextension/_locales/zh_CN/messages.json @@ -160,5 +160,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/_locales/zh_TW/messages.json b/src/drivers/webextension/_locales/zh_TW/messages.json index 26940bcef..e22bc1e74 100644 --- a/src/drivers/webextension/_locales/zh_TW/messages.json +++ b/src/drivers/webextension/_locales/zh_TW/messages.json @@ -164,5 +164,10 @@ "categoryName75": { "message": "Email" }, "categoryName76": { "message": "Personalisation" }, "categoryName77": { "message": "Retargeting" }, - "categoryName78": { "message": "RUM" } + "categoryName78": { "message": "RUM" }, + "categoryName79": { "message": "Geolocation" }, + "categoryName80": { "message": "WordPress themes" }, + "categoryName81": { "message": "Shopify themes" }, + "categoryName82": { "message": "Drupal themes" }, + "categoryName83": { "message": "Browser fingerprinting" } } diff --git a/src/drivers/webextension/images/icons/ClientJS.png b/src/drivers/webextension/images/icons/ClientJS.png new file mode 100644 index 000000000..e645dc350 Binary files /dev/null and b/src/drivers/webextension/images/icons/ClientJS.png differ diff --git a/src/drivers/webextension/images/icons/Contentstack.png b/src/drivers/webextension/images/icons/Contentstack.png new file mode 100644 index 000000000..19b156ac4 Binary files /dev/null and b/src/drivers/webextension/images/icons/Contentstack.png differ diff --git a/src/drivers/webextension/images/icons/Digistore24.svg b/src/drivers/webextension/images/icons/Digistore24.svg new file mode 100644 index 000000000..8ad696b5c --- /dev/null +++ b/src/drivers/webextension/images/icons/Digistore24.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/drivers/webextension/images/icons/Fit Analytics.png b/src/drivers/webextension/images/icons/Fit Analytics.png new file mode 100644 index 000000000..a82b88ff2 Binary files /dev/null and b/src/drivers/webextension/images/icons/Fit Analytics.png differ diff --git a/src/drivers/webextension/images/icons/MaxMind.png b/src/drivers/webextension/images/icons/MaxMind.png new file mode 100644 index 000000000..900e3f51a Binary files /dev/null and b/src/drivers/webextension/images/icons/MaxMind.png differ diff --git a/src/drivers/webextension/images/icons/Stylitics.svg b/src/drivers/webextension/images/icons/Stylitics.svg new file mode 100644 index 000000000..c35592855 --- /dev/null +++ b/src/drivers/webextension/images/icons/Stylitics.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/drivers/webextension/images/icons/Syte.svg b/src/drivers/webextension/images/icons/Syte.svg new file mode 100644 index 000000000..24e220de8 --- /dev/null +++ b/src/drivers/webextension/images/icons/Syte.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/drivers/webextension/images/icons/ThreatMetrix.svg b/src/drivers/webextension/images/icons/ThreatMetrix.svg new file mode 100644 index 000000000..0b6b8b74d --- /dev/null +++ b/src/drivers/webextension/images/icons/ThreatMetrix.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/drivers/webextension/images/icons/TruValidate.svg b/src/drivers/webextension/images/icons/TruValidate.svg new file mode 100644 index 000000000..dd62499f6 --- /dev/null +++ b/src/drivers/webextension/images/icons/TruValidate.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/drivers/webextension/images/icons/Unpkg.png b/src/drivers/webextension/images/icons/Unpkg.png new file mode 100644 index 000000000..51534d683 Binary files /dev/null and b/src/drivers/webextension/images/icons/Unpkg.png differ diff --git a/src/drivers/webextension/js/content.js b/src/drivers/webextension/js/content.js index 6694e7a82..182cb6a50 100644 --- a/src/drivers/webextension/js/content.js +++ b/src/drivers/webextension/js/content.js @@ -3,6 +3,12 @@ /* globals chrome */ const Content = { + href: location.href, + cache: {}, + language: '', + + requiresAnalyzed: [], + /** * Initialise content script */ @@ -32,7 +38,7 @@ const Content = { html = chunks.join('\n') // Determine language based on the HTML lang attribute or content - const language = + Content.language = document.documentElement.getAttribute('lang') || document.documentElement.getAttribute('xml:lang') || (await new Promise((resolve) => @@ -86,10 +92,37 @@ const Content = { {} ) + // Detect Google Ads + if (/^(www\.)?google(\.[a-z]{2,3}){1,2}$/.test(location.hostname)) { + const ads = document.querySelectorAll( + '#tads [data-text-ad] a[data-pcu]' + ) + + for (const ad of ads) { + Content.driver('detectTechnology', [ad.href, 'Google Ads']) + } + } + + // Detect Microsoft Ads + if (/^(www\.)?bing\.com$/.test(location.hostname)) { + const ads = document.querySelectorAll('.b_ad .b_adurl cite') + + for (const ad of ads) { + const url = ad.textContent.split(' ')[0].trim() + + Content.driver('detectTechnology', [ + url.startsWith('http') ? url : `http://${url}`, + 'Microsoft Advertising', + ]) + } + } + + Content.cache = { html, css, scripts, meta } + Content.driver('onContentLoad', [ - location.href, - { html, css, scripts, meta }, - language, + Content.href, + Content.cache, + Content.language, ]) const technologies = await Content.driver('getTechnologies') @@ -105,6 +138,32 @@ const Content = { } }, + /** + * Enable scripts to call Driver functions through messaging + * @param {Object} message + * @param {Object} sender + * @param {Function} callback + */ + onMessage({ source, func, args }, sender, callback) { + if (!func) { + return + } + + Content.driver('log', { source, func, args }) + + if (!Content[func]) { + Content.error(new Error(`Method does not exist: Content.${func}`)) + + return + } + + Promise.resolve(Content[func].call(Content[func], ...(args || []))) + .then(callback) + .catch(Content.error) + + return !!callback + }, + driver(func, args) { return new Promise((resolve, reject) => { chrome.runtime.sendMessage( @@ -136,6 +195,23 @@ const Content = { }) }, + analyzeRequires(requires) { + Object.keys(requires).forEach((name) => { + if (!Content.requiresAnalyzed.includes(name)) { + Content.requiresAnalyzed.push(name) + + Content.driver('onContentLoad', [ + Content.href, + Content.cache, + Content.language, + name, + ]) + + Content.onGetTechnologies(requires[name].technologies) + } + }) + }, + /** * Callback for getTechnologies * @param {Array} technologies @@ -259,33 +335,13 @@ const Content = { return technologies }, []) - // Detect Google Ads - if (/^(www\.)?google(\.[a-z]{2,3}){1,2}$/.test(location.hostname)) { - const ads = document.querySelectorAll('#tads [data-text-ad] a[data-pcu]') - - for (const ad of ads) { - Content.driver('detectTechnology', [ad.href, 'Google Ads']) - } - } - - // Detect Microsoft Ads - if (/^(www\.)?bing\.com$/.test(location.hostname)) { - const ads = document.querySelectorAll('.b_ad .b_adurl cite') - - for (const ad of ads) { - const url = ad.textContent.split(' ')[0].trim() - - Content.driver('detectTechnology', [ - url.startsWith('http') ? url : `http://${url}`, - 'Microsoft Advertising', - ]) - } - } - Content.driver('analyzeDom', [location.href, dom]) }, } +// Enable messaging between scripts +chrome.runtime.onMessage.addListener(Content.onMessage) + if (/complete|interactive|loaded/.test(document.readyState)) { Content.init() } else { diff --git a/src/drivers/webextension/js/driver.js b/src/drivers/webextension/js/driver.js index 8d0bc6f5b..e998255aa 100644 --- a/src/drivers/webextension/js/driver.js +++ b/src/drivers/webextension/js/driver.js @@ -298,6 +298,38 @@ const Driver = { return !!callback }, + async content(url, func, args) { + const [tab] = await promisify(chrome.tabs, 'query', { + url: globEscape(url), + }) + + if (!tab) { + return + } + + return new Promise((resolve, reject) => { + chrome.tabs.sendMessage( + tab.id, + { + source: 'driver.js', + func, + args: args ? (Array.isArray(args) ? args : [args]) : [], + }, + (response) => { + chrome.runtime.lastError + ? func === 'error' + ? resolve() + : Driver.error( + new Error( + `${chrome.runtime.lastError}: Driver.${func}(${args})` + ) + ) + : resolve(response) + } + ) + }) + }, + /** * Analyse response headers * @param {Object} request @@ -375,7 +407,7 @@ const Driver = { * @param {Object} items * @param {String} language */ - async onContentLoad(url, items, language) { + async onContentLoad(url, items, language, requires) { try { const { hostname } = new URL(url) @@ -393,7 +425,10 @@ const Driver = { await Driver.onDetect( url, - await analyze({ url, ...items }), + await analyze( + { url, ...items }, + requires ? Wappalyzer.requires[requires].technologies : undefined + ), language, true ) @@ -429,7 +464,13 @@ const Driver = { * @param {String} language * @param {Boolean} incrementHits */ - async onDetect(url, detections = [], language, incrementHits = false) { + async onDetect( + url, + detections = [], + language, + incrementHits = false, + analyzeRequires = true + ) { if (!url || !detections.length) { return } @@ -526,6 +567,15 @@ const Driver = { return detection }) + const requires = Wappalyzer.requires + .filter(({ name, technologies }) => + resolved.some(({ name: _name }) => _name === name) + ) + .map(({ technologies }) => technologies) + .flat() + + Driver.content(url, 'analyzeRequires', [requires]) + await Driver.setIcon(url, resolved) if (url) { diff --git a/src/technologies.json b/src/technologies.json index 95280bcf1..4d6896d80 100644 --- a/src/technologies.json +++ b/src/technologies.json @@ -300,6 +300,26 @@ "78": { "name": "RUM", "priority": 9 + }, + "79": { + "name": "Geolocation", + "priority": 9 + }, + "80": { + "name": "WordPress themes", + "priority": 9 + }, + "81": { + "name": "Shopify themes", + "priority": 9 + }, + "82": { + "name": "Drupal themes", + "priority": 9 + }, + "83": { + "name": "Browser fingerprinting", + "priority": 9 } }, "technologies": { @@ -4554,6 +4574,23 @@ "scripts": "static\\.getclicky\\.com", "website": "http://getclicky.com" }, + "ClientJS": { + "cats": [ + 59, + 83 + ], + "description": "ClientJS is a JavaScript library for generating browser fingerprints, exposing all the browser data-points.", + "icon": "ClientJS.png", + "js": { + "ClientJS": "" + }, + "scripts": [ + "/clientjs@(\\d.*?)/\\;version:\\1", + "/ClientJS/(?:(\\d.*?)/)?\\;version:\\1" + ], + "oss": true, + "website": "http://clientjs.org" + }, "Clipboard.js": { "cats": [ 19 @@ -4972,6 +5009,20 @@ "website": "http://www.contentful.com", "xhr": "cdn\\.contentful\\.com" }, + "Contentstack": { + "cats": [ + 1 + ], + "description": "Contentstack is a headless CMS software designed to help businesses deliver personalized content experiences to audiences via multiple channels.", + "icon": "Contentstack.png", + "dom": "img[src*='images.contentstack.io']", + "saas": true, + "pricing": [ + "high", + "recurring" + ], + "website": "https://www.contentstack.com" + }, "Convert": { "cats": [ 74 @@ -5700,6 +5751,28 @@ "icon": "DigiCert.svg", "website": "https://www.digicert.com/" }, + "Digistore24": { + "cats": [ + 71 + ], + "description": "Digistore24 is a German digital reselling and affiliate marketing platform.", + "icon": "Digistore24.svg", + "dom": "a[href*='www.digistore24.com'][target='_blank']", + "js": { + "getTheSourceForDigistoreLinks": "", + "DIGISTORE_VENDORKEY": "", + "DIGISTORE_LINK_ID_KEY": "" + }, + "scripts": [ + "digistore/digistore\\.js", + "www\\.digistore24\\.com" + ], + "saas": true, + "pricing": [ + "payg" + ], + "website": "https://www.digistore24.com" + }, "DigitalRiver": { "cats": [ 6 @@ -7047,8 +7120,10 @@ }, "FingerprintJS": { "cats": [ - 59 + 59, + 83 ], + "description": "FingerprintJS is a browser fingerprinting library that queries browser attributes and computes a hashed visitor identifier from them.", "icon": "FingerprintJS.svg", "js": { "Fingerprint": "(\\d)?$\\;version:\\1", @@ -7058,9 +7133,18 @@ }, "scripts": [ "fingerprint(\\d)?(?:\\.min)?\\.js\\;version:\\1", - "/fingerprintjs@(\\d)\\;version:\\1" + "/fingerprintjs@(\\d.*?)/\\;version:\\1", + "/fingerprintjs-pro/(?:(\\d.*?)/)?\\;version:\\1", + "/fingerprintjs-pro@(\\d.*?)/\\;version:\\1", + "/fingerprintjs2/(?:(\\d.*?)/)?\\;version:\\1", + "/fingerprintjs2@(\\d.*?)/\\;version:\\1" + ], + "saas": true, + "oss": true, + "pricing": [ + "payg" ], - "website": "https://fingerprintjs.com/" + "website": "https://fingerprintjs.com" }, "Firebase": { "cats": [ @@ -7117,6 +7201,24 @@ "website": "https://www.firstimpression.io", "xhr": "\\.firstimpression\\.io" }, + "Fit Analytics": { + "cats": [ + 5, + 76 + ], + "description": "Fit Analytics is a platform that provides clothing size recommendations for online customers by measuring individual dimensions via webcams.", + "icon": "Fit Analytics.png", + "js": { + "_fitAnalytics": "", + "FitAnalyticsWidget": "" + }, + "scripts": "\\.fitanalytics\\.com", + "saas": true, + "pricing": [ + "poa" + ], + "website": "https://www.fitanalytics.com" + }, "Flarum": { "cats": [ 2 @@ -7343,18 +7445,23 @@ }, "Forter": { "cats": [ - 10 + 6, + 16 ], "cookies": { "forterToken": "" }, - "description": "Forter provides fraud prevention technology for online retailers and marketplaces.", + "description": "Forter is a SaaS company that provides fraud prevention technology for online retailers and marketplaces.", "icon": "Forter.svg", "js": { "ftr__startScriptLoad": "" }, "scripts": "forter\\.com", - "website": "https://www.forter.com/" + "saas": true, + "pricing": [ + "poa" + ], + "website": "https://www.forter.com" }, "Fortune3": { "cats": [ @@ -7513,7 +7620,7 @@ 32, 74 ], - "description": "Frosmo is a SaaS company wich provides AI-driven personalisation products.", + "description": "Frosmo is a SaaS company which provides AI-driven personalisation products.", "icon": "Frosmo.png", "js": { "_frosmo": "", @@ -7855,6 +7962,7 @@ }, "Ghost": { "cats": [ + 1, 11 ], "description": "Ghost is a free and open-source blogging platform written in JavaScript, designed to simplify the process of online publishing for individual bloggers as well as online publications.", @@ -10851,7 +10959,8 @@ }, "Kount": { "cats": [ - 10 + 6, + 16 ], "description": "Kount is a suite of fraud detection and prevention solutions for ecommerce businesses.", "icon": "Kount.svg", @@ -10862,7 +10971,11 @@ "scripts": [ "shopify\\.kount\\.net/js" ], - "website": "https://kount.com/" + "saas": true, + "pricing": [ + "poa" + ], + "website": "https://kount.com" }, "Kubernetes Dashboard": { "cats": [ @@ -12147,6 +12260,25 @@ }, "website": "http://max-3000.com" }, + "MaxMind": { + "cats": [ + 79, + 83 + ], + "icon": "MaxMind.png", + "description": "MaxMind is a provider of geolocation and online fraud detection tools.", + "scripts": [ + "[device|js]\\.maxmind\\.com/", + "geoip\\.maxmind\\.min\\.js" + ], + "xhr": "\\.maxmind\\.com", + "saas": true, + "pricing": [ + "freemium", + "payg" + ], + "website": "https://www.maxmind.com" + }, "Maxemail": { "cats": [ 32 @@ -14716,14 +14848,25 @@ "cats": [ 16 ], + "icon": "perimeterx.svg", + "description": "PerimeterX is a provider of scalable, behavior-based threat protection technology for the web, cloud, and mobile.", "cookies": { "_px3": "", "_pxff_cc": "", "_pxhd": "", "_pxvid": "" }, - "icon": "perimeterx.svg", - "website": "https://www.perimeterx.com/" + "js": { + "_pxAppId": "" + }, + "scripts": "client\\.a\\.pxi\\.pub/", + "saas": true, + "pricing": [ + "payg", + "recurring", + "poa" + ], + "website": "https://www.perimeterx.com" }, "Perl": { "cats": [ @@ -18259,8 +18402,7 @@ "description": "SiteSpect is the A/B testing and optimisation solution.", "icon": "SiteSpect.png", "js": { - "SS": "\\;confidence:50", - "ss_dom_var": "\\;confidence:50" + "ss_dom_var": "" }, "pricing": [ "poa" @@ -19719,6 +19861,26 @@ }, "website": "https://github.com/syntaxhighlighter" }, + "Syte": { + "cats": [ + 76, + 29 + ], + "description": "Syte is a provider of visual AI technology that aims to improve retailers' site navigation, product discovery, and user experience by powering solutions that engage and convert shoppers.", + "icon": "Syte.svg", + "dom": "img[src*='cdn.syteapi.com']", + "js": { + "SyteApi.getBinImageBB": "", + "SyteApp.Analytics": "", + "SytePixel": "" + }, + "scripts": "cdn\\.syteapi\\.com/", + "saas": true, + "pricing": [ + "poa" + ], + "website": "https://www.syte.ai" + }, "T-Soft": { "cats": [ 6 @@ -20190,6 +20352,20 @@ "scripts": "cdn(?:-themes)?\\.thinkific\\.com", "website": "https://www.thinkific.com" }, + "ThreatMetrix": { + "cats": [ + 16, + 83 + ], + "description": "LexisNexis ThreatMetrix is an enterprise solution for online risk and fraud protection ('digital identity intelligence and digital authentication').", + "icon": "ThreatMetrix.svg", + "scripts": "\\.online-metrix\\.net", + "saas": true, + "pricing": [ + "poa" + ], + "website": "https://risk.lexisnexis.com/products/threatmetrix" + }, "ThriveCart": { "cats": [ 6 @@ -20563,6 +20739,23 @@ "scripts": "\\.trustpilot\\.com", "website": "https://business.trustpilot.com" }, + "TruValidate": { + "cats": [ + 16, + 83 + ], + "description": "TransUnion TruValidate (previously ReputationShield/IDVision from iovation) is an online risk and fraud detection platform.", + "icon": "TruValidate.svg", + "scripts": [ + "mpsnare\\.iesnare\\.com", + "ci-mpsnare\\.iovation\\.com" + ], + "saas": true, + "pricing": [ + "poa" + ], + "website": "https://www.transunion.com/solution/truvalidate" + }, "Tumblr": { "cats": [ 11 @@ -20826,6 +21019,17 @@ "icon": "UNIX.png", "website": "http://unix.org" }, + "Unpkg": { + "cats": [ + 31 + ], + "description": "Unpkg is a content delivery network for everything on npm.", + "icon": "Unpkg.png", + "dom": "link[href*='unpkg.com']", + "scripts": "unpkg\\.com/", + "oss": true, + "website": "https://unpkg.com" + }, "Ubercart": { "cats": [ 6 @@ -24330,6 +24534,28 @@ }, "website": "https://styled-components.com" }, + "Stylitics": { + "cats": [ + 5, + 32 + ], + "description": "Stylitics is a cloud-based SaaS platform for retailers to automate and distribute visual content at scale.", + "icon": "Stylitics.svg", + "dom": "link[href*='.stylitics.com']", + "js": { + "Stylitics": "", + "stylitics": "" + }, + "scripts": [ + "\\.stylitics\\.com/v([\\d.]+)\\;version:\\1", + "/stylitics/js/stylitics\\.js\\?ver=v([\\d.]+)\\;version:\\1" + ], + "saas": true, + "pricing": [ + "poa" + ], + "website": "https://stylitics.com" + }, "swift.engine": { "cats": [ 1 diff --git a/src/wappalyzer.js b/src/wappalyzer.js index 57508d81c..92fefbcce 100644 --- a/src/wappalyzer.js +++ b/src/wappalyzer.js @@ -11,6 +11,7 @@ function toArray(value) { const Wappalyzer = { technologies: [], categories: [], + requires: {}, slugify: (string) => string @@ -194,20 +195,23 @@ const Wappalyzer = { * Initialize analyzation. * @param {*} param0 */ - async analyze({ - url, - xhr, - html, - css, - robots, - magento, - meta, - headers, - dns, - certIssuer, - cookies, - scripts, - }) { + async analyze( + { + url, + xhr, + html, + css, + robots, + magento, + meta, + headers, + dns, + certIssuer, + cookies, + scripts, + }, + technologies = Wappalyzer.technologies + ) { const oo = Wappalyzer.analyzeOneToOne const om = Wappalyzer.analyzeOneToMany const mm = Wappalyzer.analyzeManyToMany @@ -217,7 +221,7 @@ const Wappalyzer = { try { const detections = flatten( await Promise.all( - Wappalyzer.technologies.map(async (technology) => { + technologies.map(async (technology) => { await next() return flatten([ @@ -270,6 +274,7 @@ const Wappalyzer = { js, implies, excludes, + requires, icon, website, cpe, @@ -312,6 +317,9 @@ const Wappalyzer = { excludes: transform(excludes).map(({ value }) => ({ name: value, })), + requires: transform(requires).map(({ value }) => ({ + name: value, + })), icon: icon || 'default.svg', website: website || null, cpe: cpe || null, @@ -319,6 +327,29 @@ const Wappalyzer = { return technologies }, []) + + Wappalyzer.technologies + .filter(({ requires }) => requires.length) + .forEach((technology) => + technology.requires.forEach(({ name }) => { + if (!Wappalyzer.getTechnology(name)) { + throw new Error(`Required technology does not exist: ${name}`) + } + + Wappalyzer.requires[name] = Wappalyzer.requires[name] || [] + + Wappalyzer.requires[name].push(technology) + }) + ) + + Wappalyzer.requires = Object.keys(Wappalyzer.requires).map((name) => ({ + name, + technologies: Wappalyzer.requires[name], + })) + + Wappalyzer.technologies = Wappalyzer.technologies.filter( + ({ requires }) => !requires.length + ) }, /**