From ae66a578baf9bd1d1daa07bbc44ec755998c618e Mon Sep 17 00:00:00 2001 From: ElbertF Date: Sat, 24 Dec 2011 16:13:46 +1100 Subject: [PATCH] Work on Firefox adapter --- adapters/firefox/chrome.manifest | 8 +- adapters/firefox/chrome/content/js/adapter.js | 675 ------------------ adapters/firefox/chrome/content/js/content.js | 122 ---- .../firefox/chrome/content/xul/wappalyzer.xul | 58 -- .../chrome/locale/en-US/wappalyzer.dtd | 51 -- .../chrome/locale/en-US/wappalyzer.properties | 3 - adapters/firefox/content/js/adapter.js | 68 ++ .../firefox/{chrome => }/content/js/apps.js | 0 adapters/firefox/content/js/content.js | 28 + .../firefox/{chrome => }/content/js/custom.js | 0 .../{chrome => }/content/js/evaluate.js | 0 .../{chrome => }/content/js/options.js | 0 .../{chrome => }/content/js/wappalyzer.js | 0 .../{chrome => }/content/xul/options.xul | 0 adapters/firefox/content/xul/wappalyzer.xul | 40 ++ adapters/firefox/locale/en-US/wappalyzer.dtd | 27 + .../locale/en-US/wappalyzer.properties | 1 + .../{chrome => }/skin/css/wappalyzer.css | 0 .../{chrome => }/skin/images/donate.png | Bin .../{chrome => }/skin/images/feedback.png | Bin .../{chrome => }/skin/images/github.ico | Bin .../{chrome => }/skin/images/icon16x16.ico | Bin .../skin/images/icon16x16_hot.ico | Bin .../{chrome => }/skin/images/icon32x32.png | Bin .../firefox/{chrome => }/skin/images/icons | 0 .../{chrome => }/skin/images/options.png | Bin .../{chrome => }/skin/images/twitter.ico | Bin adapters/html/images/icon.png | Bin 0 -> 12044 bytes adapters/html/index.html | 2 + adapters/html/js/adapter.js | 7 + wappalyzer.js | 158 ++-- 31 files changed, 265 insertions(+), 983 deletions(-) delete mode 100644 adapters/firefox/chrome/content/js/adapter.js delete mode 100644 adapters/firefox/chrome/content/js/content.js delete mode 100755 adapters/firefox/chrome/content/xul/wappalyzer.xul delete mode 100755 adapters/firefox/chrome/locale/en-US/wappalyzer.dtd delete mode 100755 adapters/firefox/chrome/locale/en-US/wappalyzer.properties create mode 100644 adapters/firefox/content/js/adapter.js rename adapters/firefox/{chrome => }/content/js/apps.js (100%) create mode 100644 adapters/firefox/content/js/content.js rename adapters/firefox/{chrome => }/content/js/custom.js (100%) rename adapters/firefox/{chrome => }/content/js/evaluate.js (100%) rename adapters/firefox/{chrome => }/content/js/options.js (100%) rename adapters/firefox/{chrome => }/content/js/wappalyzer.js (100%) rename adapters/firefox/{chrome => }/content/xul/options.xul (100%) create mode 100755 adapters/firefox/content/xul/wappalyzer.xul create mode 100755 adapters/firefox/locale/en-US/wappalyzer.dtd create mode 100755 adapters/firefox/locale/en-US/wappalyzer.properties rename adapters/firefox/{chrome => }/skin/css/wappalyzer.css (100%) rename adapters/firefox/{chrome => }/skin/images/donate.png (100%) rename adapters/firefox/{chrome => }/skin/images/feedback.png (100%) rename adapters/firefox/{chrome => }/skin/images/github.ico (100%) rename adapters/firefox/{chrome => }/skin/images/icon16x16.ico (100%) rename adapters/firefox/{chrome => }/skin/images/icon16x16_hot.ico (100%) rename adapters/firefox/{chrome => }/skin/images/icon32x32.png (100%) rename adapters/firefox/{chrome => }/skin/images/icons (100%) rename adapters/firefox/{chrome => }/skin/images/options.png (100%) rename adapters/firefox/{chrome => }/skin/images/twitter.ico (100%) create mode 100644 adapters/html/images/icon.png diff --git a/adapters/firefox/chrome.manifest b/adapters/firefox/chrome.manifest index a8be77a4a..2c74ed59d 100644 --- a/adapters/firefox/chrome.manifest +++ b/adapters/firefox/chrome.manifest @@ -1,5 +1,5 @@ -content wappalyzer chrome/content/ -locale wappalyzer en-US chrome/locale/en-US/ -skin wappalyzer classic/1.0 chrome/skin/ +content wappalyzer content/ +locale wappalyzer en-US locale/en-US/ +skin wappalyzer classic/1.0 skin/ -overlay chrome://browser/content/browser.xul chrome://wappalyzer/content/wappalyzer.xul +overlay chrome://browser/content/browser.xul chrome://wappalyzer/content/xul/wappalyzer.xul diff --git a/adapters/firefox/chrome/content/js/adapter.js b/adapters/firefox/chrome/content/js/adapter.js deleted file mode 100644 index aa0f7bdc3..000000000 --- a/adapters/firefox/chrome/content/js/adapter.js +++ /dev/null @@ -1,675 +0,0 @@ -// Wappalyzer by ElbertF 2009 http://elbertf.com - -var wappalyzer = (function() { - var self = { - apps: {}, - appsDetected: 0, - browser: false, - cats: {}, - checkUnique: {}, - currentTab: false, - customApps: '', - debug: false, - enableTracking: true, - githubUrl: 'https://github.com/ElbertF/Wappalyzer', - history: {}, - hitCount: 0, - homeUrl: 'http://wappalyzer.com/', - hoverTimeout: false, - newInstall: false, - popupOnHover: true, - prevUrl: '', - prefs: {}, - regexBlacklist: /(dev\.|\/admin|\.local)/, - regexDomain: /^[a-z0-9._\-]+\.[a-z]+/, - req: false, - request: false, - showApps: 1, - showCats: [], - strings: {}, - twitterUrl: 'https://twitter.com/Wappalyzer', - version: '', - - init: function() { - self.log('init'); - - self.browser = gBrowser; - - self.strings = document.getElementById('wappalyzer-strings'); - - // Preferences - self.prefs = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('wappalyzer.'); - - self.prefs.QueryInterface(Components.interfaces.nsIPrefBranch2); - self.prefs.addObserver('', wappalyzer, false); - - self.showApps = self.prefs.getIntPref( 'showApps'); - self.customApps = self.prefs.getCharPref('customApps'); - self.debug = self.prefs.getBoolPref('debug'); - self.enableTracking = self.prefs.getBoolPref('enableTracking'); - self.popupOnHover = self.prefs.getBoolPref('popupOnHover'); - self.newInstall = self.prefs.getBoolPref('newInstall'); - self.version = self.prefs.getCharPref('version'); - - var i = 0; - - while ( ++ i ) { - try { - self.showCats[i] = self.prefs.getBoolPref('cat' + i); - } catch (e) { - break; - } - } - - var locationPref = self.prefs.getIntPref('location'); - - self.moveLocation(locationPref); - - // Open page after installation - if ( self.newInstall ) { - self.prefs.setBoolPref('newInstall', false); - - gBrowser.addEventListener('DOMContentLoaded', self.installSuccess, false); - } else { - // Open page after upgrade - try { - var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch); - - var enabledItems = prefs.getCharPref('extensions.enabledAddons'); - var version = enabledItems.replace(/(^.*wappalyzer[^:]+:)([^,]+),.*$/, '$2'); - - if ( version && self.version != version ) { - gBrowser.addEventListener('DOMContentLoaded', self.upgradeSuccess, false); - - self.version = version; - - self.prefs.setCharPref('version', self.version); - } - } - catch(e) { } - } - - // Listen messages sent from the content process - if ( typeof messageManager != 'undefined' ) { - messageManager.addMessageListener('wappalyzer:onPageLoad', self.onContentPageLoad); - - messageManager.loadFrameScript('chrome://wappalyzer/content/content.js', true); - } - - // Listen for URL changes - self.browser.addProgressListener(self.urlChange, Components.interfaces.nsIWebProgress.NOTIFY_LOCATION); - - // Listen for page loads - self.browser.addEventListener('DOMContentLoaded', self.onPageLoad, true); - - self.evaluateCustomApps(); - }, - - // Log messages to console - log: function(message) { - if ( self.debug && message ) { - var consoleService = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService); - - consoleService.logStringMessage("Wappalyzer: " + message); - } - }, - - // Listen for preference changes - observe: function(subject, topic, data) { - if ( topic != 'nsPref:changed' ) { - return; - } - - switch(true) { - case data == 'customApps': - self.customApps = self.prefs.getCharPref('customApps'); - - break; - case data == 'debug': - self.debug = self.prefs.getBoolPref('debug'); - - break; - case data == 'enableTracking': - self.enableTracking = self.prefs.getBoolPref('enableTracking'); - - break; - case data == 'popupOnHover': - self.popupOnHover = self.prefs.getBoolPref('popupOnHover'); - - self.moveLocation(); - - break; - case data == 'showApps': - self.showApps = self.prefs.getIntPref('showApps'); - - break; - case data == 'location': - var locationPref = self.prefs.getIntPref('location'); - - self.moveLocation(locationPref); - - break; - case data.test(/^cat[0-9]+$/): - var cat = data.replace(/^cat([0-9]+)$/, '$1'); - - self.showCats[cat] = self.prefs.getIntPref('cat' + cat); - - break; - } - }, - - openTab: function(url) { - self.browser.selectedTab = self.browser.addTab(url); - }, - - moveLocation: function(locationPref) { - self.log('moveLocation'); - - switch ( locationPref ) { - case 1: - var containerId = 'wappalyzer-statusbar'; - - // Show status bar panel - document.getElementById('wappalyzer-statusbar').style.visibility = ''; - document.getElementById('wappalyzer-statusbar').style.padding = '1px'; - - break; - default: - var containerId = 'urlbar-icons'; - - // Hide status bar panel - document.getElementById('wappalyzer-statusbar').style.visibility = 'hidden'; - document.getElementById('wappalyzer-statusbar').style.padding = '0'; - } - - var e = document.getElementById(containerId); - var container = document.getElementById('wappalyzer-container'); - - if ( self.popupOnHover ) { - container.addEventListener('mouseover', function() { - self.hoverTimeout = setTimeout(function() { - document.getElementById('wappalyzer-apps').openPopup(document.getElementById('wappalyzer-container'), 'after_end'); - }, 200); - }, false); - - container.addEventListener('mouseout', function() { clearTimeout(self.hoverTimeout); }, false); - } - - e.appendChild(container); - }, - - onPageLoad: function(event) { - self.log('onPageLoad'); - - var target = event.originalTarget; - - if ( !target.request ) { - self.request = false; - } - - self.analyzePage( - target.documentElement, - target.location.href, - target.documentElement.innerHTML, - [], - [], - true - ); - }, - - onContentPageLoad: function(message) { - self.log('onContentPageLoad'); - - self.analyzePage( - null, - message.json.href, - message.json.html, - message.json.headers, - message.json.environmentVars, - true - ); - }, - - onUrlChange: function(request) { - self.log('onUrlChange'); - - self.clearDetectedApps(); - - var doc = self.browser.contentDocument; - - self.request = doc.request ? doc.request : request; - - self.currentTab = false; - - self.analyzePage( - doc, - doc.location.href ? doc.location.href : '', - doc.documentElement ? doc.documentElement.innerHTML : '', - [], - [], - false - ); - }, - - urlChange: { - QueryInterface: function(iid) { - if ( iid.equals(Components.interfaces.nsIWebProgressListener) || - iid.equals(Components.interfaces.nsISupportsWeakReference) || - iid.equals(Components.interfaces.nsISupports) ) { - return this; - } - - throw Components.results.NS_NOINTERFACE; - }, - - onLocationChange: function(progress, request, url) { - self.log('urlChange.onLocationChange'); - - if ( !url ) { - self.prevUrl = ''; - - return; - } - - if ( url.spec != self.prevUrl ) { - self.prevUrl = url.spec; - - self.onUrlChange(request); - } - }, - - onStateChange: function(a, b, c, d) {}, - onProgressChange: function(a, b, c, d, e, f) {}, - onStatusChange: function(a, b, c, d) {}, - onSecurityChange: function(a, b, c) {} - }, - - analyzePage: function(doc, href, html, headers, environmentVars, doCount) { - self.log('analyzePage'); - - self.currentTab = false; - - if ( href == self.browser.contentDocument.location.href ) { - self.currentTab = true; - - if ( !doc ) { - doc = self.browser.contentDocument; - } - - self.clearDetectedApps(); - } - - if ( typeof html == 'undefined' ) { - html = ''; - } - - // Prevent large documents from slowing things down - if ( html.length > 50000 ) { - html = html.substring(0, 25000) + html.substring(html.length - 25000, html.length); - } - - // Scan URL, domain and response headers for patterns - if ( html || self.request ) { - // Check cached application names - if ( doc && typeof doc.detectedApps != 'undefined' ) { - for ( i in doc.detectedApps ) { - var appName = doc.detectedApps[i]; - - if ( typeof self.checkUnique[appName] == 'undefined' ) { - self.log('CACHE'); // - - self.showApp(appName, doc, href, doCount); - - self.checkUnique[appName] = true; - } - } - } - - for ( var appName in self.apps ) { - // Don't scan for apps that have already been detected - if ( typeof self.checkUnique[appName] == 'undefined' ) { - // Scan HTML - if ( html && typeof self.apps[appName].html != 'undefined' ) { - if ( self.apps[appName].html.test(html) ) { - self.showApp(appName, doc, href, doCount); - } - } - - // Scan script tags - if ( html && typeof self.apps[appName].script != 'undefined' ) { - var - regex = /]+src=("|')([^"']+)\1/ig, - match = [] - ; - - while ( match = regex.exec(html) ) { - if ( self.apps[appName].script.test(match[2]) ) { - self.showApp(appName, doc, href, doCount); - - break; - } - } - } - - // Scan meta tags - if ( html && typeof self.apps[appName].meta != 'undefined' ) { - var - regex = /]+>/ig, - match = [] - ; - - while ( match = regex.exec(html) ) { - for ( meta in self.apps[appName].meta ) { - if ( new RegExp('name=["\']' + meta + '["\']', 'i').test(match) ) { - var content = match.toString().match(/content=("|')([^"']+)("|')/i); - - if ( self.apps[appName].meta[meta].test(content[2]) ) { - self.showApp(appName, doc, href, doCount); - - break; - } - } - } - } - } - - // Scan URL - if ( href && typeof self.apps[appName].url != 'undefined' ) { - var regex = self.apps[appName].url; - - if ( regex.test(href) ) { - self.showApp(appName, doc, href, doCount); - } - } - - // Scan response headers - if ( typeof self.apps[appName].headers != 'undefined' && self.request ) { - for ( var header in self.apps[appName].headers ) { - var regex = self.apps[appName].headers[header]; - - try { - if ( regex.test(self.request.nsIHttpChannel.getResponseHeader(header)) ) { - self.showApp(appName, doc, href, doCount); - } - } - catch(e) { } - } - } - - // Scan environment variables - if ( environmentVars && typeof self.apps[appName].env != 'undefined' ) { - var regex = self.apps[appName].env; - - for ( var i in environmentVars ) { - try { - if ( regex.test(environmentVars[i]) ) { - self.showApp(appName, doc, href, doCount); - } - } - catch(e) { } - } - } - } - } - } - - html = ''; // Free memory - }, - - showApp: function(detectedApp, doc, href, doCount) { - self.log('showApp ' + detectedApp); - - self.report(detectedApp, href); - - // Keep detected application names in memory - if ( doc ) { - if ( typeof doc.detectedApps == 'undefined' ) { - doc.detectedApps = []; - } - - doc.detectedApps.push(detectedApp); - } - - if ( detectedApp && typeof self.checkUnique[detectedApp] == 'undefined' ) { - var show = false; - - for ( var i in self.apps[detectedApp].cats ) { - if ( self.showCats[self.apps[detectedApp].cats[i]] ) { - show = true; - - break; - } - } - - if ( show && self.currentTab ) { - var e = document.getElementById('wappalyzer-detected-apps'); - - if ( self.showApps == 2 ) { - document.getElementById('wappalyzer-icon').setAttribute('src', 'chrome://wappalyzer/skin/icon16x16_hot.ico'); - - document.getElementById('wappalyzer-detected-apps').style.display = 'none'; - } - else { - // Hide Wappalyzer icon - document.getElementById('wappalyzer-icon').style.display = 'none'; - - document.getElementById('wappalyzer-detected-apps').style.display = ''; - } - - // Show app icon and label - var child = document.createElement('image'); - - if ( typeof self.apps[detectedApp].icon == 'string' ) { - child.setAttribute('src', self.apps[detectedApp].icon); - } - else { - child.setAttribute('src', 'chrome://wappalyzer/skin/icons/' + detectedApp + '.ico'); - } - - child.setAttribute('class', 'wappalyzer-icon'); - - if ( self.appsDetected ) { - child.setAttribute('style', 'margin-left: .5em'); - } - - e.appendChild(child); - - if ( self.showApps == 0 ) { - var child = document.createElement('label'); - - child.setAttribute('value', detectedApp); - child.setAttribute('class', 'wappalyzer-app-name'); - - e.appendChild(child); - } - - // Show application in popup - var e = document.getElementById('wappalyzer-apps'); - - if ( !self.appsDetected ) { - // Remove "no apps detected" message - document.getElementById('wappalyzer-apps').removeChild(document.getElementById('wappalyzer-no-detected-apps')); - } - else { - var child = document.createElement('menuseparator'); - - e.appendChild(child); - } - - var child = document.createElement('menuitem'); - - child.setAttribute('class', 'menuitem-iconic'); - child.setAttribute('type', ''); - - child.addEventListener('command', function() { self.openTab(self.homeUrl + 'stats/app/' + escape(detectedApp)); }, false); - - if ( typeof self.apps[detectedApp].custom == 'undefined' ) { - child.setAttribute('label', detectedApp); - child.setAttribute('image', 'chrome://wappalyzer/skin/icons/' + detectedApp + '.ico'); - } - else { - child.setAttribute('label', detectedApp + ' (' + self.strings.getString('wappalyzer.custom') + ')'); - child.setAttribute('disabled', 'true'); - child.setAttribute('image', self.apps[detectedApp].icon); - } - - e.appendChild(child); - - if ( self.apps[detectedApp].cats ) { - for ( var i in self.apps[detectedApp].cats ) { - var child = document.createElement('menuitem'); - - child.setAttribute('label', self.cats[self.apps[detectedApp].cats[i]].name); - child.setAttribute('disabled', 'true'); - - e.appendChild(child); - } - } - } - - if ( doCount ) { - self.report(detectedApp, href); - } - - self.appsDetected ++; - - self.checkUnique[detectedApp] = true; - } - }, - - report: function(detectedApp, href) { - self.log('report'); - - if ( typeof self.apps[detectedApp].custom == 'undefined' ) { - var - regex = /:\/\/(.[^/]+)/, - domain = href.match(regex) ? href.match(regex)[1] : '' - ; - - if ( self.enableTracking && self.regexDomain.test(domain) && !self.regexBlacklist.test(href) ) { - if ( typeof self.history[domain] == 'undefined' ) { - self.history[domain] = []; - } - - if ( typeof self.history[domain][detectedApp] == 'undefined' ) { - self.history[domain][detectedApp] = 0; - } - - self.history[domain][detectedApp] ++; - - self.hitCount ++; - - if ( self.hitCount > 200 ) { - self.sendReport(); - } - } - } - }, - - // Anonymously send the name of the detected apps and domains to wappalyzer.com - // You can turn this off in the options dialog - // This is used to track the distribution of software, stats are publicly available on the site - sendReport: function() { - self.log('sendReport'); - - if ( self.enableTracking && !self.req ) { - var report = ''; - - if ( self.history ) { - for ( var i in self.history ) { - report += '[' + i; - - for ( var j in self.history[i] ) { - report += '|' + j + ':' + self.history[i][j]; - } - - report += ']'; - } - } - - // Make POST request - self.req = new XMLHttpRequest(); - - self.req.open('POST', self.homeUrl + 'report/', true); - - self.req.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE; - - self.req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - - self.req.onreadystatechange = function(e) { - if ( self.req.readyState == 4 ) { - if ( self.req.status == 200 ) { - // Reset - report = ''; - - self.hitCount = 0; - self.history = []; - } - - self.req.close(); - - self.req = false; - } - }; - - self.req.send('d=' + encodeURIComponent(report)); - } - }, - - clearDetectedApps: function() { - self.log('clearDetectedApps'); - - self.appsDetected = 0; - self.checkUnique = []; - - // Show Wappalyzer icon - document.getElementById('wappalyzer-icon').setAttribute('src', 'chrome://wappalyzer/skin/icon16x16.ico'); - document.getElementById('wappalyzer-icon').style.display = ''; - - // Clear app icons and labels - var e = document.getElementById('wappalyzer-detected-apps'); - - while ( e.childNodes.length > 0 ) { - e.removeChild(e.childNodes.item(0)); - } - - // Clear application popup - var e = document.getElementById('wappalyzer-apps'); - - while ( e.childNodes.length > 0 ) { - e.removeChild(e.childNodes.item(0)); - } - - var child = document.createElement('menuitem'); - - child.setAttribute('label', self.strings.getString('wappalyzer.noDetectedApps')); - child.setAttribute('id', 'wappalyzer-no-detected-apps'); - child.setAttribute('class', 'menuitem-iconic'); - child.setAttribute('disabled', 'true'); - child.setAttribute('type', ''); - - e.appendChild(child); - }, - - installSuccess: function() { - self.log('installSuccess'); - - gBrowser.removeEventListener('DOMContentLoaded', self.installSuccess, false); - - self.openTab(self.homeUrl + 'install/success/'); - }, - - upgradeSuccess: function() { - self.log('upgradeSuccess'); - - gBrowser.removeEventListener('DOMContentLoaded', self.upgradeSuccess, false); - - self.openTab(self.homeUrl + 'install/upgraded/'); - } - }; - - addEventListener('load', function() { self.init(); }, false); - addEventListener('unload', function() { self.sendReport(); }, false); - - return self; -})(); diff --git a/adapters/firefox/chrome/content/js/content.js b/adapters/firefox/chrome/content/js/content.js deleted file mode 100644 index 8ec2b7304..000000000 --- a/adapters/firefox/chrome/content/js/content.js +++ /dev/null @@ -1,122 +0,0 @@ -(function() { - var self = { - element: false, - prevUrl: '', - - init: function() { - self.log('init'); - - addEventListener('DOMContentLoaded', self.onPageLoad, false); - }, - - log: function(message) { - return; // - - var consoleService = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService); - - consoleService.logStringMessage("Wappalyzer content.js: " + message); - }, - - onPageLoad: function(e) { - self.log('onPageLoad'); - - self.getEnvironmentVars(); - }, - - onUrlChange: function(request) { - self.log('onUrlChange'); - - self.getEnvironmentVars(); - }, - - urlChange: { - QueryInterface: function(iid) { - if ( iid.equals(Components.interfaces.nsIWebProgressListener) || - iid.equals(Components.interfaces.nsISupportsWeakReference) || - iid.equals(Components.interfaces.nsISupports) ) { - return this; - } - - throw Components.results.NS_NOINTERFACE; - }, - - onLocationChange: function(progress, request, url) { - if ( !url ) { - self.prevUrl = ''; - - return; - } - - if ( url.spec != self.prevUrl ) { - self.prevUrl = url.spec; - - self.onUrlChange(request); - } - }, - - onStateChange: function(a, b, c, d) {}, - onProgressChange: function(a, b, c, d, e, f) {}, - onStatusChange: function(a, b, c, d) {}, - onSecurityChange: function(a, b, c) {} - }, - - getEnvironmentVars: function() { - self.log('getEnvironmentVars'); - - if ( content.document.contentType != 'text/html' || typeof content.document.html == 'undefined' ) { - return; - } - - var environmentVars = ''; - - try { - var element = content.document.createElement('wappalyzerData'); - - element.setAttribute('id', 'wappalyzerData'); - element.setAttribute('style', 'display: none'); - - content.document.documentElement.appendChild(element); - - content.location.href = 'javascript:' + - '(function() {' + - 'try {' + - 'var event = document.createEvent("Events");' + - - 'event.initEvent("wappalyzerEvent", true, false);' + - - 'var environmentVars = "";' + - - 'for ( var i in window ) environmentVars += i + " ";' + - - 'document.getElementById("wappalyzerData").appendChild(document.createComment(environmentVars));' + - - 'document.getElementById("wappalyzerData").dispatchEvent(event);' + - '}' + - 'catch(e) { }' + - '})();'; - - element.addEventListener('wappalyzerEvent', (function(event) { - environmentVars = event.target.childNodes[0].nodeValue; - - self.log('getEnvironmentVars: ' + environmentVars); - - element.parentNode.removeChild(element); - - sendAsyncMessage('wappalyzer:onPageLoad', { - href: content.document.location.href, - html: content.document.documentElement.innerHTML, - headers: [], - environmentVars: environmentVars.split(' ') - }); - }), true); - } - catch(e) { } - - return environmentVars; - } - } - - self.init(); - - return self; -})(); diff --git a/adapters/firefox/chrome/content/xul/wappalyzer.xul b/adapters/firefox/chrome/content/xul/wappalyzer.xul deleted file mode 100755 index 21fe6b4d2..000000000 --- a/adapters/firefox/chrome/content/xul/wappalyzer.xul +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - diff --git a/adapters/html/js/adapter.js b/adapters/html/js/adapter.js index 5958dfce4..a6a9ac020 100644 --- a/adapters/html/js/adapter.js +++ b/adapters/html/js/adapter.js @@ -4,6 +4,13 @@ var w = wappalyzer; w.adapter = { + /** + * Log messages to console + */ + log: function(args) { + if ( console != null ) console[args.type](args.message); + }, + /** * Initialize */ diff --git a/wappalyzer.js b/wappalyzer.js index 3f0f9aa05..256cc7cd2 100644 --- a/wappalyzer.js +++ b/wappalyzer.js @@ -17,7 +17,7 @@ var wappalyzer = wappalyzer || (function() { return; } - w.log('w.adapter.' + func); + if ( func != 'log' ) w.log('w.adapter.' + func); return w.adapter[func](args); }; @@ -27,11 +27,14 @@ var wappalyzer = wappalyzer || (function() { */ var w = { // Cache detected applications per URL - cache: new Array, + history: new Array, + detected: new Array, config: { environment: 'dev', // dev | live + version: false, + websiteURL: 'http://wappalyzer.com/', twitterURL: 'https://twitter.com/Wappalyzer', githubURL: 'https://github.com/ElbertF/Wappalyzer', @@ -44,10 +47,10 @@ var wappalyzer = wappalyzer || (function() { * Log messages to console */ log: function(message, type) { - if ( w.config.environment == 'dev' ) { - console[type || 'debug'](typeof message === 'string' ? '[wappalyzer] ' + message : message); + if ( w.config.environment === 'dev' ) { + if ( type == null ) type = 'debug'; - return true; + adapter('log', { message: '[wappalyzer ' + type + '] ' + message, type: type }); } }, @@ -80,106 +83,121 @@ var wappalyzer = wappalyzer || (function() { /** * Analyze the request */ - analyze: function(url, callback) { + analyze: function(hostname, url, data) { w.log('w.analyze'); - if ( !w.cache[url] ) { - var - apps = new Array(), - data = callback() - ; + var apps = new Array(); - if ( data ) { - for ( var app in w.apps ) { - for ( var type in w.apps[app] ) { - if ( apps.indexOf(app) !== -1 ) continue; // Skip if the app has already been detected + if ( w.history [hostname] == null ) w.history [hostname] = new Array(); + if ( w.detected[url] == null ) w.detected[url] = new Array(); - switch ( type ) { - case 'url': - if ( w.apps[app].url.test(data[type]) ) apps.push(app); + if ( data ) { + for ( var app in w.apps ) { + for ( var type in w.apps[app] ) { + if ( w.detected[url].indexOf(app) !== -1 && apps.indexOf(app) !== -1 ) continue; // Skip if the app has already been detected - break; - case 'html': - if ( w.apps[app].html.test(data[type]) ) apps.push(app); + switch ( type ) { + case 'url': + if ( w.apps[app].url.test(url) ) apps.push(app); - break; - case 'script': - if ( data['html'] == null ) break; + break; + case 'html': + if ( data[type] == null ) break; - var - regex = /]+src=("|')([^"']+)\1/ig, - match = [] - ; + if ( w.apps[app].html.test(data[type]) ) apps.push(app); - while ( match = regex.exec(data['html']) ) { - if ( w.apps[app].script.test(match[2]) ) { - apps.push(app); + break; + case 'script': + if ( data[type] == null || data['html'] == null ) break; - break; - } + var + regex = /]+src=("|')([^"']+)\1/ig, + match = [] + ; + + while ( match = regex.exec(data['html']) ) { + if ( w.apps[app].script.test(match[2]) ) { + apps.push(app); + + break; } + } - break; - case 'meta': - if ( data['html'] == null ) break; + break; + case 'meta': + if ( data[type] == null || data['html'] == null ) break; - var - regex = /]+>/ig, - match = [] - ; + var + regex = /]+>/ig, + match = [] + ; - while ( match = regex.exec(data['html']) ) { - for ( meta in w.apps[app].meta ) { - if ( new RegExp('name=["\']' + meta + '["\']', 'i').test(match) ) { - var content = match.toString().match(/content=("|')([^"']+)("|')/i); + while ( match = regex.exec(data['html']) ) { + for ( meta in w.apps[app].meta ) { + if ( new RegExp('name=["\']' + meta + '["\']', 'i').test(match) ) { + var content = match.toString().match(/content=("|')([^"']+)("|')/i); - if ( w.apps[app].meta[meta].test(content[2]) ) { - apps.push(app); + if ( w.apps[app].meta[meta].test(content[2]) ) { + apps.push(app); - break; - } + break; } } } + } - break; - case 'headers': - for ( var header in w.apps[app].headers ) { - if ( data[type][header] != null && w.apps[app].headers[header].test(data[type][header]) ) { - apps.push(app); + break; + case 'headers': + if ( data[type] == null ) break; - break; - } + for ( var header in w.apps[app].headers ) { + if ( data[type][header] != null && w.apps[app].headers[header].test(data[type][header]) ) { + apps.push(app); + + break; } + } - break; - case 'env': - for ( var i in data[type] ) { - if ( w.apps[app].env.test(data[type][i]) ) { - apps.push(app); + break; + case 'env': + if ( data[type] == null ) break; - break; - } + for ( var i in data[type] ) { + if ( w.apps[app].env.test(data[type][i]) ) { + apps.push(app); + + break; } + } - break; - } + break; } } } w.log(apps.length + ' apps detected: ' + apps.join(', ')); - w.cache[url] = { hits: 0, apps: apps }; + // Keep history of detected apps + apps.map(function(app) { + // Per hostname + var index = w.history.indexOf(app); - delete apps, data; - } else { - w.cache[url].hits ++; + if ( index === -1 ) { + w.history[hostname].push({ app: app, hits: 1 }); + } else { + w.history[hostname][index].hits ++; + } - w.log(w.cache[url].apps.length + ' apps cached (hit ' + w.cache[url].hits + '): ' + w.cache[url].apps.join(', ')); + // Per URL + var index = w.detected.indexOf(app); + + if ( index === -1 ) w.detected[url].push(app); + }); + + delete apps, data; } - adapter('displayApps', { apps: w.cache[url].apps }); + adapter('displayApps', { url: url, apps: w.detected[url] }); } };