diff --git a/drivers/bookmarklet/images/icons/G-WAN.png b/drivers/bookmarklet/images/icons/G-WAN.png new file mode 100644 index 000000000..21997a742 Binary files /dev/null and b/drivers/bookmarklet/images/icons/G-WAN.png differ diff --git a/drivers/bookmarklet/images/icons/Hogan.js.png b/drivers/bookmarklet/images/icons/Hogan.js.png new file mode 100644 index 000000000..7f74461f2 Binary files /dev/null and b/drivers/bookmarklet/images/icons/Hogan.js.png differ diff --git a/drivers/bookmarklet/images/icons/WebsPlanet.png b/drivers/bookmarklet/images/icons/WebsPlanet.png new file mode 100644 index 000000000..cee2e67d1 Binary files /dev/null and b/drivers/bookmarklet/images/icons/WebsPlanet.png differ diff --git a/drivers/bookmarklet/js/wappalyzer.js b/drivers/bookmarklet/js/wappalyzer.js index 44c7cf0ff..bcc79ff08 100644 --- a/drivers/bookmarklet/js/wappalyzer.js +++ b/drivers/bookmarklet/js/wappalyzer.js @@ -12,38 +12,82 @@ var wappalyzer = (function() { /** * Application class */ - var Application = function(detected) { - this.confidence = {}; - this.confidenceTotal = 0; - this.detected = Boolean(detected); - this.versions = []; + var Application = function(app, detected) { + var self = this; + + self.app = app; + self.confidence = {}; + self.confidenceTotal = 0; + self.detected = Boolean(detected); + self.version = ''; + self.versions = []; /** * Calculate confidence total */ - this.getConfidence = function() { + self.getConfidence = function() { var total = 0; - for ( id in this.confidence ) { - total += this.confidence[id]; + for ( id in self.confidence ) { + total += self.confidence[id]; } - return this.confidenceTotal = Math.min(total, 100); + return self.confidenceTotal = Math.min(total, 100); } /** - * Resolve version number + * Resolve version number (find the longest version number that contains all shorter detected version numbers) */ - this.getVersion = function() { - return null; + self.getVersion = function() { + var next, resolved; + + if ( !self.versions.length ) { + return; + } + + self.versions.sort(function(a, b) { + return a.length > b.length ? 1 : ( a.length < b.length ? -1 : 0 ); + }); + + resolved = self.versions[0]; + + for ( i in self.versions ) { + next = parseInt(i) + 1; + + if ( next < self.versions.length ) { + if ( self.versions[next].indexOf(self.versions[i]) !== -1 ) { + resolved = self.versions[next]; + } else { + break; + } + } + } + + return self.version = resolved; } - this.setDetected = function(pattern, type, key) { - this.detected = true; + self.setDetected = function(pattern, type, value, key) { + self.detected = true; - this.confidence[type + ' ' + ( key ? ' ' + key : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Set confidence level + self.confidence[type + ' ' + ( key ? key + ' ' : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Detect version number if ( pattern.version ) { + var + version = pattern.version, + matches = pattern.regex.exec(value) + ; + + if ( matches ) { + matches.map(function(match, i) { + version = version.replace('\\' + i, match); + }); + + self.versions.push(version); + + self.getVersion(); + } } } } @@ -132,7 +176,13 @@ var wappalyzer = (function() { */ log: function(message, type) { if ( w.config.environment === 'dev' ) { - if ( typeof type === 'undefined' ) { type = 'debug'; } + if ( typeof type === 'undefined' ) { + type = 'debug'; + } + + if ( typeof message === 'object' ) { + message = JSON.stringify(message); + } driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type }); } @@ -172,7 +222,7 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, j, app, type, regexMeta, regexScript, match, content, meta, header, + i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version, profiler = { regexCount: 0, startTime: new Date().getTime() @@ -195,7 +245,7 @@ var wappalyzer = (function() { } for ( app in w.apps ) { - apps[app] = new Application(); + apps[app] = new Application(app); for ( type in w.apps[app] ) { switch ( type ) { @@ -204,7 +254,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(url) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, url); } }); @@ -218,7 +268,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } }); @@ -237,7 +287,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(match[2]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } } }); @@ -263,7 +313,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { - apps[app].setDetected(pattern, type, meta); + apps[app].setDetected(pattern, type, content[2], meta); } }); } @@ -281,7 +331,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { - apps[app].setDetected(pattern, type, header); + apps[app].setDetected(pattern, type, data[type][header], header); } }); } @@ -297,7 +347,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type][i]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type][i]); } } }); @@ -331,7 +381,7 @@ var wappalyzer = (function() { // Apply app confidence to implied app if ( !apps.hasOwnProperty(implied) ) { - apps[implied] = new Application(true); + apps[implied] = new Application(implied, true); } for ( id in confidence ) { @@ -349,9 +399,7 @@ var wappalyzer = (function() { confidence = apps[app].confidence; // Per URL - if ( !w.detected[url].hasOwnProperty(app)) { - w.detected[url][app] = new Application(); - } + w.detected[url][app] = apps[app]; for ( id in confidence ) { w.detected[url][app].confidence[id] = confidence[id]; diff --git a/drivers/bookmarklet/json b/drivers/bookmarklet/json index cfb6a7c6e..1b4374c5c 100644 --- a/drivers/bookmarklet/json +++ b/drivers/bookmarklet/json @@ -725,6 +725,10 @@ "html": "gravityInsightsParams\\.site_guid = '", "env": "^GravityInsights$" }, + "G-WAN": { + "cats": [ 22 ], + "headers": { "Server": "G-WAN" } + }, "GX WebManager": { "cats": [ 1 ], "meta": { "generator": "GX WebManager" } @@ -742,6 +746,10 @@ "script": "highcharts.*\\.js", "env": "^Highcharts$" }, + "Hogan.js": { + "cats": [ 12 ], + "env": "^Hogan$" + }, "Hotaru CMS": { "cats": [ 1 ], "meta": { "generator": "Hotaru CMS" } @@ -1886,6 +1894,10 @@ "meta": { "generator": "WebsiteBaker" }, "implies": [ "PHP" ] }, + "WebsPlanet": { + "cats": [ 1 ], + "meta": { "generator": "WebsPlanet" } + }, "Webtrekk": { "cats": [ 10 ], "html": "var webtrekk = new Object" diff --git a/drivers/chrome/apps.json b/drivers/chrome/apps.json index cfb6a7c6e..1b4374c5c 100644 --- a/drivers/chrome/apps.json +++ b/drivers/chrome/apps.json @@ -725,6 +725,10 @@ "html": "gravityInsightsParams\\.site_guid = '", "env": "^GravityInsights$" }, + "G-WAN": { + "cats": [ 22 ], + "headers": { "Server": "G-WAN" } + }, "GX WebManager": { "cats": [ 1 ], "meta": { "generator": "GX WebManager" } @@ -742,6 +746,10 @@ "script": "highcharts.*\\.js", "env": "^Highcharts$" }, + "Hogan.js": { + "cats": [ 12 ], + "env": "^Hogan$" + }, "Hotaru CMS": { "cats": [ 1 ], "meta": { "generator": "Hotaru CMS" } @@ -1886,6 +1894,10 @@ "meta": { "generator": "WebsiteBaker" }, "implies": [ "PHP" ] }, + "WebsPlanet": { + "cats": [ 1 ], + "meta": { "generator": "WebsPlanet" } + }, "Webtrekk": { "cats": [ 10 ], "html": "var webtrekk = new Object" diff --git a/drivers/chrome/images/icons/G-WAN.png b/drivers/chrome/images/icons/G-WAN.png new file mode 100644 index 000000000..21997a742 Binary files /dev/null and b/drivers/chrome/images/icons/G-WAN.png differ diff --git a/drivers/chrome/images/icons/Hogan.js.png b/drivers/chrome/images/icons/Hogan.js.png new file mode 100644 index 000000000..7f74461f2 Binary files /dev/null and b/drivers/chrome/images/icons/Hogan.js.png differ diff --git a/drivers/chrome/images/icons/WebsPlanet.png b/drivers/chrome/images/icons/WebsPlanet.png new file mode 100644 index 000000000..cee2e67d1 Binary files /dev/null and b/drivers/chrome/images/icons/WebsPlanet.png differ diff --git a/drivers/chrome/js/popup.js b/drivers/chrome/js/popup.js index fd1b154bf..10b2a7e0f 100644 --- a/drivers/chrome/js/popup.js +++ b/drivers/chrome/js/popup.js @@ -42,7 +42,7 @@ document.addEventListener('DOMContentLoaded', function() { }, displayApps: function() { - var appName, confidence; + var appName, confidence, version; chrome.tabs.getSelected(null, function(tab) { chrome.extension.sendRequest({ id: 'get_apps', tab: tab }, function(response) { @@ -59,12 +59,13 @@ document.addEventListener('DOMContentLoaded', function() { for ( appName in response.tabCache.appsDetected ) { confidence = response.tabCache.appsDetected[appName].confidenceTotal; + version = response.tabCache.appsDetected[appName].version; html = '
' + '' + '' + - '' + appName + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' ) + '' + + '' + appName + ( version ? ' ' + version : '' ) + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' ) + '' + ''; response.apps[appName].cats.map(function(cat) { diff --git a/drivers/chrome/js/wappalyzer.js b/drivers/chrome/js/wappalyzer.js index 44c7cf0ff..bcc79ff08 100644 --- a/drivers/chrome/js/wappalyzer.js +++ b/drivers/chrome/js/wappalyzer.js @@ -12,38 +12,82 @@ var wappalyzer = (function() { /** * Application class */ - var Application = function(detected) { - this.confidence = {}; - this.confidenceTotal = 0; - this.detected = Boolean(detected); - this.versions = []; + var Application = function(app, detected) { + var self = this; + + self.app = app; + self.confidence = {}; + self.confidenceTotal = 0; + self.detected = Boolean(detected); + self.version = ''; + self.versions = []; /** * Calculate confidence total */ - this.getConfidence = function() { + self.getConfidence = function() { var total = 0; - for ( id in this.confidence ) { - total += this.confidence[id]; + for ( id in self.confidence ) { + total += self.confidence[id]; } - return this.confidenceTotal = Math.min(total, 100); + return self.confidenceTotal = Math.min(total, 100); } /** - * Resolve version number + * Resolve version number (find the longest version number that contains all shorter detected version numbers) */ - this.getVersion = function() { - return null; + self.getVersion = function() { + var next, resolved; + + if ( !self.versions.length ) { + return; + } + + self.versions.sort(function(a, b) { + return a.length > b.length ? 1 : ( a.length < b.length ? -1 : 0 ); + }); + + resolved = self.versions[0]; + + for ( i in self.versions ) { + next = parseInt(i) + 1; + + if ( next < self.versions.length ) { + if ( self.versions[next].indexOf(self.versions[i]) !== -1 ) { + resolved = self.versions[next]; + } else { + break; + } + } + } + + return self.version = resolved; } - this.setDetected = function(pattern, type, key) { - this.detected = true; + self.setDetected = function(pattern, type, value, key) { + self.detected = true; - this.confidence[type + ' ' + ( key ? ' ' + key : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Set confidence level + self.confidence[type + ' ' + ( key ? key + ' ' : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Detect version number if ( pattern.version ) { + var + version = pattern.version, + matches = pattern.regex.exec(value) + ; + + if ( matches ) { + matches.map(function(match, i) { + version = version.replace('\\' + i, match); + }); + + self.versions.push(version); + + self.getVersion(); + } } } } @@ -132,7 +176,13 @@ var wappalyzer = (function() { */ log: function(message, type) { if ( w.config.environment === 'dev' ) { - if ( typeof type === 'undefined' ) { type = 'debug'; } + if ( typeof type === 'undefined' ) { + type = 'debug'; + } + + if ( typeof message === 'object' ) { + message = JSON.stringify(message); + } driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type }); } @@ -172,7 +222,7 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, j, app, type, regexMeta, regexScript, match, content, meta, header, + i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version, profiler = { regexCount: 0, startTime: new Date().getTime() @@ -195,7 +245,7 @@ var wappalyzer = (function() { } for ( app in w.apps ) { - apps[app] = new Application(); + apps[app] = new Application(app); for ( type in w.apps[app] ) { switch ( type ) { @@ -204,7 +254,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(url) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, url); } }); @@ -218,7 +268,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } }); @@ -237,7 +287,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(match[2]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } } }); @@ -263,7 +313,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { - apps[app].setDetected(pattern, type, meta); + apps[app].setDetected(pattern, type, content[2], meta); } }); } @@ -281,7 +331,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { - apps[app].setDetected(pattern, type, header); + apps[app].setDetected(pattern, type, data[type][header], header); } }); } @@ -297,7 +347,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type][i]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type][i]); } } }); @@ -331,7 +381,7 @@ var wappalyzer = (function() { // Apply app confidence to implied app if ( !apps.hasOwnProperty(implied) ) { - apps[implied] = new Application(true); + apps[implied] = new Application(implied, true); } for ( id in confidence ) { @@ -349,9 +399,7 @@ var wappalyzer = (function() { confidence = apps[app].confidence; // Per URL - if ( !w.detected[url].hasOwnProperty(app)) { - w.detected[url][app] = new Application(); - } + w.detected[url][app] = apps[app]; for ( id in confidence ) { w.detected[url][app].confidence[id] = confidence[id]; diff --git a/drivers/firefox-jetpack/data/apps.json b/drivers/firefox-jetpack/data/apps.json index cfb6a7c6e..1b4374c5c 100644 --- a/drivers/firefox-jetpack/data/apps.json +++ b/drivers/firefox-jetpack/data/apps.json @@ -725,6 +725,10 @@ "html": "gravityInsightsParams\\.site_guid = '", "env": "^GravityInsights$" }, + "G-WAN": { + "cats": [ 22 ], + "headers": { "Server": "G-WAN" } + }, "GX WebManager": { "cats": [ 1 ], "meta": { "generator": "GX WebManager" } @@ -742,6 +746,10 @@ "script": "highcharts.*\\.js", "env": "^Highcharts$" }, + "Hogan.js": { + "cats": [ 12 ], + "env": "^Hogan$" + }, "Hotaru CMS": { "cats": [ 1 ], "meta": { "generator": "Hotaru CMS" } @@ -1886,6 +1894,10 @@ "meta": { "generator": "WebsiteBaker" }, "implies": [ "PHP" ] }, + "WebsPlanet": { + "cats": [ 1 ], + "meta": { "generator": "WebsPlanet" } + }, "Webtrekk": { "cats": [ 10 ], "html": "var webtrekk = new Object" diff --git a/drivers/firefox-jetpack/images/icons/G-WAN.png b/drivers/firefox-jetpack/images/icons/G-WAN.png new file mode 100644 index 000000000..21997a742 Binary files /dev/null and b/drivers/firefox-jetpack/images/icons/G-WAN.png differ diff --git a/drivers/firefox-jetpack/images/icons/Hogan.js.png b/drivers/firefox-jetpack/images/icons/Hogan.js.png new file mode 100644 index 000000000..7f74461f2 Binary files /dev/null and b/drivers/firefox-jetpack/images/icons/Hogan.js.png differ diff --git a/drivers/firefox-jetpack/images/icons/WebsPlanet.png b/drivers/firefox-jetpack/images/icons/WebsPlanet.png new file mode 100644 index 000000000..cee2e67d1 Binary files /dev/null and b/drivers/firefox-jetpack/images/icons/WebsPlanet.png differ diff --git a/drivers/firefox-jetpack/lib/wappalyzer.js b/drivers/firefox-jetpack/lib/wappalyzer.js index 44c7cf0ff..bcc79ff08 100644 --- a/drivers/firefox-jetpack/lib/wappalyzer.js +++ b/drivers/firefox-jetpack/lib/wappalyzer.js @@ -12,38 +12,82 @@ var wappalyzer = (function() { /** * Application class */ - var Application = function(detected) { - this.confidence = {}; - this.confidenceTotal = 0; - this.detected = Boolean(detected); - this.versions = []; + var Application = function(app, detected) { + var self = this; + + self.app = app; + self.confidence = {}; + self.confidenceTotal = 0; + self.detected = Boolean(detected); + self.version = ''; + self.versions = []; /** * Calculate confidence total */ - this.getConfidence = function() { + self.getConfidence = function() { var total = 0; - for ( id in this.confidence ) { - total += this.confidence[id]; + for ( id in self.confidence ) { + total += self.confidence[id]; } - return this.confidenceTotal = Math.min(total, 100); + return self.confidenceTotal = Math.min(total, 100); } /** - * Resolve version number + * Resolve version number (find the longest version number that contains all shorter detected version numbers) */ - this.getVersion = function() { - return null; + self.getVersion = function() { + var next, resolved; + + if ( !self.versions.length ) { + return; + } + + self.versions.sort(function(a, b) { + return a.length > b.length ? 1 : ( a.length < b.length ? -1 : 0 ); + }); + + resolved = self.versions[0]; + + for ( i in self.versions ) { + next = parseInt(i) + 1; + + if ( next < self.versions.length ) { + if ( self.versions[next].indexOf(self.versions[i]) !== -1 ) { + resolved = self.versions[next]; + } else { + break; + } + } + } + + return self.version = resolved; } - this.setDetected = function(pattern, type, key) { - this.detected = true; + self.setDetected = function(pattern, type, value, key) { + self.detected = true; - this.confidence[type + ' ' + ( key ? ' ' + key : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Set confidence level + self.confidence[type + ' ' + ( key ? key + ' ' : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Detect version number if ( pattern.version ) { + var + version = pattern.version, + matches = pattern.regex.exec(value) + ; + + if ( matches ) { + matches.map(function(match, i) { + version = version.replace('\\' + i, match); + }); + + self.versions.push(version); + + self.getVersion(); + } } } } @@ -132,7 +176,13 @@ var wappalyzer = (function() { */ log: function(message, type) { if ( w.config.environment === 'dev' ) { - if ( typeof type === 'undefined' ) { type = 'debug'; } + if ( typeof type === 'undefined' ) { + type = 'debug'; + } + + if ( typeof message === 'object' ) { + message = JSON.stringify(message); + } driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type }); } @@ -172,7 +222,7 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, j, app, type, regexMeta, regexScript, match, content, meta, header, + i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version, profiler = { regexCount: 0, startTime: new Date().getTime() @@ -195,7 +245,7 @@ var wappalyzer = (function() { } for ( app in w.apps ) { - apps[app] = new Application(); + apps[app] = new Application(app); for ( type in w.apps[app] ) { switch ( type ) { @@ -204,7 +254,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(url) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, url); } }); @@ -218,7 +268,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } }); @@ -237,7 +287,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(match[2]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } } }); @@ -263,7 +313,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { - apps[app].setDetected(pattern, type, meta); + apps[app].setDetected(pattern, type, content[2], meta); } }); } @@ -281,7 +331,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { - apps[app].setDetected(pattern, type, header); + apps[app].setDetected(pattern, type, data[type][header], header); } }); } @@ -297,7 +347,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type][i]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type][i]); } } }); @@ -331,7 +381,7 @@ var wappalyzer = (function() { // Apply app confidence to implied app if ( !apps.hasOwnProperty(implied) ) { - apps[implied] = new Application(true); + apps[implied] = new Application(implied, true); } for ( id in confidence ) { @@ -349,9 +399,7 @@ var wappalyzer = (function() { confidence = apps[app].confidence; // Per URL - if ( !w.detected[url].hasOwnProperty(app)) { - w.detected[url][app] = new Application(); - } + w.detected[url][app] = apps[app]; for ( id in confidence ) { w.detected[url][app].confidence[id] = confidence[id]; diff --git a/drivers/firefox/content/apps.json b/drivers/firefox/content/apps.json index cfb6a7c6e..1b4374c5c 100644 --- a/drivers/firefox/content/apps.json +++ b/drivers/firefox/content/apps.json @@ -725,6 +725,10 @@ "html": "gravityInsightsParams\\.site_guid = '", "env": "^GravityInsights$" }, + "G-WAN": { + "cats": [ 22 ], + "headers": { "Server": "G-WAN" } + }, "GX WebManager": { "cats": [ 1 ], "meta": { "generator": "GX WebManager" } @@ -742,6 +746,10 @@ "script": "highcharts.*\\.js", "env": "^Highcharts$" }, + "Hogan.js": { + "cats": [ 12 ], + "env": "^Hogan$" + }, "Hotaru CMS": { "cats": [ 1 ], "meta": { "generator": "Hotaru CMS" } @@ -1886,6 +1894,10 @@ "meta": { "generator": "WebsiteBaker" }, "implies": [ "PHP" ] }, + "WebsPlanet": { + "cats": [ 1 ], + "meta": { "generator": "WebsPlanet" } + }, "Webtrekk": { "cats": [ 10 ], "html": "var webtrekk = new Object" diff --git a/drivers/firefox/content/js/driver.js b/drivers/firefox/content/js/driver.js index e208fb712..28e0264ee 100644 --- a/drivers/firefox/content/js/driver.js +++ b/drivers/firefox/content/js/driver.js @@ -136,7 +136,7 @@ */ displayApps: function() { var - i, j, app, confidence, elements, menuItem, menuSeparator, image, + i, j, app, confidence, elements, menuItem, menuSeparator, image, version, remove = [], container = d.getElementById('wappalyzer-container'), menu = d.getElementById('wappalyzer-applications'), @@ -175,6 +175,7 @@ for ( app in w.detected[url] ) { confidence = w.detected[url][app].confidenceTotal; + version = w.detected[url][app].version; var j, cat, showCat, categories = []; @@ -191,7 +192,7 @@ menuItem.setAttribute('class', 'wappalyzer-application menuitem-iconic'); menuItem.setAttribute('image', 'chrome://wappalyzer/skin/images/icons/' + app + '.png'); - menuItem.setAttribute('label', app + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' )); + menuItem.setAttribute('label', app + ( version ? ' ' + version : '' ) + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' )); menuItem.setAttribute('name', app); menuItem.setAttribute('data-url', w.config.websiteURL + 'applications/' + app.toLowerCase().replace(/ /g, '-').replace(/[^\w-]/g, '')); diff --git a/drivers/firefox/content/js/wappalyzer.js b/drivers/firefox/content/js/wappalyzer.js index 44c7cf0ff..bcc79ff08 100644 --- a/drivers/firefox/content/js/wappalyzer.js +++ b/drivers/firefox/content/js/wappalyzer.js @@ -12,38 +12,82 @@ var wappalyzer = (function() { /** * Application class */ - var Application = function(detected) { - this.confidence = {}; - this.confidenceTotal = 0; - this.detected = Boolean(detected); - this.versions = []; + var Application = function(app, detected) { + var self = this; + + self.app = app; + self.confidence = {}; + self.confidenceTotal = 0; + self.detected = Boolean(detected); + self.version = ''; + self.versions = []; /** * Calculate confidence total */ - this.getConfidence = function() { + self.getConfidence = function() { var total = 0; - for ( id in this.confidence ) { - total += this.confidence[id]; + for ( id in self.confidence ) { + total += self.confidence[id]; } - return this.confidenceTotal = Math.min(total, 100); + return self.confidenceTotal = Math.min(total, 100); } /** - * Resolve version number + * Resolve version number (find the longest version number that contains all shorter detected version numbers) */ - this.getVersion = function() { - return null; + self.getVersion = function() { + var next, resolved; + + if ( !self.versions.length ) { + return; + } + + self.versions.sort(function(a, b) { + return a.length > b.length ? 1 : ( a.length < b.length ? -1 : 0 ); + }); + + resolved = self.versions[0]; + + for ( i in self.versions ) { + next = parseInt(i) + 1; + + if ( next < self.versions.length ) { + if ( self.versions[next].indexOf(self.versions[i]) !== -1 ) { + resolved = self.versions[next]; + } else { + break; + } + } + } + + return self.version = resolved; } - this.setDetected = function(pattern, type, key) { - this.detected = true; + self.setDetected = function(pattern, type, value, key) { + self.detected = true; - this.confidence[type + ' ' + ( key ? ' ' + key : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Set confidence level + self.confidence[type + ' ' + ( key ? key + ' ' : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Detect version number if ( pattern.version ) { + var + version = pattern.version, + matches = pattern.regex.exec(value) + ; + + if ( matches ) { + matches.map(function(match, i) { + version = version.replace('\\' + i, match); + }); + + self.versions.push(version); + + self.getVersion(); + } } } } @@ -132,7 +176,13 @@ var wappalyzer = (function() { */ log: function(message, type) { if ( w.config.environment === 'dev' ) { - if ( typeof type === 'undefined' ) { type = 'debug'; } + if ( typeof type === 'undefined' ) { + type = 'debug'; + } + + if ( typeof message === 'object' ) { + message = JSON.stringify(message); + } driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type }); } @@ -172,7 +222,7 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, j, app, type, regexMeta, regexScript, match, content, meta, header, + i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version, profiler = { regexCount: 0, startTime: new Date().getTime() @@ -195,7 +245,7 @@ var wappalyzer = (function() { } for ( app in w.apps ) { - apps[app] = new Application(); + apps[app] = new Application(app); for ( type in w.apps[app] ) { switch ( type ) { @@ -204,7 +254,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(url) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, url); } }); @@ -218,7 +268,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } }); @@ -237,7 +287,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(match[2]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } } }); @@ -263,7 +313,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { - apps[app].setDetected(pattern, type, meta); + apps[app].setDetected(pattern, type, content[2], meta); } }); } @@ -281,7 +331,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { - apps[app].setDetected(pattern, type, header); + apps[app].setDetected(pattern, type, data[type][header], header); } }); } @@ -297,7 +347,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type][i]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type][i]); } } }); @@ -331,7 +381,7 @@ var wappalyzer = (function() { // Apply app confidence to implied app if ( !apps.hasOwnProperty(implied) ) { - apps[implied] = new Application(true); + apps[implied] = new Application(implied, true); } for ( id in confidence ) { @@ -349,9 +399,7 @@ var wappalyzer = (function() { confidence = apps[app].confidence; // Per URL - if ( !w.detected[url].hasOwnProperty(app)) { - w.detected[url][app] = new Application(); - } + w.detected[url][app] = apps[app]; for ( id in confidence ) { w.detected[url][app].confidence[id] = confidence[id]; diff --git a/drivers/firefox/skin/images/icons/G-WAN.png b/drivers/firefox/skin/images/icons/G-WAN.png new file mode 100644 index 000000000..21997a742 Binary files /dev/null and b/drivers/firefox/skin/images/icons/G-WAN.png differ diff --git a/drivers/firefox/skin/images/icons/Hogan.js.png b/drivers/firefox/skin/images/icons/Hogan.js.png new file mode 100644 index 000000000..7f74461f2 Binary files /dev/null and b/drivers/firefox/skin/images/icons/Hogan.js.png differ diff --git a/drivers/firefox/skin/images/icons/WebsPlanet.png b/drivers/firefox/skin/images/icons/WebsPlanet.png new file mode 100644 index 000000000..cee2e67d1 Binary files /dev/null and b/drivers/firefox/skin/images/icons/WebsPlanet.png differ diff --git a/drivers/html/apps.json b/drivers/html/apps.json index cfb6a7c6e..1b4374c5c 100644 --- a/drivers/html/apps.json +++ b/drivers/html/apps.json @@ -725,6 +725,10 @@ "html": "gravityInsightsParams\\.site_guid = '", "env": "^GravityInsights$" }, + "G-WAN": { + "cats": [ 22 ], + "headers": { "Server": "G-WAN" } + }, "GX WebManager": { "cats": [ 1 ], "meta": { "generator": "GX WebManager" } @@ -742,6 +746,10 @@ "script": "highcharts.*\\.js", "env": "^Highcharts$" }, + "Hogan.js": { + "cats": [ 12 ], + "env": "^Hogan$" + }, "Hotaru CMS": { "cats": [ 1 ], "meta": { "generator": "Hotaru CMS" } @@ -1886,6 +1894,10 @@ "meta": { "generator": "WebsiteBaker" }, "implies": [ "PHP" ] }, + "WebsPlanet": { + "cats": [ 1 ], + "meta": { "generator": "WebsPlanet" } + }, "Webtrekk": { "cats": [ 10 ], "html": "var webtrekk = new Object" diff --git a/drivers/html/images/icons/G-WAN.png b/drivers/html/images/icons/G-WAN.png new file mode 100644 index 000000000..21997a742 Binary files /dev/null and b/drivers/html/images/icons/G-WAN.png differ diff --git a/drivers/html/images/icons/Hogan.js.png b/drivers/html/images/icons/Hogan.js.png new file mode 100644 index 000000000..7f74461f2 Binary files /dev/null and b/drivers/html/images/icons/Hogan.js.png differ diff --git a/drivers/html/images/icons/WebsPlanet.png b/drivers/html/images/icons/WebsPlanet.png new file mode 100644 index 000000000..cee2e67d1 Binary files /dev/null and b/drivers/html/images/icons/WebsPlanet.png differ diff --git a/drivers/html/js/wappalyzer.js b/drivers/html/js/wappalyzer.js index 44c7cf0ff..bcc79ff08 100644 --- a/drivers/html/js/wappalyzer.js +++ b/drivers/html/js/wappalyzer.js @@ -12,38 +12,82 @@ var wappalyzer = (function() { /** * Application class */ - var Application = function(detected) { - this.confidence = {}; - this.confidenceTotal = 0; - this.detected = Boolean(detected); - this.versions = []; + var Application = function(app, detected) { + var self = this; + + self.app = app; + self.confidence = {}; + self.confidenceTotal = 0; + self.detected = Boolean(detected); + self.version = ''; + self.versions = []; /** * Calculate confidence total */ - this.getConfidence = function() { + self.getConfidence = function() { var total = 0; - for ( id in this.confidence ) { - total += this.confidence[id]; + for ( id in self.confidence ) { + total += self.confidence[id]; } - return this.confidenceTotal = Math.min(total, 100); + return self.confidenceTotal = Math.min(total, 100); } /** - * Resolve version number + * Resolve version number (find the longest version number that contains all shorter detected version numbers) */ - this.getVersion = function() { - return null; + self.getVersion = function() { + var next, resolved; + + if ( !self.versions.length ) { + return; + } + + self.versions.sort(function(a, b) { + return a.length > b.length ? 1 : ( a.length < b.length ? -1 : 0 ); + }); + + resolved = self.versions[0]; + + for ( i in self.versions ) { + next = parseInt(i) + 1; + + if ( next < self.versions.length ) { + if ( self.versions[next].indexOf(self.versions[i]) !== -1 ) { + resolved = self.versions[next]; + } else { + break; + } + } + } + + return self.version = resolved; } - this.setDetected = function(pattern, type, key) { - this.detected = true; + self.setDetected = function(pattern, type, value, key) { + self.detected = true; - this.confidence[type + ' ' + ( key ? ' ' + key : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Set confidence level + self.confidence[type + ' ' + ( key ? key + ' ' : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Detect version number if ( pattern.version ) { + var + version = pattern.version, + matches = pattern.regex.exec(value) + ; + + if ( matches ) { + matches.map(function(match, i) { + version = version.replace('\\' + i, match); + }); + + self.versions.push(version); + + self.getVersion(); + } } } } @@ -132,7 +176,13 @@ var wappalyzer = (function() { */ log: function(message, type) { if ( w.config.environment === 'dev' ) { - if ( typeof type === 'undefined' ) { type = 'debug'; } + if ( typeof type === 'undefined' ) { + type = 'debug'; + } + + if ( typeof message === 'object' ) { + message = JSON.stringify(message); + } driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type }); } @@ -172,7 +222,7 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, j, app, type, regexMeta, regexScript, match, content, meta, header, + i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version, profiler = { regexCount: 0, startTime: new Date().getTime() @@ -195,7 +245,7 @@ var wappalyzer = (function() { } for ( app in w.apps ) { - apps[app] = new Application(); + apps[app] = new Application(app); for ( type in w.apps[app] ) { switch ( type ) { @@ -204,7 +254,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(url) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, url); } }); @@ -218,7 +268,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } }); @@ -237,7 +287,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(match[2]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } } }); @@ -263,7 +313,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { - apps[app].setDetected(pattern, type, meta); + apps[app].setDetected(pattern, type, content[2], meta); } }); } @@ -281,7 +331,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { - apps[app].setDetected(pattern, type, header); + apps[app].setDetected(pattern, type, data[type][header], header); } }); } @@ -297,7 +347,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type][i]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type][i]); } } }); @@ -331,7 +381,7 @@ var wappalyzer = (function() { // Apply app confidence to implied app if ( !apps.hasOwnProperty(implied) ) { - apps[implied] = new Application(true); + apps[implied] = new Application(implied, true); } for ( id in confidence ) { @@ -349,9 +399,7 @@ var wappalyzer = (function() { confidence = apps[app].confidence; // Per URL - if ( !w.detected[url].hasOwnProperty(app)) { - w.detected[url][app] = new Application(); - } + w.detected[url][app] = apps[app]; for ( id in confidence ) { w.detected[url][app].confidence[id] = confidence[id]; diff --git a/drivers/php/apps.json b/drivers/php/apps.json index cfb6a7c6e..1b4374c5c 100644 --- a/drivers/php/apps.json +++ b/drivers/php/apps.json @@ -725,6 +725,10 @@ "html": "gravityInsightsParams\\.site_guid = '", "env": "^GravityInsights$" }, + "G-WAN": { + "cats": [ 22 ], + "headers": { "Server": "G-WAN" } + }, "GX WebManager": { "cats": [ 1 ], "meta": { "generator": "GX WebManager" } @@ -742,6 +746,10 @@ "script": "highcharts.*\\.js", "env": "^Highcharts$" }, + "Hogan.js": { + "cats": [ 12 ], + "env": "^Hogan$" + }, "Hotaru CMS": { "cats": [ 1 ], "meta": { "generator": "Hotaru CMS" } @@ -1886,6 +1894,10 @@ "meta": { "generator": "WebsiteBaker" }, "implies": [ "PHP" ] }, + "WebsPlanet": { + "cats": [ 1 ], + "meta": { "generator": "WebsPlanet" } + }, "Webtrekk": { "cats": [ 10 ], "html": "var webtrekk = new Object" diff --git a/drivers/php/js/wappalyzer.js b/drivers/php/js/wappalyzer.js index 44c7cf0ff..bcc79ff08 100644 --- a/drivers/php/js/wappalyzer.js +++ b/drivers/php/js/wappalyzer.js @@ -12,38 +12,82 @@ var wappalyzer = (function() { /** * Application class */ - var Application = function(detected) { - this.confidence = {}; - this.confidenceTotal = 0; - this.detected = Boolean(detected); - this.versions = []; + var Application = function(app, detected) { + var self = this; + + self.app = app; + self.confidence = {}; + self.confidenceTotal = 0; + self.detected = Boolean(detected); + self.version = ''; + self.versions = []; /** * Calculate confidence total */ - this.getConfidence = function() { + self.getConfidence = function() { var total = 0; - for ( id in this.confidence ) { - total += this.confidence[id]; + for ( id in self.confidence ) { + total += self.confidence[id]; } - return this.confidenceTotal = Math.min(total, 100); + return self.confidenceTotal = Math.min(total, 100); } /** - * Resolve version number + * Resolve version number (find the longest version number that contains all shorter detected version numbers) */ - this.getVersion = function() { - return null; + self.getVersion = function() { + var next, resolved; + + if ( !self.versions.length ) { + return; + } + + self.versions.sort(function(a, b) { + return a.length > b.length ? 1 : ( a.length < b.length ? -1 : 0 ); + }); + + resolved = self.versions[0]; + + for ( i in self.versions ) { + next = parseInt(i) + 1; + + if ( next < self.versions.length ) { + if ( self.versions[next].indexOf(self.versions[i]) !== -1 ) { + resolved = self.versions[next]; + } else { + break; + } + } + } + + return self.version = resolved; } - this.setDetected = function(pattern, type, key) { - this.detected = true; + self.setDetected = function(pattern, type, value, key) { + self.detected = true; - this.confidence[type + ' ' + ( key ? ' ' + key : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Set confidence level + self.confidence[type + ' ' + ( key ? key + ' ' : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Detect version number if ( pattern.version ) { + var + version = pattern.version, + matches = pattern.regex.exec(value) + ; + + if ( matches ) { + matches.map(function(match, i) { + version = version.replace('\\' + i, match); + }); + + self.versions.push(version); + + self.getVersion(); + } } } } @@ -132,7 +176,13 @@ var wappalyzer = (function() { */ log: function(message, type) { if ( w.config.environment === 'dev' ) { - if ( typeof type === 'undefined' ) { type = 'debug'; } + if ( typeof type === 'undefined' ) { + type = 'debug'; + } + + if ( typeof message === 'object' ) { + message = JSON.stringify(message); + } driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type }); } @@ -172,7 +222,7 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, j, app, type, regexMeta, regexScript, match, content, meta, header, + i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version, profiler = { regexCount: 0, startTime: new Date().getTime() @@ -195,7 +245,7 @@ var wappalyzer = (function() { } for ( app in w.apps ) { - apps[app] = new Application(); + apps[app] = new Application(app); for ( type in w.apps[app] ) { switch ( type ) { @@ -204,7 +254,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(url) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, url); } }); @@ -218,7 +268,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } }); @@ -237,7 +287,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(match[2]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } } }); @@ -263,7 +313,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { - apps[app].setDetected(pattern, type, meta); + apps[app].setDetected(pattern, type, content[2], meta); } }); } @@ -281,7 +331,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { - apps[app].setDetected(pattern, type, header); + apps[app].setDetected(pattern, type, data[type][header], header); } }); } @@ -297,7 +347,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type][i]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type][i]); } } }); @@ -331,7 +381,7 @@ var wappalyzer = (function() { // Apply app confidence to implied app if ( !apps.hasOwnProperty(implied) ) { - apps[implied] = new Application(true); + apps[implied] = new Application(implied, true); } for ( id in confidence ) { @@ -349,9 +399,7 @@ var wappalyzer = (function() { confidence = apps[app].confidence; // Per URL - if ( !w.detected[url].hasOwnProperty(app)) { - w.detected[url][app] = new Application(); - } + w.detected[url][app] = apps[app]; for ( id in confidence ) { w.detected[url][app].confidence[id] = confidence[id]; diff --git a/share/apps.json b/share/apps.json index 7ca107ee8..71756e235 100644 --- a/share/apps.json +++ b/share/apps.json @@ -725,6 +725,10 @@ "html": "gravityInsightsParams\\.site_guid = '", "env": "^GravityInsights$" }, + "G-WAN": { + "cats": [ 22 ], + "headers": { "Server": "G-WAN" } + }, "GX WebManager": { "cats": [ 1 ], "meta": { "generator": "GX WebManager" } @@ -742,6 +746,10 @@ "script": "highcharts.*\\.js", "env": "^Highcharts$" }, + "Hogan.js": { + "cats": [ 12 ], + "env": "^Hogan$" + }, "Hotaru CMS": { "cats": [ 1 ], "meta": { "generator": "Hotaru CMS" } @@ -1894,6 +1902,10 @@ "meta": { "generator": "WebsiteBaker" }, "implies": [ "PHP" ] }, + "WebsPlanet": { + "cats": [ 1 ], + "meta": { "generator": "WebsPlanet" } + }, "Webtrekk": { "cats": [ 10 ], "html": "var webtrekk = new Object" diff --git a/share/images/icons/G-WAN.png b/share/images/icons/G-WAN.png new file mode 100644 index 000000000..21997a742 Binary files /dev/null and b/share/images/icons/G-WAN.png differ diff --git a/share/images/icons/Hogan.js.png b/share/images/icons/Hogan.js.png new file mode 100644 index 000000000..7f74461f2 Binary files /dev/null and b/share/images/icons/Hogan.js.png differ diff --git a/share/images/icons/WebsPlanet.png b/share/images/icons/WebsPlanet.png new file mode 100644 index 000000000..cee2e67d1 Binary files /dev/null and b/share/images/icons/WebsPlanet.png differ diff --git a/share/js/wappalyzer.js b/share/js/wappalyzer.js index 44c7cf0ff..bcc79ff08 100644 --- a/share/js/wappalyzer.js +++ b/share/js/wappalyzer.js @@ -12,38 +12,82 @@ var wappalyzer = (function() { /** * Application class */ - var Application = function(detected) { - this.confidence = {}; - this.confidenceTotal = 0; - this.detected = Boolean(detected); - this.versions = []; + var Application = function(app, detected) { + var self = this; + + self.app = app; + self.confidence = {}; + self.confidenceTotal = 0; + self.detected = Boolean(detected); + self.version = ''; + self.versions = []; /** * Calculate confidence total */ - this.getConfidence = function() { + self.getConfidence = function() { var total = 0; - for ( id in this.confidence ) { - total += this.confidence[id]; + for ( id in self.confidence ) { + total += self.confidence[id]; } - return this.confidenceTotal = Math.min(total, 100); + return self.confidenceTotal = Math.min(total, 100); } /** - * Resolve version number + * Resolve version number (find the longest version number that contains all shorter detected version numbers) */ - this.getVersion = function() { - return null; + self.getVersion = function() { + var next, resolved; + + if ( !self.versions.length ) { + return; + } + + self.versions.sort(function(a, b) { + return a.length > b.length ? 1 : ( a.length < b.length ? -1 : 0 ); + }); + + resolved = self.versions[0]; + + for ( i in self.versions ) { + next = parseInt(i) + 1; + + if ( next < self.versions.length ) { + if ( self.versions[next].indexOf(self.versions[i]) !== -1 ) { + resolved = self.versions[next]; + } else { + break; + } + } + } + + return self.version = resolved; } - this.setDetected = function(pattern, type, key) { - this.detected = true; + self.setDetected = function(pattern, type, value, key) { + self.detected = true; - this.confidence[type + ' ' + ( key ? ' ' + key : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Set confidence level + self.confidence[type + ' ' + ( key ? key + ' ' : '' ) + pattern.regex] = pattern.confidence ? pattern.confidence : 100; + // Detect version number if ( pattern.version ) { + var + version = pattern.version, + matches = pattern.regex.exec(value) + ; + + if ( matches ) { + matches.map(function(match, i) { + version = version.replace('\\' + i, match); + }); + + self.versions.push(version); + + self.getVersion(); + } } } } @@ -132,7 +176,13 @@ var wappalyzer = (function() { */ log: function(message, type) { if ( w.config.environment === 'dev' ) { - if ( typeof type === 'undefined' ) { type = 'debug'; } + if ( typeof type === 'undefined' ) { + type = 'debug'; + } + + if ( typeof message === 'object' ) { + message = JSON.stringify(message); + } driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type }); } @@ -172,7 +222,7 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, j, app, type, regexMeta, regexScript, match, content, meta, header, + i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version, profiler = { regexCount: 0, startTime: new Date().getTime() @@ -195,7 +245,7 @@ var wappalyzer = (function() { } for ( app in w.apps ) { - apps[app] = new Application(); + apps[app] = new Application(app); for ( type in w.apps[app] ) { switch ( type ) { @@ -204,7 +254,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(url) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, url); } }); @@ -218,7 +268,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } }); @@ -237,7 +287,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(match[2]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type]); } } }); @@ -263,7 +313,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { - apps[app].setDetected(pattern, type, meta); + apps[app].setDetected(pattern, type, content[2], meta); } }); } @@ -281,7 +331,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { - apps[app].setDetected(pattern, type, header); + apps[app].setDetected(pattern, type, data[type][header], header); } }); } @@ -297,7 +347,7 @@ var wappalyzer = (function() { profiler.regexCount ++; if ( pattern.regex.test(data[type][i]) ) { - apps[app].setDetected(pattern, type); + apps[app].setDetected(pattern, type, data[type][i]); } } }); @@ -331,7 +381,7 @@ var wappalyzer = (function() { // Apply app confidence to implied app if ( !apps.hasOwnProperty(implied) ) { - apps[implied] = new Application(true); + apps[implied] = new Application(implied, true); } for ( id in confidence ) { @@ -349,9 +399,7 @@ var wappalyzer = (function() { confidence = apps[app].confidence; // Per URL - if ( !w.detected[url].hasOwnProperty(app)) { - w.detected[url][app] = new Application(); - } + w.detected[url][app] = apps[app]; for ( id in confidence ) { w.detected[url][app].confidence[id] = confidence[id];