diff --git a/.travis.yml b/.travis.yml index d78ea5d9f..d9239161a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: node_js node_js: - "node" sudo: false +dist: trusty before_install: - export WAPPALYZER_ROOT=$TRAVIS_BUILD_DIR - export WAPPALYZER_NODE_PATH=$TRAVIS_BUILD_DIR @@ -27,9 +28,3 @@ cache: - node_modules env: - CXX=g++-4.8 -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.8 diff --git a/src/apps.json b/src/apps.json index 4a58d9050..428cbbef7 100755 --- a/src/apps.json +++ b/src/apps.json @@ -510,7 +510,7 @@ "12" ], "env": "^angular$", - "icon": "AngularJS.png", + "icon": "AngularJS.svg", "script": [ "angular(?:\\-|\\.)([\\d.]*\\d)[^/]*\\.js\\;version:\\1", "/([\\d.]+(?:\\-?rc[.\\d]*)*)/angular(?:\\.min)?\\.js\\;version:\\1", @@ -1910,7 +1910,7 @@ "icon": "Dell.png", "website": "http://dell.com" }, - "Demandware": { + "Salesforce Commerce Cloud": { "cats": [ "6" ], @@ -1919,7 +1919,7 @@ "Server": "Demandware eCommerce Server" }, "html": "<[^>]+demandware\\.edgesuite", - "icon": "Demandware.png", + "icon": "Salesforce.svg", "website": "http://demandware.com" }, "Deployd": { @@ -2358,7 +2358,7 @@ ], "env": "^enyo$", "icon": "Enyo.png", - "script": "\benyo\\.js", + "script": "enyo\\.js", "website": "http://enyojs.com" }, "Epoch": { @@ -2516,6 +2516,16 @@ "script": "jquery\\.fancybox\\.pack\\.js(?:\\?v=([\\d.]+))?$\\;version:\\1", "website": "http://fancyapps.com/fancybox" }, + "Fastly": { + "cats": [ + "31" + ], + "headers": { + "Fastly-Debug-Digest": "" + }, + "icon": "Fastly.svg", + "website": "https://www.fastly.com" + }, "Fat-Free Framework": { "cats": [ "18" @@ -2699,9 +2709,11 @@ "cats": [ "24" ], + "html": "<[^>]+class=\"[^\"]*(?:fr-view|fr-box)", "icon": "Froala.svg", "implies": [ - "jQuery" + "jQuery", + "Font Awesome" ], "website": "http://froala.com/wysiwyg-editor" }, @@ -3066,6 +3078,17 @@ "script": "apis\\.google\\.com/js/[a-z]*\\.js", "website": "http://plus.google.com" }, + "Google Search Appliance": { + "cats": [ + "22", + "29" + ], + "headers": { + "Server": "^Google\\sSearch\\sAppliance$" + }, + "icon": "Google Search Appliance.png", + "website": "https://enterprise.google.com/search" + }, "Google Sites": { "cats": [ "1" @@ -3119,6 +3142,19 @@ }, "website": "http://developers.google.com/web-toolkit" }, + "govCMS": { + "cats": [ + "1" + ], + "meta": { + "generator": "Drupal ([\\d]+) \\(http:\\/\\/drupal\\.org\\) \\+ govCMS\\;version:\\1" + }, + "icon": "govCMS.svg", + "implies": [ + "Drupal" + ], + "website": "https://www.govcms.gov.au" + }, "Graffiti CMS": { "cats": [ "1" @@ -4286,6 +4322,16 @@ "icon": "LabVIEW.png", "website": "http://ni.com/labview" }, + "Shapecss": { + "cats":[ + "18" + ], + "env": "^Shapecss$", + "html":"]* href=\"[^\"]*shapecss(?:\\.min)?\\.css", + "script":"shapecss(?:\\.min)?\\.js", + "icon":"Shapecss.svg", + "website":"https://shapecss.com" + }, "Laravel": { "cats": [ "18" @@ -4342,6 +4388,17 @@ "implies": "Scala", "website": "http://liftweb.net" }, + "Play": { + "cats": [ + "18" + ], + "headers": { + "Set-Cookie": "PLAY_SESSION" + }, + "icon": "Play.svg", + "implies": "Scala", + "website": "https://www.playframework.com" + }, "LightMon Engine": { "cats": [ "1" @@ -5482,7 +5539,7 @@ "icon": "OWL Carousel.png", "implies": "jQuery", "script": "owl.carousel.*\\.js", - "website": "http://owlgraphic.com/owlcarousel" + "website": "https://owlcarousel2.github.io/OwlCarousel2/" }, "OXID eShop": { "cats": [ @@ -6547,6 +6604,17 @@ }, "website": "http://example.com" }, + "Raspbian": { + "cats": [ + "28" + ], + "headers": { + "Server": "Raspbian", + "X-Powered-By": "Raspbian" + }, + "icon": "Raspbian.svg", + "website": "https://www.raspbian.org/" + }, "React": { "cats": [ "12" @@ -7020,6 +7088,7 @@ ], "implies": "jQuery", "script": "select2.*\\.js", + "icon": "Select2.png", "website": "http://select2.github.io" }, "Semantic-ui": { @@ -7433,6 +7502,23 @@ "script": "^https?://api\\.solvemedia\\.com/", "website": "http://solvemedia.com" }, + "SonarQubes": { + "cats": [ + "47" + ], + "env": "^Sonar(?:Measures|Request)$", + "html": [ + "SonarQube" + ], + "script": "^/js/bundles/sonar\\.js?v=([\\d.]+)$\\;version:\\1", + "icon": "sonar.png", + "implies": "Java", + "meta": { + "application-name": "^SonarQubes$" + }, + "website": "https://www.sonarqube.org/" + }, "SoundManager": { "cats": [ "12" @@ -7594,6 +7680,16 @@ "icon": "Store Systems.png", "website": "http://store-systems.de" }, + "Storyblok": { + "cats": [ + "1" + ], + "icon": "storyblok.png", + "meta": { + "generator": "storyblok" + }, + "website": "https://www.storyblok.com" + }, "Strapdown.js": { "cats": [ "12" @@ -7696,6 +7792,15 @@ "script": "sweet-alert(?:\\.min)?\\.js", "website": "http://t4t5.github.io/sweetalert/" }, + "SweetAlert2": { + "cats": [ + "12" + ], + "html": "]+?href=\"[^\"]+sweetalert2(?:\\.min)?\\.css", + "icon": "SweetAlert2.png", + "script": "sweetalert2(?:\\.min)?\\.js", + "website": "https://limonte.github.io/sweetalert2" + }, "Swiftlet": { "cats": [ "18" @@ -8400,7 +8505,6 @@ "icon": "Vimeo.png", "website": "http://vimeo.com" }, - "Vinala": { "cats": [ "18" @@ -9996,6 +10100,15 @@ "icon": "swift.engine.png", "website": "http://mittec.ru/default" }, + "WEBXPAY": { + "cats": [ + "6" + ], + "env": "^WEBXPAY$", + "html": "Powered by WEBXPAY<", + "icon": "WEBXPAY.png", + "website": "https://webxpay.com" + }, "three.js": { "cats": [ "25" @@ -10157,6 +10270,14 @@ "icon": "xui.png", "script": "[^a-z]xui.*\\.js", "website": "http://xuijs.com" + }, + "Moon": { + "cats": [ + "12" + ], + "icon": "moon.png", + "script": "/moon(?:\\.min)?\\.js$", + "website": "http://moonjs.ga/" } }, "categories": { diff --git a/src/drivers/webextension/_locales/ru/messages.json b/src/drivers/webextension/_locales/ru/messages.json index 4f460991d..9b8842c76 100644 --- a/src/drivers/webextension/_locales/ru/messages.json +++ b/src/drivers/webextension/_locales/ru/messages.json @@ -4,6 +4,10 @@ "categoryName3" : { "message" : "Менеджер БД" }, "categoryName4" : { "message" : "Документация" }, "categoryName5" : { "message" : "Виджет" }, + "categoryName6" : { "message" : "Электронная коммерция" }, + "categoryName7" : { "message" : "Фотогалерея" }, + "categoryName8" : { "message" : "Вики" }, + "categoryName9" : { "message" : "Панель управления хостингом" }, "categoryName10" : { "message" : "Аналитика" }, "categoryName11" : { "message" : "Блог" }, "categoryName12" : { "message" : "JS фреймворк" }, @@ -35,7 +39,7 @@ "categoryName38" : { "message" : "Медиа сервер" }, "categoryName39" : { "message" : "Вебкамера" }, "categoryName40" : { "message" : "Принтер" }, - "categoryName41" : { "message" : "Провайдер платежей" }, + "categoryName41" : { "message" : "Платёжная система" }, "categoryName42" : { "message" : "Менеджер тэгов" }, "categoryName43" : { "message" : "Paywall" }, "categoryName44" : { "message" : "Система непрерывной интеграции" }, @@ -47,12 +51,13 @@ "categoryName50" : { "message" : "Управление документами" }, "categoryName51" : { "message": "Генератор лендингов" }, "categoryName52" : { "message": "Live Chat" }, - "categoryName53" : { "message": "CRM" }, + "categoryName53" : { "message": "CRM" }, "github" : { "message" : "Форкнуть на GitHub!" }, "noAppsDetected" : { "message" : "Нет данных о сайте" }, "nothingToDo" : { "message" : "Тут нечего искать" }, - "optionTracking" : { "message" : "Анонимно отправлять статистику распознанных данных на сервер (для улучшения расширения)" }, - "optionUpgradeMessage" : { "message" : "Оповещать меня о новых обновлениях" }, + "optionTracking" : { "message" : "Анонимно отправлять статистику распознанных данных на сервер (для исследований)" }, + "optionDynamicIcon" : { "message": "Использовать значок приложения вместо логотипа Wappalyzer" }, + "optionUpgradeMessage" : { "message" : "Оповещать меня об обновлениях" }, "options" : { "message" : "Настройки" }, "optionsSave" : { "message" : "Сохранить" }, "optionsSaved" : { "message" : "Успешно сохранено!" }, diff --git a/src/drivers/webextension/background.html b/src/drivers/webextension/background.html index 06e298abf..4c4160ac3 100644 --- a/src/drivers/webextension/background.html +++ b/src/drivers/webextension/background.html @@ -6,7 +6,6 @@ - diff --git a/src/drivers/webextension/js/content.js b/src/drivers/webextension/js/content.js index ac21ee724..f7bab8ecd 100644 --- a/src/drivers/webextension/js/content.js +++ b/src/drivers/webextension/js/content.js @@ -5,25 +5,25 @@ init: function() { var html = document.documentElement.outerHTML; - c.log('init'); + c.log('Function call: init()'); if ( html.length > 50000 ) { html = html.substring(0, 25000) + html.substring(html.length - 25000, html.length); } - browser.runtime.sendMessage({ id: 'analyze', subject: { html: html } }); + browser.runtime.sendMessage({ id: 'analyze', subject: { html: html }, source: 'content.js' }); c.getEnvironmentVars(); }, log: function(message) { - browser.runtime.sendMessage({ id: 'log', message: '[ content.js ] ' + message }); + browser.runtime.sendMessage({ id: 'log', message: message, source: 'content.js' }); }, getEnvironmentVars: function() { var container, script; - c.log('getEnvironmentVars'); + c.log('Function call: getEnvironmentVars()'); if ( typeof document.documentElement.innerHTML === 'undefined' ) { return; @@ -48,7 +48,7 @@ environmentVars = environmentVars.split(' ').slice(0, 500); - browser.runtime.sendMessage({ id: 'analyze', subject: { env: environmentVars } }); + browser.runtime.sendMessage({ id: 'analyze', subject: { env: environmentVars }, source: 'content.js' }); }), true); document.documentElement.appendChild(container); diff --git a/src/drivers/webextension/js/driver.js b/src/drivers/webextension/js/driver.js index 4dee2dd54..b6b1e1d2e 100644 --- a/src/drivers/webextension/js/driver.js +++ b/src/drivers/webextension/js/driver.js @@ -26,7 +26,7 @@ * Log messages to console */ log: function(args) { - console.log('[wappalyzer ' + args.type + '] ' + args.message); + console.log('[wappalyzer ' + args.type + ']', '[' + args.source + ']', JSON.parse(args.message)); }, /** @@ -53,7 +53,7 @@ * Initialize */ init: function() { - w.log('init'); + w.log('Function call: w.driver.init()', 'driver'); // Load apps.json var xhr = new XMLHttpRequest(); @@ -122,8 +122,6 @@ } browser.tabs.onRemoved.addListener(function(tabId) { - w.log('remove tab'); - tabCache[tabId] = null; }); @@ -153,8 +151,6 @@ } } } - - w.log(JSON.stringify({ uri: uri, headers: responseHeaders })); } }, { urls: [ 'http://*/*', 'https://*/*' ], types: [ 'main_frame' ] }, [ 'responseHeaders' ]); @@ -178,11 +174,13 @@ a = document.createElement('a'); if ( typeof message.id != 'undefined' ) { - w.log('message: ' + message.id); + if ( message.id !== 'log' ) { + w.log('Message received from ' + message.source + ': ' + message.id, 'driver'); + } switch ( message.id ) { case 'log': - w.log(message.message); + w.log(message.message, message.source); break; case 'analyze': @@ -295,8 +293,6 @@ if ( Object.keys(w.ping.hostnames).length && tracking ) { w.driver.post('http://ping.wappalyzer.com/v2/', w.ping); - w.log('w.driver.ping: ' + JSON.stringify(w.ping)); - w.ping = { hostnames: {} }; w.driver.post('https://ad.wappalyzer.com/log/wp/', w.adCache); @@ -318,7 +314,7 @@ xhr.onreadystatechange = function() { if ( xhr.readyState == 4 ) { - w.log('w.driver.post: status ' + xhr.status + ' (' + url + ')'); + w.log({ 'POST request': { url: url, status: xhr.status, data: data } }, 'driver'); } }; diff --git a/src/drivers/webextension/js/inject.js b/src/drivers/webextension/js/inject.js index 2369c2583..cc56a76c5 100644 --- a/src/drivers/webextension/js/inject.js +++ b/src/drivers/webextension/js/inject.js @@ -1,6 +1,6 @@ (function() { try { - var i, environmentVars, e = document.createEvent('Events'); + var i, environmentVars = '', e = document.createEvent('Events'); e.initEvent('wappalyzerEvent', true, false); diff --git a/src/drivers/webextension/js/popup.js b/src/drivers/webextension/js/popup.js index 70808bb53..eb760d34c 100644 --- a/src/drivers/webextension/js/popup.js +++ b/src/drivers/webextension/js/popup.js @@ -1,24 +1,17 @@ /** global: chrome */ /** global: browser */ -document.addEventListener('DOMContentLoaded', function() { - var - slugify, popup, - d = document, - detectedApps = d.getElementById('detected-apps'); - - slugify = function(string) { - return string.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/--+/g, '-').replace(/(?:^-|-$)/, ''); - }; - - popup = { +(function() { + var popup = { init: function() { var callback = function(tabs) { - if ( tabs[0].url.match(/https?:\/\//) ) { - detectedApps.innerHTML = '
' + browser.i18n.getMessage('noAppsDetected') + '
'; - } else { - detectedApps.innerHTML = '
' + browser.i18n.getMessage('nothingToDo') + '
'; - } + ( chrome || browser ).runtime.sendMessage({ id: 'get_apps', tab: tabs[0], source: 'popup.js' }, function(response) { + if ( /complete|interacrive|loaded/.test(document.readyState) ) { + popup.displayApps(response) + } else { + document.addEventListener('DOMContentLoaded', function() { popup.displayApps(response) }); + } + }); }; try { @@ -28,62 +21,56 @@ document.addEventListener('DOMContentLoaded', function() { // Edge browser.tabs.query({ active: true, currentWindow: true }, callback); } - - popup.displayApps(); }, - displayApps: function() { - var appName, confidence, version; + displayApps: function(response) { + var + appName, confidence, version, + detectedApps = document.querySelector('#detected-apps'); + html = ''; - var callback = function(tabs) { - function sendGetApps(response) { - var html; - - if ( response.tabCache && response.tabCache.count > 0 ) { - detectedApps.innerHTML = ''; + if ( response.tabCache && response.tabCache.count > 0 ) { + for ( appName in response.tabCache.appsDetected ) { + confidence = response.tabCache.appsDetected[appName].confidenceTotal; + version = response.tabCache.appsDetected[appName].version; - for ( appName in response.tabCache.appsDetected ) { - confidence = response.tabCache.appsDetected[appName].confidenceTotal; - version = response.tabCache.appsDetected[appName].version; + html += + '
' + + '' + + '' + + '' + + '' + appName + '' + + ( version ? ' ' + version : '' ) + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' ) + + '' + + ''; - html = - '
' + - '' + - '' + - '' + appName + '' + ( version ? ' ' + version : '' ) + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' ) + '' + - ''; + response.apps[appName].cats.forEach(function(cat) { + html += + '' + + '' + browser.i18n.getMessage('categoryName' + cat) + '' + + ''; + }); - response.apps[appName].cats.forEach(function(cat) { - html += - '' + - '' + browser.i18n.getMessage('categoryName' + cat) + '' + - ''; - }); + html += + '' + + '
'; + } + } else { + html = '
' + browser.i18n.getMessage('noAppsDetected') + '
'; + } - html += - '' + - '
'; + detectedApps.innerHTML = html; - detectedApps.innerHTML = detectedApps.innerHTML + html; - } - } - } - if (typeof chrome === "undefined") { - browser.runtime.sendMessage({ id: 'get_apps', tab: tabs[0] }, sendGetApps); - } else { - chrome.runtime.sendMessage({ id: 'get_apps', tab: tabs[0] }, sendGetApps); - } - }; + // Force redraw after popup animation on Mac OS + setTimeout(function() { + document.body.innerHTML += ' '; + }, 600); + }, - try { - // Chrome, Firefox - browser.tabs.query({ active: true, currentWindow: true }).then(callback); - } catch ( e ) { - // Edge - browser.tabs.query({ active: true, currentWindow: true }, callback); - } + slugify: function(string) { + return string.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/--+/g, '-').replace(/(?:^-|-$)/, ''); } }; popup.init(); -}); +}()); diff --git a/src/drivers/webextension/popup.html b/src/drivers/webextension/popup.html index 1548d426e..afa6e0976 100644 --- a/src/drivers/webextension/popup.html +++ b/src/drivers/webextension/popup.html @@ -4,7 +4,6 @@ - diff --git a/src/icons/AngularJS.png b/src/icons/AngularJS.png deleted file mode 100644 index 6dc0783e1..000000000 Binary files a/src/icons/AngularJS.png and /dev/null differ diff --git a/src/icons/AngularJS.svg b/src/icons/AngularJS.svg new file mode 100644 index 000000000..649c9f92f --- /dev/null +++ b/src/icons/AngularJS.svg @@ -0,0 +1,74 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/src/icons/Demandware.png b/src/icons/Demandware.png deleted file mode 100644 index c2ef8d545..000000000 Binary files a/src/icons/Demandware.png and /dev/null differ diff --git a/src/icons/Fastly.svg b/src/icons/Fastly.svg new file mode 100644 index 000000000..05ae7d05d --- /dev/null +++ b/src/icons/Fastly.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/src/icons/Google Search Appliance.png b/src/icons/Google Search Appliance.png new file mode 100644 index 000000000..2e1f97ece Binary files /dev/null and b/src/icons/Google Search Appliance.png differ diff --git a/src/icons/PHP.svg b/src/icons/PHP.svg index 3c8553621..e5799b153 100644 --- a/src/icons/PHP.svg +++ b/src/icons/PHP.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/icons/Play.svg b/src/icons/Play.svg new file mode 100644 index 000000000..10925d767 --- /dev/null +++ b/src/icons/Play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/Raspbian.svg b/src/icons/Raspbian.svg new file mode 100644 index 000000000..2131cf097 --- /dev/null +++ b/src/icons/Raspbian.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/icons/Select2.png b/src/icons/Select2.png index 850ac1368..fc1f269f7 100644 Binary files a/src/icons/Select2.png and b/src/icons/Select2.png differ diff --git a/src/icons/Shapecss.svg b/src/icons/Shapecss.svg new file mode 100644 index 000000000..8d577bec6 --- /dev/null +++ b/src/icons/Shapecss.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + diff --git a/src/icons/SweetAlert2.png b/src/icons/SweetAlert2.png new file mode 100644 index 000000000..1d7edfcf1 Binary files /dev/null and b/src/icons/SweetAlert2.png differ diff --git a/src/icons/WEBXPAY.png b/src/icons/WEBXPAY.png new file mode 100644 index 000000000..425391d63 Binary files /dev/null and b/src/icons/WEBXPAY.png differ diff --git a/src/icons/govCMS.svg b/src/icons/govCMS.svg new file mode 100644 index 000000000..6b1f767c6 --- /dev/null +++ b/src/icons/govCMS.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/moon.png b/src/icons/moon.png new file mode 100644 index 000000000..2fdae7cc3 Binary files /dev/null and b/src/icons/moon.png differ diff --git a/src/icons/sonar.png b/src/icons/sonar.png new file mode 100644 index 000000000..cd565b061 Binary files /dev/null and b/src/icons/sonar.png differ diff --git a/src/icons/storyblok.png b/src/icons/storyblok.png new file mode 100644 index 000000000..daf5882d1 Binary files /dev/null and b/src/icons/storyblok.png differ diff --git a/src/wappalyzer.js b/src/wappalyzer.js index 1ec8a4850..aa7b2f03e 100644 --- a/src/wappalyzer.js +++ b/src/wappalyzer.js @@ -14,12 +14,12 @@ var wappalyzer = (function() { */ var Application = function(app, detected) { this.app = app; - this.confidence = {}; + this.confidence = { }; this.confidenceTotal = 0; this.detected = Boolean(detected); - this.excludes = []; + this.excludes = [ ]; this.version = ''; - this.versions = []; + this.versions = [ ]; }; Application.prototype = { @@ -27,7 +27,9 @@ var wappalyzer = (function() { * Calculate confidence total */ getConfidence: function() { - var total = 0, id; + var + id, + total = 0; for ( id in this.confidence ) { total += this.confidence[id]; @@ -67,7 +69,7 @@ var wappalyzer = (function() { this.detected = true; // Set confidence level - this.confidence[type + ' ' + ( key ? key + ' ' : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + this.confidence[type + ' ' + ( key ? key + ' ' : '' ) + pattern.regex] = pattern.confidence || 100; // Detect version number if ( pattern.version ) { @@ -81,15 +83,11 @@ var wappalyzer = (function() { var ternary = new RegExp('\\\\' + i + '\\?([^:]+):(.*)$').exec(version); if ( ternary && ternary.length === 3 ) { - w.log({ match: match, i: i, ternary: ternary }); - version = version.replace(ternary[0], match ? ternary[1] : ternary[2]); - - w.log({ version: version }); } // Replace back references - version = version.replace(new RegExp('\\\\' + i, 'g'), match ? match : ''); + version = version.replace(new RegExp('\\\\' + i, 'g'), match || ''); }); if ( version && this.versions.indexOf(version) < 0 ) { @@ -102,20 +100,20 @@ var wappalyzer = (function() { } }; + var asArray = function(value) { + return typeof value === 'string' ? [ value ] : value; + }; + /** * Call driver functions */ var driver = function(func, args) { if ( typeof w.driver[func] !== 'function' ) { - w.log('not implemented: w.driver.' + func, 'warn'); + w.log('not implemented: w.driver.' + func, 'core', 'warn'); return; } - if ( func !== 'log' ) { - w.log('w.driver.' + func); - } - return w.driver[func](args); }; @@ -127,25 +125,17 @@ var wappalyzer = (function() { key, parsed = {}; - // Convert array to object containing array - if ( patterns instanceof Array ) { - patterns = { main: patterns } - } - // Convert string to object containing array containing string - if ( typeof patterns === 'string' ) { - patterns = { main: [ patterns ] }; + if ( typeof patterns === 'string' || patterns instanceof Array ) { + patterns = { + main: asArray(patterns) + }; } for ( key in patterns ) { parsed[key] = []; - // Convert string to array containing string - if ( typeof patterns[key] === 'string' ) { - patterns[key] = [ patterns[key] ]; - } - - patterns[key].forEach(function(pattern) { + asArray(patterns[key]).forEach(function(pattern) { var attrs = {}; pattern.split('\\;').forEach(function(attr, i) { @@ -164,7 +154,7 @@ var wappalyzer = (function() { } catch (e) { attrs.regex = new RegExp(); - w.log(e + ': ' + attr, 'error'); + w.log(e + ': ' + attr, 'error', 'core'); } } }); @@ -185,48 +175,48 @@ var wappalyzer = (function() { * Main script */ var w = { - apps: {}, - cats: null, - ping: { hostnames: {} }, - adCache: [], + apps: {}, + cats: null, + ping: { + hostnames: { } + }, + adCache: [], detected: {}, config: { websiteURL: 'https://wappalyzer.com/', twitterURL: 'https://twitter.com/Wappalyzer', - githubURL: 'https://github.com/AliasIO/Wappalyzer', + githubURL: 'https://github.com/AliasIO/Wappalyzer', + }, + + validation: { + hostname: /(www.)?((.+?)\.(([a-z]{2,3}\.)?[a-z]{2,6}))$/, + hostnameBlacklist: /((local|dev(elopment)?|stag(e|ing)?|test(ing)?|demo(shop)?|admin|google|cache)\.|\/admin|\.local)/ }, /** * Log messages to console */ - log: function(message, type) { - if ( type === undefined ) { - type = 'debug'; - } - - if ( typeof message === 'object' ) { - message = JSON.stringify(message); - } - - driver('log', { message: message, type: type }); + log: function(message, source, type) { + driver('log', { + source: source || '', + message: JSON.stringify(message), + type: type || 'debug' + }); }, /** * Initialize */ init: function() { - w.log('w.init'); - - // Checks - if ( w.driver === undefined ) { - w.log('no driver, exiting'); - - return; - } + w.log('Function call: w.init()', 'core'); // Initialize driver - driver('init'); + if ( w.driver !== undefined ) { + driver('init'); + } else { + w.log('No driver, exiting', 'core'); + } }, /** @@ -237,10 +227,10 @@ var wappalyzer = (function() { app, apps = {}; - w.log('w.analyze'); + w.log('Function call: w.analyze()', 'core'); if ( w.apps === undefined || w.categories === undefined ) { - w.log('apps.json not loaded, check for syntax errors'); + w.log('apps.json not loaded, check for syntax errors', 'core'); return; } @@ -290,7 +280,9 @@ var wappalyzer = (function() { w.cacheDetectedApps(apps, url); w.trackDetectedApps(apps, url, hostname, data.html); - w.log(Object.keys(apps).length + ' apps detected: ' + Object.keys(apps).join(', ') + ' on ' + url); + if ( Object.keys(apps).length ) { + w.log(Object.keys(apps).length + ' apps detected: ' + Object.keys(apps).join(', ') + ' on ' + url, 'core'); + } driver('displayApps'); }, @@ -303,11 +295,7 @@ var wappalyzer = (function() { // Exclude app in detected apps only for ( app in apps ) { if ( w.apps[app].excludes ) { - if ( typeof w.apps[app].excludes === 'string' ) { - w.apps[app].excludes = [ w.apps[app].excludes ]; - } - - w.apps[app].excludes.forEach(function(excluded) { + asArray(w.apps[app].excludes).forEach(function(excluded) { excludes.push(excluded); }); } @@ -336,16 +324,11 @@ var wappalyzer = (function() { confidence = apps[app].confidence; if ( w.apps[app] && w.apps[app].implies ) { - // Cast strings to an array - if ( typeof w.apps[app].implies === 'string' ) { - w.apps[app].implies = [ w.apps[app].implies ]; - } - - w.apps[app].implies.forEach(function(implied) { + asArray(w.apps[app].implies).forEach(function(implied) { implied = parsePatterns(implied)[0]; if ( !w.apps[implied.string] ) { - w.log('Implied application ' + implied.string + ' does not exist', 'warn'); + w.log('Implied application ' + implied.string + ' does not exist', 'core', 'warn'); return; } @@ -391,28 +374,24 @@ var wappalyzer = (function() { var app, match; for ( app in apps ) { - if ( w.detected[url][app].getConfidence() >= 100 ) { - if ( /(www.)?((.+?)\.(([a-z]{2,3}\.)?[a-z]{2,6}))$/.test(hostname) && !/((local|dev(elopment)?|stag(e|ing)?|test(ing)?|demo(shop)?|admin|google|cache)\.|\/admin|\.local)/.test(url) ) { - if ( !w.ping.hostnames.hasOwnProperty(hostname) ) { - w.ping.hostnames[hostname] = { - applications: {}, - meta: {} - }; - } + if ( w.detected[url][app].getConfidence() >= 100 && w.validation.hostname.test(hostname) && !w.validation.hostnameBlacklist.test(url) ) { + if ( !w.ping.hostnames.hasOwnProperty(hostname) ) { + w.ping.hostnames[hostname] = { + applications: {}, + meta: {} + }; + } - if ( !w.ping.hostnames[hostname].applications.hasOwnProperty(app) ) { - w.ping.hostnames[hostname].applications[app] = { - hits: 0 - }; - } + if ( !w.ping.hostnames[hostname].applications.hasOwnProperty(app) ) { + w.ping.hostnames[hostname].applications[app] = { + hits: 0 + }; + } - w.ping.hostnames[hostname].applications[app].hits ++; + w.ping.hostnames[hostname].applications[app].hits ++; - if ( apps[app].version ) { - w.ping.hostnames[hostname].applications[app].version = apps[app].version; - } - } else { - w.log('Ignoring hostname "' + hostname + '"'); + if ( apps[app].version ) { + w.ping.hostnames[hostname].applications[app].version = apps[app].version; } } } @@ -516,7 +495,7 @@ var wappalyzer = (function() { header, patterns = parsePatterns(w.apps[app.app].headers); - if ( patterns.length && headers ) { + if ( headers ) { for ( header in patterns ) { patterns[header].forEach(function(pattern) { header = header.toLowerCase();