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
+ )
},
/**