From 575809793e9c4be6ed5a2c8f2c77aca73ad12380 Mon Sep 17 00:00:00 2001
From: Elbert Alias <77259+AliasIO@users.noreply.github.com>
Date: Tue, 9 Jun 2020 15:17:40 +1000
Subject: [PATCH] Refactoring
---
src/drivers/webextension/css/styles.css | 22 ++
src/drivers/webextension/html/popup.html | 5 +-
src/drivers/webextension/js/content.js | 15 +-
src/drivers/webextension/js/driver.js | 393 +++++++++++++------
src/drivers/webextension/js/lib/iframe.js | 11 +-
src/drivers/webextension/js/lib/jsontodom.js | 63 ---
src/drivers/webextension/js/lib/network.js | 159 ++------
src/drivers/webextension/js/popup.js | 44 ++-
8 files changed, 405 insertions(+), 307 deletions(-)
delete mode 100644 src/drivers/webextension/js/lib/jsontodom.js
diff --git a/src/drivers/webextension/css/styles.css b/src/drivers/webextension/css/styles.css
index 9ed0f55a3..d4a45aaa3 100644
--- a/src/drivers/webextension/css/styles.css
+++ b/src/drivers/webextension/css/styles.css
@@ -150,6 +150,21 @@ a:hover {
color: var(--color-text);
}
+.technology__confidence {
+ opacity: .5;
+ font-size: .7rem;
+ margin-left: .2rem;
+}
+
+.technology__version {
+ background: var(--color-secondary);
+ border-radius: 3px;
+ font-size: .7rem;
+ padding: .1rem .3rem;
+ margin-left: .4rem;
+ vertical-align: middle;
+}
+
.terms {
align-items: center;
display: flex;
@@ -235,6 +250,13 @@ a:hover {
color: #fff
}
+ .theme-mode .technology__confidence {
+ }
+
+ .theme-mode .technology__version {
+ background: var(--color-primary);
+ }
+
.theme-mode .footer {
border-color: var(--color-secondary-dark)
}
diff --git a/src/drivers/webextension/html/popup.html b/src/drivers/webextension/html/popup.html
index 5cf376251..593fc255b 100644
--- a/src/drivers/webextension/html/popup.html
+++ b/src/drivers/webextension/html/popup.html
@@ -55,8 +55,11 @@
+
+
+
+
-
diff --git a/src/drivers/webextension/js/content.js b/src/drivers/webextension/js/content.js
index e637475c5..405be35d6 100644
--- a/src/drivers/webextension/js/content.js
+++ b/src/drivers/webextension/js/content.js
@@ -25,6 +25,19 @@ const Content = {
html = chunks.join('\n')
+ const language =
+ document.documentElement.getAttribute('lang') ||
+ document.documentElement.getAttribute('xml:lang') ||
+ (await new Promise((resolve) =>
+ chrome.i18n.detectLanguage(html, ({ languages }) =>
+ resolve(
+ languages
+ .filter(({ percentage }) => percentage >= 75)
+ .map(({ language: lang }) => lang)[0]
+ )
+ )
+ ))
+
// Script tags
const scripts = Array.from(document.scripts)
.filter(({ src }) => src)
@@ -41,7 +54,7 @@ const Content = {
Content.port.postMessage({
func: 'onContentLoad',
- args: [location.href, { html, scripts, meta }]
+ args: [location.href, { html, scripts, meta }, language]
})
Content.port.postMessage({ func: 'getTechnologies' })
diff --git a/src/drivers/webextension/js/driver.js b/src/drivers/webextension/js/driver.js
index 0dd587cc3..7daf679af 100644
--- a/src/drivers/webextension/js/driver.js
+++ b/src/drivers/webextension/js/driver.js
@@ -7,15 +7,61 @@ const {
setCategories,
analyze,
analyzeManyToMany,
- resolve,
- unique
+ resolve
} = Wappalyzer
-const { promisify, getOption } = Utils
+const { agent, promisify, getOption, setOption } = Utils
+
+const expiry = 1000 * 60 * 60 * 24
const Driver = {
- cache: {
- hostnames: {},
- robots: {}
+ lastPing: Date.now(),
+
+ 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(
+ ({
+ pattern: { regex, confidence, version },
+ match,
+ technology: name,
+ hits
+ }) => ({
+ pattern: {
+ regex: new RegExp(regex, 'i'),
+ confidence,
+ version
+ },
+ match,
+ technology: Wappalyzer.technologies.find(
+ ({ name: _name }) => name === _name
+ ),
+ hits
+ })
+ )
+ }
+ }),
+ {}
+ ),
+ tabs: {},
+ robots: (await getOption('robots')) || {},
+ ads: (await getOption('ads')) || []
+ }
+
+ chrome.runtime.onConnect.addListener(Driver.onRuntimeConnect)
+ chrome.webRequest.onCompleted.addListener(
+ Driver.onWebRequestComplete,
+ { urls: ['http://*/*', 'https://*/*'], types: ['main_frame'] },
+ ['responseHeaders']
+ )
+ chrome.tabs.onRemoved.addListener((id) => (Driver.cache.tabs[id] = null))
},
log(message, source = 'driver', type = 'log') {
@@ -97,90 +143,6 @@ const Driver = {
func,
args: await Driver[func].call(port.sender, ...(args || []))
})
-
- /*
- const pinnedCategory = await getOption('pinnedCategory')
-
- const url = new URL(port.sender.tab.url)
-
- const cookies = await browser.cookies.getAll({
- domain: `.${url.hostname}`
- })
-
- let response
-
- switch (message.id) {
- case 'log':
- wappalyzer.log(message.subject, message.source)
-
- break
- case 'analyze':
- if (message.subject.html) {
- browser.i18n
- .detectLanguage(message.subject.html)
- .then(({ languages }) => {
- const language = languages
- .filter(({ percentage }) => percentage >= 75)
- .map(({ language: lang }) => lang)[0]
-
- message.subject.language = language
-
- wappalyzer.analyze(url, message.subject, {
- tab: port.sender.tab
- })
- })
- } else {
- wappalyzer.analyze(url, message.subject, { tab: port.sender.tab })
- }
-
- await setOption('hostnameCache', wappalyzer.hostnameCache)
-
- break
- case 'ad_log':
- wappalyzer.cacheDetectedAds(message.subject)
-
- break
- case 'get_apps':
- response = {
- tabCache: tabCache[message.tab.id],
- apps: wappalyzer.apps,
- categories: wappalyzer.categories,
- pinnedCategory,
- termsAccepted:
- userAgent() === 'chrome' ||
- (await getOption('termsAccepted', false))
- }
-
- break
- case 'set_option':
- await setOption(message.key, message.value)
-
- break
- case 'get_js_patterns':
- response = {
- patterns: wappalyzer.jsPatterns
- }
-
- break
- case 'update_theme_mode':
- // Sync theme mode to popup.
- response = {
- themeMode: await getOption('themeMode', false)
- }
-
- break
- default:
- // Do nothing
- }
-
- if (response) {
- port.postMessage({
- id: message.id,
- response
- })
- }
- })
- */
})
},
@@ -220,7 +182,7 @@ const Driver = {
}
},
- async onContentLoad(href, items) {
+ async onContentLoad(href, items, language) {
try {
const url = new URL(href)
@@ -228,7 +190,7 @@ const Driver = {
domain: `.${url.hostname}`
})
- await Driver.onDetect(url, await analyze(href, items))
+ await Driver.onDetect(url, await analyze(href, items), language)
} catch (error) {
Driver.error(error)
}
@@ -238,15 +200,98 @@ const Driver = {
return Wappalyzer.technologies
},
- async onDetect(url, detections = []) {
- Driver.cache.hostnames[url.hostname] = unique([
- ...(Driver.cache.hostnames[url.hostname] || []),
- ...detections
- ])
+ async onDetect(url, detections = [], language) {
+ // Cache detections
+ // eslint-disable-next-line standard/computed-property-even-spacing
+ Driver.cache.hostnames[url.hostname] = {
+ ...(Driver.cache.hostnames[url.hostname] || {
+ detections: []
+ }),
+ dateTime: Date.now()
+ }
+
+ Driver.cache.hostnames[url.hostname].language =
+ Driver.cache.hostnames[url.hostname].language || language
+
+ detections.forEach((detection) => {
+ const foo = Driver.cache.hostnames[url.hostname].detections
+ const {
+ technology: { name },
+ pattern: { regex }
+ } = detection
+
+ const cache = foo.find(
+ ({ technology: { name: _name }, pattern: { regex: _regex } }) =>
+ name === _name && (!regex || regex) === _regex
+ )
+
+ if (cache) {
+ cache.hits += 1
+ } else {
+ foo.push({
+ ...detection,
+ hits: 1
+ })
+ }
+ })
+
+ // Expire cache
+ Driver.cache.hostnames = Object.keys(Driver.cache.hostnames).reduce(
+ (hostnames, hostname) => {
+ const cache = Driver.cache.hostnames[hostname]
+
+ if (cache.dateTime > Date.now() - expiry) {
+ hostnames[hostname] = cache
+ }
+
+ return hostnames
+ },
+ {}
+ )
+
+ await setOption(
+ 'hostnames',
+ Object.keys(Driver.cache.hostnames).reduce(
+ (cache, hostname) => ({
+ ...cache,
+ [hostname]: {
+ ...Driver.cache.hostnames[hostname],
+ detections: Driver.cache.hostnames[hostname].detections.map(
+ ({
+ pattern: { regex, confidence, version },
+ match,
+ technology: { name: technology }
+ }) => ({
+ technology,
+ pattern: {
+ regex: regex.source,
+ confidence,
+ version
+ },
+ match
+ })
+ )
+ }
+ }),
+ {}
+ )
+ )
- const resolved = resolve(Driver.cache.hostnames[url.hostname])
+ const resolved = resolve(Driver.cache.hostnames[url.hostname].detections)
await Driver.setIcon(url, resolved)
+
+ const tabs = await promisify(chrome.tabs, 'query', { url: [url.href] })
+
+ tabs.forEach(({ id }) => (Driver.cache.tabs[id] = resolved))
+
+ await Driver.ping()
+ },
+
+ async onAd(ad) {
+ Driver.cache.ads.push(ad)
+
+ await setOption('ads', Driver.cache.ads)
},
async setIcon(url, technologies) {
@@ -292,24 +337,152 @@ const Driver = {
},
async getDetections() {
- const [{ url: href }] = await promisify(chrome.tabs, 'query', {
+ const [{ id }] = await promisify(chrome.tabs, 'query', {
active: true,
currentWindow: true
})
+ return Driver.cache.tabs[id]
+ },
+
+ async getRobots(hostname, secure = false) {
+ if (!(await getOption('tracking', true))) {
+ return
+ }
+
+ if (typeof Driver.cache.robots[hostname] !== 'undefined') {
+ return Driver.cache.robots[hostname]
+ }
+
+ try {
+ Driver.cache.robots[hostname] = await Promise.race([
+ new Promise(async (resolve) => {
+ const response = await fetch(
+ `http${secure ? 's' : ''}://${hostname}/robots.txt`,
+ {
+ redirect: 'follow',
+ mode: 'no-cors'
+ }
+ )
+
+ if (!response.ok) {
+ Driver.error(new Error(response.statusText))
+
+ resolve('')
+ }
+
+ let agent
+
+ resolve(
+ (await response.text()).split('\n').reduce((disallows, line) => {
+ let matches = /^User-agent:\s*(.+)$/i.exec(line.trim())
+
+ if (matches) {
+ agent = matches[1].toLowerCase()
+ } else if (agent === '*' || agent === 'wappalyzer') {
+ matches = /^Disallow:\s*(.+)$/i.exec(line.trim())
+
+ if (matches) {
+ disallows.push(matches[1])
+ }
+ }
+
+ return disallows
+ }, [])
+ )
+ }),
+ new Promise((resolve) => setTimeout(() => resolve(''), 5000))
+ ])
+
+ Driver.cache.robots = Object.keys(Driver.cache.robots)
+ .slice(-50)
+ .reduce(
+ (cache, hostname) => ({
+ ...cache,
+ [hostname]: Driver.cache.robots[hostname]
+ }),
+ {}
+ )
+
+ await setOption('robots', Driver.cache.robots)
+
+ return Driver.cache.robots[hostname]
+ } catch (error) {
+ Driver.error(error)
+ }
+ },
+
+ async checkRobots(href) {
const url = new URL(href)
- return resolve(Driver.cache.hostnames[url.hostname])
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') {
+ throw new Error('Invalid protocol')
+ }
+
+ const robots = await Driver.getRobots(
+ url.hostname,
+ url.protocol === 'https:'
+ )
+
+ if (robots.some((disallowed) => url.pathname.indexOf(disallowed) === 0)) {
+ throw new Error('Disallowed')
+ }
+ },
+
+ async ping() {
+ const tracking = await getOption('tracking', true)
+ const termsAccepted =
+ agent === 'chrome' || (await getOption('termsAccepted', false))
+
+ if (tracking && termsAccepted) {
+ const count = Object.keys(Driver.cache.hostnames).length
+
+ if (count && (count >= 50 || Driver.lastPing < Date.now() - 5000)) {
+ await Driver.post(
+ 'https://api.wappalyzer.com/ping/v1/',
+ Object.keys(Driver.cache.hostnames).reduce((hostnames, hostname) => {
+ const { language, detections } = Driver.cache.hostnames[hostname]
+
+ hostnames[hostname] = hostnames[hostname] || {
+ applications: {},
+ meta: {
+ language
+ }
+ }
+
+ resolve(detections).forEach(({ name, confidence, version }) => {
+ if (confidence === 100) {
+ console.log(
+ name,
+ detections.find(
+ ({ technology: { name: _name } }) => name === _name
+ )
+ )
+ hostnames[hostname].applications[name] = {
+ version,
+ hits: detections.find(
+ ({ technology: { name: _name } }) => name === _name
+ ).pattern.hits
+ }
+ }
+ })
+
+ return hostnames
+ }, {})
+ )
+
+ await setOption('hostnames', (Driver.cache.hostnames = {}))
+
+ Driver.lastPing = Date.now()
+ }
+
+ if (Driver.cache.ads.length > 50) {
+ await Driver.post('https://ad.wappalyzer.com/log/wp/', Driver.cache.ads)
+
+ await setOption('ads', (Driver.cache.ads = []))
+ }
+ }
}
}
-;(async function() {
- await Driver.loadTechnologies()
-
- chrome.runtime.onConnect.addListener(Driver.onRuntimeConnect)
- chrome.webRequest.onCompleted.addListener(
- Driver.onWebRequestComplete,
- { urls: ['http://*/*', 'https://*/*'], types: ['main_frame'] },
- ['responseHeaders']
- )
-})()
+Driver.init()
diff --git a/src/drivers/webextension/js/lib/iframe.js b/src/drivers/webextension/js/lib/iframe.js
index e132433c8..38ea3af38 100644
--- a/src/drivers/webextension/js/lib/iframe.js
+++ b/src/drivers/webextension/js/lib/iframe.js
@@ -120,8 +120,8 @@ var exports = {};
return dict;
},
sendToBackground: function(message, event, responseMessage) {
- if ( typeof browser !== 'undefined' || typeof chrome !== 'undefined' ) {
- var port = browser.runtime.connect({name:"adparser"});
+ if ( typeof chrome !== 'undefined' ) {
+ var port = chrome.runtime.connect({name:"adparser"});
port.onMessage.addListener((message) => {
if ( message && message.tracking_enabled ) {
@@ -1088,8 +1088,8 @@ var exports = {};
}
function addBackgroundListener(event, callback) {
- if ( typeof browser !== 'undefined' || typeof chrome !== 'undefined' ) {
- browser.runtime.onMessage.addListener(function(msg) {
+ if ( typeof chrome !== 'undefined' ) {
+ chrome.runtime.onMessage.addListener(function(msg) {
if ( msg.event === event ) {
callback(msg);
}
@@ -1111,6 +1111,7 @@ var exports = {};
if ( origUrl.indexOf('google.com/_/chrome/newtab') === -1 ) {
var onBlockedRobotsMessage = function() {
+ return // TODO
var log;
log = _logGen.log('invalid-robotstxt', []);
log.doc.finalPageUrl = log.doc.url;
@@ -1173,7 +1174,7 @@ if ( exports.utils.SCRIPT_IN_WINDOW_TOP ) {
})(window);
(function(adparser, pageUrl) {
function onAdFound(log) {
- adparser.sendToBackground({ id: 'ad_log', subject: log }, 'ad_log', '', function(){});
+ adparser.sendToBackground({ func: 'onAd', args: [log] }, 'onAd', '', function(){});
}
if ( adparser && adparser.inWindowTop ) {
diff --git a/src/drivers/webextension/js/lib/jsontodom.js b/src/drivers/webextension/js/lib/jsontodom.js
deleted file mode 100644
index 24d9e4c29..000000000
--- a/src/drivers/webextension/js/lib/jsontodom.js
+++ /dev/null
@@ -1,63 +0,0 @@
-jsonToDOM.namespaces = {
- html: 'http://www.w3.org/1999/xhtml',
- xul: 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul',
-};
-
-jsonToDOM.defaultNamespace = jsonToDOM.namespaces.html;
-
-function jsonToDOM(jsonTemplate, doc, nodes) {
- function namespace(name) {
- const reElemNameParts = /^(?:(.*):)?(.*)$/.exec(name);
- return { namespace: jsonToDOM.namespaces[reElemNameParts[1]], shortName: reElemNameParts[2] };
- }
-
- // Note that 'elemNameOrArray' is: either the full element name (eg. [html:]div) or an array of elements in JSON notation
- function tag(elemNameOrArray, elemAttr) {
- // Array of elements? Parse each one...
- if (Array.isArray(elemNameOrArray)) {
- const frag = doc.createDocumentFragment();
- Array.prototype.forEach.call(arguments, (thisElem) => {
- frag.appendChild(tag(...thisElem));
- });
- return frag;
- }
-
- // Single element? Parse element namespace prefix (if none exists, default to defaultNamespace), and create element
- const elemNs = namespace(elemNameOrArray);
- const elem = doc.createElementNS(elemNs.namespace || jsonToDOM.defaultNamespace, elemNs.shortName);
-
- // Set element's attributes and/or callback functions (eg. onclick)
- for (const key in elemAttr) {
- const val = elemAttr[key];
- if (nodes && key == 'key') {
- nodes[val] = elem;
- continue;
- }
-
- const attrNs = namespace(key);
- if (typeof val === 'function') {
- // Special case for function attributes; don't just add them as 'on...' attributes, but as events, using addEventListener
- elem.addEventListener(key.replace(/^on/, ''), val, false);
- } else {
- // Note that the default namespace for XML attributes is, and should be, blank (ie. they're not in any namespace)
- elem.setAttributeNS(attrNs.namespace || '', attrNs.shortName, val);
- }
- }
-
- // Create and append this element's children
- const childElems = Array.prototype.slice.call(arguments, 2);
- childElems.forEach((childElem) => {
- if (childElem != null) {
- elem.appendChild(
- childElem instanceof doc.defaultView.Node ? childElem
- : Array.isArray(childElem) ? tag(...childElem)
- : doc.createTextNode(childElem),
- );
- }
- });
-
- return elem;
- }
-
- return tag(...jsonTemplate);
-}
diff --git a/src/drivers/webextension/js/lib/network.js b/src/drivers/webextension/js/lib/network.js
index 7c46fcf9f..f9f58d843 100644
--- a/src/drivers/webextension/js/lib/network.js
+++ b/src/drivers/webextension/js/lib/network.js
@@ -1,19 +1,6 @@
-(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i= MIN_FF_MAJOR_VERSION) {
- callback();
- } else {
- elseCallback();
- }
- });
- } catch (err) {
-
- elseCallback();
- }
- } else {
- elseCallback();
- }
+ chrome.webNavigation.getFrame(getFrameDetails, callback);
}
function ifTrackingEnabled(details, ifCallback, elseCallback) {
@@ -112,24 +72,19 @@
allowedByRobotsTxt(details, ifCallback, elseCallback);
};
- browser.storage.local.get('tracking').then(function(item) {
-
- if ( item.hasOwnProperty('tracking') ) {
- if ( item.tracking ) {
- fullIfCallback();
- } else {
- elseCallback();
- }
- } else {
- fullIfCallback();
- }
+ Utils.getOption('tracking', true).then(function(tracking) {
+ if ( tracking ) {
+ fullIfCallback();
+ } else {
+ elseCallback();
+ }
});
}
function allowedByRobotsTxt(details, ifCallback, elseCallback) {
if ( details.url && !details.url.startsWith('chrome://') ) {
- robotsTxtAllows(details.url).then(ifCallback, elseCallback);
+ Driver.checkRobots(details.url, details.url.startsWith('https:')).then(ifCallback).catch(elseCallback);
} else {
elseCallback();
}
@@ -268,7 +223,7 @@
PageNetworkTrafficCollector.prototype.sendLogMessageToTabConsole = function() {
var logMessage = Array.from(arguments).join(' ');
var message = {message: logMessage, event: 'console-log-message'};
- browser.tabs.sendMessage(this.tabId, message);
+ chrome.tabs.sendMessage(this.tabId, message);
};
PageNetworkTrafficCollector.prototype.sendToTab = function(assetReq, reqs, curPageUrl, adTrackingEvent) {
@@ -298,7 +253,7 @@
msg.origUrl = curPageUrl;
msg.displayAdFound = this.displayAdFound;
- browser.tabs.sendMessage(this.tabId, msg);
+ chrome.tabs.sendMessage(this.tabId, msg);
};
PageNetworkTrafficCollector.prototype.getRedirKey = function(url, frameId) {
@@ -615,7 +570,7 @@
var _this = this,
origPageUrl, msgAssetReq;
msgAssetReq = this.msgsBeingSent[msgKey];
- browser.tabs.get(this.tabId).then(function(tab) {
+ chrome.tabs.get(this.tabId, function(tab) {
origPageUrl = tab.url;
});
@@ -697,110 +652,85 @@
function registerListeners() {
- browser.webRequest.onBeforeRequest.addListener(
+ chrome.webRequest.onBeforeRequest.addListener(
onBeforeRequestListener,
{urls: ['http://*/*', 'https://*/*']},
[]
);
- browser.webRequest.onSendHeaders.addListener(
+ chrome.webRequest.onSendHeaders.addListener(
onSendHeadersListener,
{urls: ['http://*/*', 'https://*/*']},
['requestHeaders']
);
- browser.webRequest.onHeadersReceived.addListener(
+ chrome.webRequest.onHeadersReceived.addListener(
onHeadersReceivedListener,
{urls: ['http://*/*', 'https://*/*']},
['responseHeaders']
);
- browser.webRequest.onBeforeRedirect.addListener(
+ chrome.webRequest.onBeforeRedirect.addListener(
onBeforeRedirectListener,
{urls: ['http://*/*', 'https://*/*']},
[]
);
- browser.webRequest.onResponseStarted.addListener(
+ chrome.webRequest.onResponseStarted.addListener(
onResponseStartedListener,
{urls: ['http://*/*', 'https://*/*']},
['responseHeaders']
);
- browser.webNavigation.onCommitted.addListener(onCommittedListener);
- browser.webNavigation.onCompleted.addListener(onCompletedListener);
- browser.tabs.onRemoved.addListener(onRemovedListener);
- browser.runtime.onMessage.addListener(onMessageListener);
+ chrome.webNavigation.onCommitted.addListener(onCommittedListener);
+ chrome.webNavigation.onCompleted.addListener(onCompletedListener);
+ chrome.tabs.onRemoved.addListener(onRemovedListener);
+ chrome.runtime.onMessage.addListener(onMessageListener);
areListenersRegistered = true;
}
function unregisterListeners() {
- browser.webRequest.onBeforeRequest.removeListener(
+ chrome.webRequest.onBeforeRequest.removeListener(
onBeforeRequestListener
);
- browser.webRequest.onSendHeaders.removeListener(
+ chrome.webRequest.onSendHeaders.removeListener(
onSendHeadersListener
);
- browser.webRequest.onHeadersReceived.removeListener(
+ chrome.webRequest.onHeadersReceived.removeListener(
onHeadersReceivedListener
);
- browser.webRequest.onBeforeRedirect.removeListener(
+ chrome.webRequest.onBeforeRedirect.removeListener(
onBeforeRedirectListener
);
- browser.webRequest.onResponseStarted.removeListener(
+ chrome.webRequest.onResponseStarted.removeListener(
onResponseStartedListener
);
- browser.webNavigation.onCommitted.removeListener(onCommittedListener);
- browser.webNavigation.onCompleted.removeListener(onCompletedListener);
- browser.tabs.onRemoved.removeListener(onRemovedListener);
- browser.runtime.onMessage.removeListener(onMessageListener);
+ chrome.webNavigation.onCommitted.removeListener(onCommittedListener);
+ chrome.webNavigation.onCompleted.removeListener(onCompletedListener);
+ chrome.tabs.onRemoved.removeListener(onRemovedListener);
+ chrome.runtime.onMessage.removeListener(onMessageListener);
areListenersRegistered = false;
}
- function areRequiredBrowserApisAvailable() {
- return requiredBrowserApis.every(function(api) {
- return typeof api !== 'undefined';
- });
- }
-
- if ( areRequiredBrowserApisAvailable() ) {
- ifBrowserValid(
- function() {
- browser.webNavigation.onBeforeNavigate.addListener(
- function(details) {
- if ( details.frameId === 0 ) {
- globalPageContainer.onNewNavigation(details);
- }
- },
- {
- url: [{urlMatches: 'http://*/*'}, {urlMatches: 'https://*/*'}]
- }
- );
- }, function() {
-
- }
- );
- }
-
- browser.runtime.onConnect.addListener((port) => {
- port.onMessage.addListener((message) => {
- if ( message === 'is_browser_valid' ) {
- ifBrowserValid(
- port.postMessage({'browser_valid': true}),
- port.postMessage({'browser_valid': false})
- );
- }
- });
- });
-
- browser.runtime.onConnect.addListener((port) => {
+ chrome.webNavigation.onBeforeNavigate.addListener(
+ function(details) {
+ if ( details.frameId === 0 ) {
+ globalPageContainer.onNewNavigation(details);
+ }
+ },
+ {
+ url: [{urlMatches: 'http://*/*'}, {urlMatches: 'https://*/*'}]
+ }
+ );
+
+ chrome.runtime.onConnect.addListener((port) => {
port.onMessage.addListener((message) => {
if ( message === 'is_tracking_enabled' ) {
ifTrackingEnabled(
@@ -816,7 +746,4 @@
return true;
});
});
-
})();
-
-},{}]},{},[1]);
diff --git a/src/drivers/webextension/js/popup.js b/src/drivers/webextension/js/popup.js
index a58e1cb79..5852af745 100644
--- a/src/drivers/webextension/js/popup.js
+++ b/src/drivers/webextension/js/popup.js
@@ -122,22 +122,44 @@ const Popup = {
})
)
- technologies.forEach(({ name, slug, icon, website }) => {
- const technologyNode = Popup.templates.technology.cloneNode(true)
+ technologies
+ .filter(({ confidence }) => confidence)
+ .forEach(({ name, slug, confidence, version, icon, website }) => {
+ const technologyNode = Popup.templates.technology.cloneNode(true)
- const image = technologyNode.querySelector('.technology__icon')
+ const image = technologyNode.querySelector('.technology__icon')
- image.src = `../images/icons/${icon}`
+ image.src = `../images/icons/${icon}`
- const link = technologyNode.querySelector('.technology__link')
+ const link = technologyNode.querySelector('.technology__link')
- link.href = `https://www.wappalyzer.com/technologies/${categorySlug}/${slug}`
- link.textContent = name
+ link.href = `https://www.wappalyzer.com/technologies/${categorySlug}/${slug}`
+ link.textContent = name
- categoryNode
- .querySelector('.technologies')
- .appendChild(technologyNode)
- })
+ const confidenceNode = technologyNode.querySelector(
+ '.technology__confidence'
+ )
+
+ if (confidence < 100) {
+ confidenceNode.textContent = `${confidence}% sure`
+ } else {
+ confidenceNode.remove()
+ }
+
+ const versionNode = technologyNode.querySelector(
+ '.technology__version'
+ )
+
+ if (version) {
+ versionNode.textContent = version
+ } else {
+ versionNode.remove()
+ }
+
+ categoryNode
+ .querySelector('.technologies')
+ .appendChild(technologyNode)
+ })
document.querySelector('.detections').appendChild(categoryNode)
}