diff --git a/src/apps.json b/src/apps.json index 993bd8618..dffea9b8f 100755 --- a/src/apps.json +++ b/src/apps.json @@ -1673,7 +1673,7 @@ "X-Powered-By": "CppCMS/([\\d.]+)\\;version:\\1" }, "icon": "CppCMS.png", - "implies": "C++", + "implies": "C\\+\\+", "website": "http://cppcms.com" }, "Craft CMS": { @@ -10373,4 +10373,4 @@ "priority": "9" } } -} \ No newline at end of file +} diff --git a/src/wappalyzer.js b/src/wappalyzer.js index 3b90c23c5..3d8d2eaca 100644 --- a/src/wappalyzer.js +++ b/src/wappalyzer.js @@ -234,10 +234,8 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - confirmMatch, confidence, id, match, patterns, type, version, - apps = {}, - excludes = [], - checkImplies = true; + app, confirmMatch, type, + apps = {}; w.log('w.analyze'); @@ -262,12 +260,6 @@ var wappalyzer = (function() { apps[app] = w.detected[url] && w.detected[url][app] ? w.detected[url][app] : new Application(app); for ( type in w.apps[app] ) { - patterns = parsePatterns(w.apps[app][type]); - - if ( !patterns ) { - continue; - } - confirmMatch = function(pattern, value, key) { apps[app].setDetected(pattern, type, value, key); } @@ -275,37 +267,37 @@ var wappalyzer = (function() { switch ( type ) { case 'url': if ( url ) { - w.analyzeUrl(patterns, url, confirmMatch); + w.analyzeUrl(parsePatterns(w.apps[app][type]), url, confirmMatch); } break; case 'html': if ( data.html ) { - w.analyzeHtml(patterns, data.html, confirmMatch); + w.analyzeHtml(parsePatterns(w.apps[app][type]), data.html, confirmMatch); } break; case 'script': if ( data.html ) { - w.analyzeScript(patterns, data.html, confirmMatch); + w.analyzeScript(parsePatterns(w.apps[app][type]), data.html, confirmMatch); } break; case 'meta': if ( data.html ) { - w.analyzeMeta(patterns, data.html, confirmMatch); + w.analyzeMeta(parsePatterns(w.apps[app][type]), data.html, confirmMatch); } break; case 'headers': if ( data.hasOwnProperty('headers') && data.headers ) { - w.analyzeHeaders(patterns, data.headers, confirmMatch); + w.analyzeHeaders(parsePatterns(w.apps[app][type]), data.headers, confirmMatch); } break; case 'env': if ( data.hasOwnProperty('env') && data.env ) { - w.analyzeEnv(patterns, data.env, confirmMatch); + w.analyzeEnv(parsePatterns(w.apps[app][type]), data.env, confirmMatch); } break; @@ -320,9 +312,25 @@ var wappalyzer = (function() { } } + w.resolveExcludes(apps); + w.resolveImplies(apps, url); + + 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); + + driver('displayApps'); + }, + + resolveExcludes: function(apps) { + var + app, + excludes = []; + // Exclude app in detected apps only for ( app in apps ) { - if (w.apps[app].excludes ) { + if ( w.apps[app].excludes ) { if ( typeof w.apps[app].excludes === 'string' ) { w.apps[app].excludes = [ w.apps[app].excludes ]; } @@ -339,6 +347,10 @@ var wappalyzer = (function() { delete apps[app]; } } + }, + + resolveImplies: function(apps, url) { + var checkImplies = true; // Implied applications // Run several passes as implied apps may imply other apps @@ -377,23 +389,34 @@ var wappalyzer = (function() { } } } + }, - w.log(Object.keys(apps).length + ' apps detected: ' + Object.keys(apps).join(', ') + ' on ' + url); + /** + * Cache detected applications + */ + cacheDetectedApps: function(apps, url) { + var app, key, confidence; - // Keep history of detected apps for ( app in apps ) { confidence = apps[app].confidence; - version = apps[app].version; // Per URL w.detected[url][app] = apps[app]; - for ( id in confidence ) { - w.detected[url][app].confidence[id] = confidence[id]; + for ( key in confidence ) { + w.detected[url][app].confidence[key] = confidence[key]; } + } + }, + /** + * Track detected applications + */ + trackDetectedApps: function(apps, url, hostname, html) { + var app, match; + + for ( app in apps ) { if ( w.detected[url][app].getConfidence() >= 100 ) { - // Per hostname 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] = { @@ -410,8 +433,8 @@ var wappalyzer = (function() { w.ping.hostnames[hostname].applications[app].hits ++; - if ( version ) { - w.ping.hostnames[hostname].applications[app].version = version; + if ( apps[app].version ) { + w.ping.hostnames[hostname].applications[app].version = apps[app].version; } } else { w.log('Ignoring hostname "' + hostname + '"'); @@ -421,20 +444,16 @@ var wappalyzer = (function() { // Additional information if ( w.ping.hostnames.hasOwnProperty(hostname) ) { - if ( typeof data.html === 'string' && data.html ) { - match = data.html.match(/]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i); + match = html.match(/]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i); - if ( match && match.length ) { - w.ping.hostnames[hostname].meta['language'] = match[1]; - } + if ( match && match.length ) { + w.ping.hostnames[hostname].meta['language'] = match[1]; } } if ( Object.keys(w.ping.hostnames).length >= 50 || w.adCache.length >= 50 ) { driver('ping'); } - - driver('displayApps'); }, /** @@ -481,7 +500,7 @@ var wappalyzer = (function() { */ analyzeMeta: function(patterns, html, confirmMatch) { var - content, meta, + content, match, meta, regex = /]+>/ig; while ( match = regex.exec(html) ) {