diff --git a/src/drivers/npm/package.json b/src/drivers/npm/package.json index c65b58e79..80723af8d 100644 --- a/src/drivers/npm/package.json +++ b/src/drivers/npm/package.json @@ -13,7 +13,7 @@ "software" ], "homepage": "https://www.wappalyzer.com", - "version": "6.0.1", + "version": "5.10.2", "author": "Wappalyzer", "license": "MIT", "repository": { diff --git a/src/drivers/webextension/js/content.js b/src/drivers/webextension/js/content.js index 82713d79b..66d620f4a 100644 --- a/src/drivers/webextension/js/content.js +++ b/src/drivers/webextension/js/content.js @@ -5,83 +5,90 @@ /* eslint-env browser */ const port = browser.runtime.connect({ - name: 'content.js', -}); + name: 'content.js' +}) -if (typeof browser !== 'undefined' && typeof document.body !== 'undefined') { - try { - port.postMessage({ id: 'init' }); +;(async function() { + if (typeof browser !== 'undefined' && typeof document.body !== 'undefined') { + await new Promise((resolve) => setTimeout(resolve, 1000)) - // HTML - let html = new XMLSerializer().serializeToString(document); + try { + port.postMessage({ id: 'init' }) - const chunks = []; - const maxCols = 2000; - const maxRows = 3000; - const rows = html.length / maxCols; + // HTML + let html = new XMLSerializer().serializeToString(document) - let i; + const chunks = [] + const maxCols = 2000 + const maxRows = 3000 + const rows = html.length / maxCols - for (i = 0; i < rows; i += 1) { - if (i < maxRows / 2 || i > rows - maxRows / 2) { - chunks.push(html.slice(i * maxCols, (i + 1) * maxCols)); + let i + + for (i = 0; i < rows; i += 1) { + if (i < maxRows / 2 || i > rows - maxRows / 2) { + chunks.push(html.slice(i * maxCols, (i + 1) * maxCols)) + } } - } - html = chunks.join('\n'); + html = chunks.join('\n') - // Scripts - const scripts = Array.prototype.slice - .apply(document.scripts) - .filter(script => script.src) - .map(script => script.src) - .filter(script => script.indexOf('data:text/javascript;') !== 0); + // Scripts + const scripts = Array.prototype.slice + .apply(document.scripts) + .filter((script) => script.src) + .map((script) => script.src) + .filter((script) => script.indexOf('data:text/javascript;') !== 0) - port.postMessage({ id: 'analyze', subject: { html, scripts } }); + port.postMessage({ id: 'analyze', subject: { html, scripts } }) - // JavaScript variables - const script = document.createElement('script'); + // JavaScript variables + const script = document.createElement('script') - script.onload = () => { - const onMessage = (event) => { - if (event.data.id !== 'js') { - return; - } + script.onload = () => { + const onMessage = (event) => { + if (event.data.id !== 'js') { + return + } - window.removeEventListener('message', onMessage); + window.removeEventListener('message', onMessage) - port.postMessage({ id: 'analyze', subject: { js: event.data.js } }); + port.postMessage({ id: 'analyze', subject: { js: event.data.js } }) - script.remove(); - }; + script.remove() + } - window.addEventListener('message', onMessage); + window.addEventListener('message', onMessage) - port.postMessage({ id: 'get_js_patterns' }); - }; + port.postMessage({ id: 'get_js_patterns' }) + } - script.setAttribute('src', browser.extension.getURL('js/inject.js')); + script.setAttribute('src', browser.extension.getURL('js/inject.js')) - document.body.appendChild(script); - } catch (error) { - port.postMessage({ id: 'log', subject: error }); + document.body.appendChild(script) + } catch (error) { + port.postMessage({ id: 'log', subject: error }) + } } -} +})() port.onMessage.addListener((message) => { switch (message.id) { case 'get_js_patterns': - postMessage({ - id: 'patterns', - patterns: message.response.patterns, - }, window.location.href); - - break; + postMessage( + { + id: 'patterns', + patterns: message.response.patterns + }, + window.location.href + ) + + break default: - // Do nothing + // Do nothing } -}); +}) // https://stackoverflow.com/a/44774834 // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/executeScript#Return_value -undefined; // eslint-disable-line no-unused-expressions +undefined // eslint-disable-line no-unused-expressions diff --git a/src/drivers/webextension/js/driver.js b/src/drivers/webextension/js/driver.js index f08f4db78..ee1d60e0e 100644 --- a/src/drivers/webextension/js/driver.js +++ b/src/drivers/webextension/js/driver.js @@ -354,14 +354,17 @@ wappalyzer.driver.getRobotsTxt = async (host, secure = false) => { /** * Anonymously track detected applications for research purposes */ -wappalyzer.driver.ping = async (hostnameCache = {}, adCache = []) => { +wappalyzer.driver.ping = async ( + hostnameCache = { expires: 0, hostnames: {} }, + adCache = [] +) => { const tracking = await getOption('tracking', true) const termsAccepted = userAgent() === 'chrome' || (await getOption('termsAccepted', false)) if (tracking && termsAccepted) { - if (Object.keys(hostnameCache).length) { - post('https://api.wappalyzer.com/ping/v1/', hostnameCache) + if (Object.keys(hostnameCache.hostnames).length) { + post('https://api.wappalyzer.com/ping/v1/', hostnameCache.hostnames) } if (adCache.length) { @@ -404,16 +407,19 @@ wappalyzer.driver.ping = async (hostnameCache = {}, adCache = []) => { url: `${wappalyzer.config.websiteURL}installed` }) } else if (version !== previousVersion && upgradeMessage) { - openTab({ - url: `${wappalyzer.config.websiteURL}upgraded?v${version}`, - background: true - }) + // openTab({ + // url: `${wappalyzer.config.websiteURL}upgraded?v${version}`, + // background: true + // }) } await setOption('version', version) // Hostname cache - wappalyzer.hostnameCache = await getOption('hostnameCache', {}) + wappalyzer.hostnameCache = await getOption('hostnameCache', { + expires: Date.now() + 1000 * 60 * 60 * 24, + hostnames: {} + }) // Run content script on all tabs try { diff --git a/src/drivers/webextension/js/inject.js b/src/drivers/webextension/js/inject.js index 45fbd71e3..e23cb48b9 100644 --- a/src/drivers/webextension/js/inject.js +++ b/src/drivers/webextension/js/inject.js @@ -1,52 +1,54 @@ /* eslint-env browser */ /* eslint-disable no-restricted-globals, no-prototype-builtins */ -(() => { +;(() => { try { const detectJs = (chain) => { - const properties = chain.split('.'); + const properties = chain.split('.') - let value = properties.length ? window : null; + let value = properties.length ? window : null for (let i = 0; i < properties.length; i += 1) { - const property = properties[i]; + const property = properties[i] if (value && value.hasOwnProperty(property)) { - value = value[property]; + value = value[property] } else { - value = null; + value = null - break; + break } } - return typeof value === 'string' || typeof value === 'number' ? value : !!value; - }; + return typeof value === 'string' || typeof value === 'number' + ? value + : !!value + } const onMessage = (event) => { if (event.data.id !== 'patterns') { - return; + return } - removeEventListener('message', onMessage); + removeEventListener('message', onMessage) - const patterns = event.data.patterns || {}; + const patterns = event.data.patterns || {} - const js = {}; + const js = {} for (const appName in patterns) { if (patterns.hasOwnProperty(appName)) { - js[appName] = {}; + js[appName] = {} for (const chain in patterns[appName]) { if (patterns[appName].hasOwnProperty(chain)) { - js[appName][chain] = {}; + js[appName][chain] = {} for (const index in patterns[appName][chain]) { - const value = detectJs(chain); + const value = detectJs(chain) if (value && patterns[appName][chain].hasOwnProperty(index)) { - js[appName][chain][index] = value; + js[appName][chain][index] = value } } } @@ -54,11 +56,11 @@ } } - postMessage({ id: 'js', js }, window.location.href); - }; + postMessage({ id: 'js', js }, window.location.href) + } - addEventListener('message', onMessage); + addEventListener('message', onMessage) } catch (e) { // Fail quietly } -})(); +})() diff --git a/src/drivers/webextension/js/popup.js b/src/drivers/webextension/js/popup.js index 24248935f..3aa561403 100644 --- a/src/drivers/webextension/js/popup.js +++ b/src/drivers/webextension/js/popup.js @@ -70,6 +70,14 @@ function replaceDom(domTemplate) { }) }) }) + + Array.from(document.querySelectorAll('a')).forEach((link) => { + link.addEventListener('click', () => { + browser.tabs.create({ url: link.href }) + + return false + }) + }) } function replaceDomWhenReady(dom) { diff --git a/src/drivers/webextension/manifest.json b/src/drivers/webextension/manifest.json index a5a25866e..935565000 100644 --- a/src/drivers/webextension/manifest.json +++ b/src/drivers/webextension/manifest.json @@ -4,7 +4,7 @@ "author": "Wappalyzer", "homepage_url": "https://www.wappalyzer.com", "description": "Identify web technologies", - "version": "5.10.1", + "version": "5.10.2", "default_locale": "en", "manifest_version": 2, "icons": { diff --git a/src/wappalyzer.js b/src/wappalyzer.js index 603ea119e..b562512c0 100644 --- a/src/wappalyzer.js +++ b/src/wappalyzer.js @@ -131,7 +131,10 @@ class Wappalyzer { this.driver = {} this.jsPatterns = {} this.detected = {} - this.hostnameCache = {} + this.hostnameCache = { + expires: Date.now() + 1000 * 60 * 60 * 24, + hostnames: {} + } this.adCache = [] this.config = { @@ -347,10 +350,17 @@ class Wappalyzer { * */ ping() { - if (Object.keys(this.hostnameCache).length > 50) { + if ( + !this.hostnameCache.hostnames || + Object.keys(this.hostnameCache.hostnames).length > 50 || + this.hostnameCache.expires < Date.now() + ) { this.driver.ping(this.hostnameCache) - this.hostnameCache = {} + this.hostnameCache = { + expires: Date.now() + 1000 * 60 * 60 * 24, + hostnames: {} + } } if (this.adCache.length > 50) { @@ -517,31 +527,34 @@ class Wappalyzer { validation.hostname.test(url.hostname) && !validation.hostnameBlacklist.test(url.hostname) ) { - if (!(hostname in this.hostnameCache)) { - this.hostnameCache[hostname] = { + if (!(hostname in this.hostnameCache.hostnames)) { + this.hostnameCache.hostnames[hostname] = { applications: {}, meta: {} } } - if (!(appName in this.hostnameCache[hostname].applications)) { - this.hostnameCache[hostname].applications[appName] = { + if ( + !(appName in this.hostnameCache.hostnames[hostname].applications) + ) { + this.hostnameCache.hostnames[hostname].applications[appName] = { hits: 0 } } - this.hostnameCache[hostname].applications[appName].hits += 1 + this.hostnameCache.hostnames[hostname].applications[appName].hits += 1 if (apps[appName].version) { - this.hostnameCache[hostname].applications[appName].version = - app.version + this.hostnameCache.hostnames[hostname].applications[ + appName + ].version = app.version } } } }) - if (hostname in this.hostnameCache) { - this.hostnameCache[hostname].meta.language = language + if (hostname in this.hostnameCache.hostnames) { + this.hostnameCache.hostnames[hostname].meta.language = language } this.ping()