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",