From af75f59bdf8860b640ec41907aeb6164fbaedc01 Mon Sep 17 00:00:00 2001
From: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com>
Date: Tue, 14 Jul 2026 13:32:35 +0200
Subject: [PATCH] refactor: remove cache, domain-level disabling and the
associated options page
Signed-off-by: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com>
---
src/_locales/en/messages.json | 10 ---
src/css/styles.css | 15 ----
src/html/options.html | 37 --------
src/html/popup.html | 19 +---
src/js/index.js | 157 +++++++++-------------------------
src/js/options.js | 61 -------------
src/js/popup.js | 59 +------------
src/manifest.json | 1 -
8 files changed, 42 insertions(+), 317 deletions(-)
delete mode 100644 src/html/options.html
delete mode 100644 src/js/options.js
diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json
index 6677bbb9d..59ffd9509 100644
--- a/src/_locales/en/messages.json
+++ b/src/_locales/en/messages.json
@@ -1,17 +1,7 @@
{
- "options": { "message": "Options" },
- "optionsSave": { "message": "Save options" },
- "optionsSaved": { "message": "Saved" },
- "optionDynamicIcon": { "message": "Use technology icon instead of Wappalyzer logo" },
- "optionBadge": { "message": "Show the number of identified technologies on the icon" },
- "optionShowCached": { "message": "Include cached detections in results" },
- "disableOnDomain": { "message": "Disable on this website" },
- "clearCache": { "message": "Clear cached detections" },
- "nothingToDo": { "message": "Nothing to do here." },
"noAppsDetected": { "message": "No technologies detected." },
"reloadPage": { "message": "Reload" },
"categoryPin": { "message": "Always show icon" },
- "tabTechnologies": { "message": "Technologies" },
"issue": { "message": "Something wrong or missing?" },
"categoryName1": { "message": "CMS" },
diff --git a/src/css/styles.css b/src/css/styles.css
index 119abde25..ad25192fe 100644
--- a/src/css/styles.css
+++ b/src/css/styles.css
@@ -605,21 +605,6 @@ body.dynamic-icon .category__heading:hover .category__pin {
width: 100%;
}
-.options__cache {
- background: var(--color-primary);
- border: none;
- border-radius: 4px;
- color: var(--color-primary-lighten);
- cursor: pointer;
- font-size: .85rem;
- font-weight: bold;
- padding: .8rem 1.5rem;
- margin-bottom: 1.5rem;
-}
-
-.options__cache:active {
- opacity: .9;
-}
@keyframes blink {
50% {
diff --git a/src/html/options.html b/src/html/options.html
deleted file mode 100644
index 16e498ece..000000000
--- a/src/html/options.html
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/html/popup.html b/src/html/popup.html
index 438893639..5b790016f 100644
--- a/src/html/popup.html
+++ b/src/html/popup.html
@@ -4,7 +4,7 @@
-
+ Wappalyzer
@@ -17,23 +17,6 @@
-
-
-
-
-
-
-
-
diff --git a/src/js/index.js b/src/js/index.js
index c875c00a0..853e0044b 100644
--- a/src/js/index.js
+++ b/src/js/index.js
@@ -40,12 +40,6 @@ function getRequiredTechnologies(name, categoryId) {
return undefined;
}
-function isSimilarUrl(a, b) {
- const normalise = (url) => String(url || '').replace(/(\/|\/?#.+)$/, '');
-
- return normalise(a) === normalise(b);
-}
-
const Driver = {
/**
* Initialise driver
@@ -53,32 +47,8 @@ const Driver = {
async init() {
await Driver.loadTechnologies();
- const hostnameCache = await getOption('hostnames', {});
-
Driver.cache = {
- hostnames: Object.keys(hostnameCache).reduce(
- (cache, hostname) => ({
- ...cache,
- [hostname]: {
- ...hostnameCache[hostname],
- detections: hostnameCache[hostname].detections.map(
- ({
- technology: name,
- pattern: { regex, confidence },
- version
- }) => ({
- technology: getTechnology(name, true),
- pattern: {
- regex: new RegExp(regex, 'i'),
- confidence
- },
- version
- })
- )
- }
- }),
- {}
- ),
+ urls: {},
robots: await getOption('robots', {})
};
@@ -462,27 +432,21 @@ const Driver = {
return;
}
- let hostname;
-
- try {
- ({ hostname } = new URL(initiatorUrl));
- } catch (error) {
- return;
- }
+ const pageUrl = initiatorUrl.split('#')[0];
- if (!Driver.cache.hostnames[hostname]) {
- Driver.cache.hostnames[hostname] = {};
+ if (!Driver.cache.urls[pageUrl]) {
+ Driver.cache.urls[pageUrl] = {};
}
- if (!Driver.cache.hostnames[hostname].analyzedScripts) {
- Driver.cache.hostnames[hostname].analyzedScripts = [];
+ if (!Driver.cache.urls[pageUrl].analyzedScripts) {
+ Driver.cache.urls[pageUrl].analyzedScripts = [];
}
- if (Driver.cache.hostnames[hostname].analyzedScripts.length >= 25) {
+ if (Driver.cache.urls[pageUrl].analyzedScripts.length >= 25) {
return;
}
- Driver.cache.hostnames[hostname].analyzedScripts.push(request.url);
+ Driver.cache.urls[pageUrl].analyzedScripts.push(request.url);
const response = await fetch(request.url);
@@ -586,13 +550,7 @@ const Driver = {
* Check if Wappalyzer has been disabled for the domain
*/
async isDisabledDomain(url) {
- try {
- const { hostname } = new URL(url);
-
- return (await getOption('disabledDomains', [])).includes(hostname);
- } catch (error) {
- return false;
- }
+ return false;
},
/**
@@ -618,12 +576,12 @@ const Driver = {
const { hostname, pathname } = new URL(url);
// Cache detections
- const cache = (Driver.cache.hostnames[hostname] = {
+ const cache = (Driver.cache.urls[url] = {
detections: [],
hits: incrementHits ? 0 : 1,
https: url.startsWith('https://'),
analyzedScripts: [],
- ...(Driver.cache.hostnames[hostname] || []),
+ ...(Driver.cache.urls[url] || []),
dateTime: Date.now()
});
@@ -703,59 +661,23 @@ const Driver = {
cache.language = cache.language || language;
// Expire cache
- Driver.cache.hostnames = Object.keys(Driver.cache.hostnames)
+ Driver.cache.urls = Object.keys(Driver.cache.urls)
.sort((a, b) =>
- Driver.cache.hostnames[a].dateTime > Driver.cache.hostnames[b].dateTime
- ? -1
- : 1
+ Driver.cache.urls[a].dateTime > Driver.cache.urls[b].dateTime ? -1 : 1
)
- .reduce((hostnames, hostname) => {
- const cache = Driver.cache.hostnames[hostname];
+ .reduce((urls, u) => {
+ const cache = Driver.cache.urls[u];
if (
cache.dateTime > Date.now() - expiry &&
- Object.keys(hostnames).length < maxHostnames
+ Object.keys(urls).length < maxHostnames
) {
- hostnames[hostname] = cache;
+ urls[u] = cache;
}
- return hostnames;
+ return urls;
}, {});
- // Save cache
- await setOption(
- 'hostnames',
- Object.keys(Driver.cache.hostnames).reduce(
- (hostnames, hostname) => ({
- ...hostnames,
- [hostname]: {
- ...cache,
- detections: Driver.cache.hostnames[hostname].detections
- .filter(({ technology }) => technology)
- .map(
- ({
- technology: { name: technology },
- pattern: { regex, confidence },
- version,
- rootPath,
- lastUrl
- }) => ({
- technology,
- pattern: {
- regex: regex.source,
- confidence
- },
- version,
- rootPath,
- lastUrl
- })
- )
- }
- }),
- {}
- )
- );
-
Driver.log({ hostname, technologies: resolved });
},
@@ -769,16 +691,13 @@ const Driver = {
technologies = [];
}
- const dynamicIcon = await getOption('dynamicIcon', false);
- const showCached = await getOption('showCached', true);
+ const dynamicIcon = await getOption('dynamicIcon', true);
const badge = await getOption('badge', true);
let icon = 'default.svg';
const _technologies = technologies.filter(
- ({ slug, lastUrl }) =>
- slug !== 'cart-functionality' &&
- (showCached || isSimilarUrl(url, lastUrl))
+ ({ slug }) => slug !== 'cart-functionality'
);
if (dynamicIcon) {
@@ -854,15 +773,25 @@ const Driver = {
return;
}
- const showCached = await getOption('showCached', true);
+ // Force a fresh scan on the active tab's content script with a 500ms timeout
+ try {
+ await Promise.race([
+ chrome.tabs.sendMessage(tab.id, {
+ source: 'index.js',
+ func: 'onGetTechnologies',
+ args: [Wappalyzer.technologies]
+ }),
+ new Promise((resolve) => setTimeout(resolve, 500))
+ ]);
+ } catch (error) {
+ // Content script not loaded/ready or target page is restricted (e.g. chrome://)
+ }
- const { hostname } = new URL(url);
+ const pageUrl = url.split('#')[0];
- const cache = Driver.cache.hostnames?.[hostname];
+ const cache = Driver.cache.urls?.[pageUrl];
- const resolved = (cache ? resolve(cache.detections) : []).filter(
- ({ lastUrl }) => showCached || isSimilarUrl(url, lastUrl)
- );
+ const resolved = cache ? resolve(cache.detections) : [];
await Driver.setIcon(url, resolved);
@@ -965,11 +894,9 @@ const Driver = {
* Clear caches
*/
async clearCache() {
- Driver.cache.hostnames = {};
+ Driver.cache.urls = {};
xhrAnalyzed = {};
-
- await setOption('hostnames', {});
}
};
@@ -997,15 +924,11 @@ chrome.tabs.onUpdated.addListener(async (id, { status, url }) => {
}
if (url) {
- const { hostname } = new URL(url);
+ const pageUrl = url.split('#')[0];
- const showCached = await getOption('showCached', true);
+ const cache = Driver.cache?.urls?.[pageUrl];
- const cache = Driver.cache?.hostnames?.[hostname];
-
- const resolved = (cache ? resolve(cache.detections) : []).filter(
- ({ lastUrl }) => showCached || isSimilarUrl(url, lastUrl)
- );
+ const resolved = cache ? resolve(cache.detections) : [];
await Driver.setIcon(url, resolved);
}
diff --git a/src/js/options.js b/src/js/options.js
deleted file mode 100644
index f14ed9b2e..000000000
--- a/src/js/options.js
+++ /dev/null
@@ -1,61 +0,0 @@
-'use strict';
-
-const { i18n, getOption, setOption } = Utils;
-
-const Options = {
- /**
- * Initialise options
- */
- init() {
- [
- ['dynamicIcon', true],
- ['badge', true],
- ['showCached', false]
- ].map(async ([option, defaultValue]) => {
- const el = document
- .querySelector(
- `[data-i18n="option${
- option.charAt(0).toUpperCase() + option.slice(1)
- }"]`
- )
- .parentNode.querySelector('input');
-
- if (el.type === 'checkbox') {
- el.checked = !!(await getOption(option, defaultValue));
-
- el.addEventListener('click', async () => {
- await setOption(option, !!el.checked);
- });
- }
- });
-
- document
- .querySelector('.options__cache')
- .addEventListener('click', () => Options.driver('clearCache'));
-
- i18n();
- },
-
- driver(func, args, callback) {
- return new Promise((resolve, reject) => {
- chrome.runtime.sendMessage(
- {
- source: 'content.js',
- func,
- args: args ? (Array.isArray(args) ? args : [args]) : []
- },
- (response) => {
- chrome.runtime.lastError
- ? reject(new Error(chrome.runtime.lastError.message))
- : resolve(response);
- }
- );
- });
- }
-};
-
-if (/complete|interactive|loaded/.test(document.readyState)) {
- Options.init();
-} else {
- document.addEventListener('DOMContentLoaded', Options.init);
-}
diff --git a/src/js/popup.js b/src/js/popup.js
index 833e9bcd3..b0f499b9b 100644
--- a/src/js/popup.js
+++ b/src/js/popup.js
@@ -2,21 +2,6 @@
const { open, i18n, getOption, setOption, promisify, sendMessage } = Utils;
-function setDisabledDomain(enabled) {
- const el = {
- headerSwitchEnabled: document.querySelector('.header__switch--enabled'),
- headerSwitchDisabled: document.querySelector('.header__switch--disabled')
- };
-
- if (enabled) {
- el.headerSwitchEnabled.classList.add('header__switch--hidden');
- el.headerSwitchDisabled.classList.remove('header__switch--hidden');
- } else {
- el.headerSwitchEnabled.classList.remove('header__switch--hidden');
- el.headerSwitchDisabled.classList.add('header__switch--hidden');
- }
-}
-
const Popup = {
/**
* Initialise popup
@@ -35,10 +20,6 @@ const Popup = {
empty: document.querySelector('.empty'),
emptyReload: document.querySelector('.empty__reload'),
footer: document.querySelector('.footer'),
- headerSwitchDisabled: document.querySelector('.header__switch--disabled'),
- headerSwitchEnabled: document.querySelector('.header__switch--enabled'),
- headerSwitches: document.querySelectorAll('.header__switch'),
- headerSettings: document.querySelector('.header__settings'),
issue: document.querySelector('.issue'),
tabItems: document.querySelectorAll('.tab-item'),
tabs: document.querySelectorAll('.tab'),
@@ -55,15 +36,12 @@ const Popup = {
}, {});
// Disabled domains
- const dynamicIcon = await getOption('dynamicIcon', false);
+ const dynamicIcon = await getOption('dynamicIcon', true);
if (dynamicIcon) {
el.body.classList.add('dynamic-icon');
}
- // Disabled domains
- let disabledDomains = await getOption('disabledDomains', []);
-
Popup.driver('getDetections').then(Popup.onGetDetections.bind(this));
let url;
@@ -78,44 +56,9 @@ const Popup = {
if (url.startsWith('http')) {
Popup.cache.url = url;
-
- const { hostname } = new URL(url);
-
- setDisabledDomain(disabledDomains.includes(hostname));
-
- el.headerSwitchDisabled.addEventListener('click', async () => {
- disabledDomains = disabledDomains.filter(
- (_hostname) => _hostname !== hostname
- );
-
- await setOption('disabledDomains', disabledDomains);
-
- setDisabledDomain(false);
-
- Popup.driver('getDetections').then(Popup.onGetDetections.bind(this));
- });
-
- el.headerSwitchEnabled.addEventListener('click', async () => {
- disabledDomains.push(hostname);
-
- await setOption('disabledDomains', disabledDomains);
-
- setDisabledDomain(true);
-
- Popup.driver('getDetections').then(Popup.onGetDetections.bind(this));
- });
- } else {
- for (const headerSwitch of el.headerSwitches) {
- headerSwitch.classList.add('header__switch--hidden');
- }
}
}
- // Header
- el.headerSettings.addEventListener('click', () =>
- chrome.runtime.openOptionsPage()
- );
-
// Tabs
el.tabs.forEach((tab, index) => {
tab.addEventListener('click', () => {
diff --git a/src/manifest.json b/src/manifest.json
index ade40dbbb..9604f5e72 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -60,7 +60,6 @@
]
}
],
- "options_page": "html/options.html",
"permissions": [
"cookies",
"storage",