Basic version detection functional

main
Elbert Alias 12 years ago
parent 6135d1a80d
commit bbda93296a

@ -12,38 +12,82 @@ var wappalyzer = (function() {
/** /**
* Application class * Application class
*/ */
var Application = function(detected) { var Application = function(app, detected) {
this.confidence = {}; var self = this;
this.confidenceTotal = 0;
this.detected = Boolean(detected); self.app = app;
this.versions = []; self.confidence = {};
self.confidenceTotal = 0;
self.detected = Boolean(detected);
self.version = '';
self.versions = [];
/** /**
* Calculate confidence total * Calculate confidence total
*/ */
this.getConfidence = function() { self.getConfidence = function() {
var total = 0; var total = 0;
for ( id in this.confidence ) { for ( id in self.confidence ) {
total += this.confidence[id]; 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() { self.getVersion = function() {
return null; 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) { self.setDetected = function(pattern, type, value, key) {
this.detected = true; 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 ) { 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) { log: function(message, type) {
if ( w.config.environment === 'dev' ) { 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 }); driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type });
} }
@ -172,7 +222,7 @@ var wappalyzer = (function() {
*/ */
analyze: function(hostname, url, data) { analyze: function(hostname, url, data) {
var var
i, j, app, type, regexMeta, regexScript, match, content, meta, header, i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version,
profiler = { profiler = {
regexCount: 0, regexCount: 0,
startTime: new Date().getTime() startTime: new Date().getTime()
@ -195,7 +245,7 @@ var wappalyzer = (function() {
} }
for ( app in w.apps ) { for ( app in w.apps ) {
apps[app] = new Application(); apps[app] = new Application(app);
for ( type in w.apps[app] ) { for ( type in w.apps[app] ) {
switch ( type ) { switch ( type ) {
@ -204,7 +254,7 @@ var wappalyzer = (function() {
profiler.regexCount ++; profiler.regexCount ++;
if ( pattern.regex.test(url) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(match[2]) ) { 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 ++; profiler.regexCount ++;
if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { 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 ++; profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type][i]) ) { 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 // Apply app confidence to implied app
if ( !apps.hasOwnProperty(implied) ) { if ( !apps.hasOwnProperty(implied) ) {
apps[implied] = new Application(true); apps[implied] = new Application(implied, true);
} }
for ( id in confidence ) { for ( id in confidence ) {
@ -349,9 +399,7 @@ var wappalyzer = (function() {
confidence = apps[app].confidence; confidence = apps[app].confidence;
// Per URL // Per URL
if ( !w.detected[url].hasOwnProperty(app)) { w.detected[url][app] = apps[app];
w.detected[url][app] = new Application();
}
for ( id in confidence ) { for ( id in confidence ) {
w.detected[url][app].confidence[id] = confidence[id]; w.detected[url][app].confidence[id] = confidence[id];

@ -42,7 +42,7 @@ document.addEventListener('DOMContentLoaded', function() {
}, },
displayApps: function() { displayApps: function() {
var appName, confidence; var appName, confidence, version;
chrome.tabs.getSelected(null, function(tab) { chrome.tabs.getSelected(null, function(tab) {
chrome.extension.sendRequest({ id: 'get_apps', tab: tab }, function(response) { chrome.extension.sendRequest({ id: 'get_apps', tab: tab }, function(response) {
@ -59,12 +59,13 @@ document.addEventListener('DOMContentLoaded', function() {
for ( appName in response.tabCache.appsDetected ) { for ( appName in response.tabCache.appsDetected ) {
confidence = response.tabCache.appsDetected[appName].confidenceTotal; confidence = response.tabCache.appsDetected[appName].confidenceTotal;
version = response.tabCache.appsDetected[appName].version;
html = html =
'<div class="detected-app">' + '<div class="detected-app">' +
'<a target="_blank" href="http://wappalyzer.com/applications/' + appName.toLowerCase().replace(/ /g, '-').replace(/[^\w-]/g, '') + '?utm_source=chrome&utm_medium=popup&utm_campaign=extensions">' + '<a target="_blank" href="http://wappalyzer.com/applications/' + appName.toLowerCase().replace(/ /g, '-').replace(/[^\w-]/g, '') + '?utm_source=chrome&utm_medium=popup&utm_campaign=extensions">' +
'<img src="images/icons/' + appName + '.png"/>' + '<img src="images/icons/' + appName + '.png"/>' +
'<span class="label">' + appName + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' ) + '</span>' + '<span class="label">' + appName + ( version ? ' ' + version : '' ) + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' ) + '</span>' +
'</a>'; '</a>';
response.apps[appName].cats.map(function(cat) { response.apps[appName].cats.map(function(cat) {

@ -12,38 +12,82 @@ var wappalyzer = (function() {
/** /**
* Application class * Application class
*/ */
var Application = function(detected) { var Application = function(app, detected) {
this.confidence = {}; var self = this;
this.confidenceTotal = 0;
this.detected = Boolean(detected); self.app = app;
this.versions = []; self.confidence = {};
self.confidenceTotal = 0;
self.detected = Boolean(detected);
self.version = '';
self.versions = [];
/** /**
* Calculate confidence total * Calculate confidence total
*/ */
this.getConfidence = function() { self.getConfidence = function() {
var total = 0; var total = 0;
for ( id in this.confidence ) { for ( id in self.confidence ) {
total += this.confidence[id]; 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() { self.getVersion = function() {
return null; 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) { self.setDetected = function(pattern, type, value, key) {
this.detected = true; 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 ) { 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) { log: function(message, type) {
if ( w.config.environment === 'dev' ) { 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 }); driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type });
} }
@ -172,7 +222,7 @@ var wappalyzer = (function() {
*/ */
analyze: function(hostname, url, data) { analyze: function(hostname, url, data) {
var var
i, j, app, type, regexMeta, regexScript, match, content, meta, header, i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version,
profiler = { profiler = {
regexCount: 0, regexCount: 0,
startTime: new Date().getTime() startTime: new Date().getTime()
@ -195,7 +245,7 @@ var wappalyzer = (function() {
} }
for ( app in w.apps ) { for ( app in w.apps ) {
apps[app] = new Application(); apps[app] = new Application(app);
for ( type in w.apps[app] ) { for ( type in w.apps[app] ) {
switch ( type ) { switch ( type ) {
@ -204,7 +254,7 @@ var wappalyzer = (function() {
profiler.regexCount ++; profiler.regexCount ++;
if ( pattern.regex.test(url) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(match[2]) ) { 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 ++; profiler.regexCount ++;
if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { 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 ++; profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type][i]) ) { 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 // Apply app confidence to implied app
if ( !apps.hasOwnProperty(implied) ) { if ( !apps.hasOwnProperty(implied) ) {
apps[implied] = new Application(true); apps[implied] = new Application(implied, true);
} }
for ( id in confidence ) { for ( id in confidence ) {
@ -349,9 +399,7 @@ var wappalyzer = (function() {
confidence = apps[app].confidence; confidence = apps[app].confidence;
// Per URL // Per URL
if ( !w.detected[url].hasOwnProperty(app)) { w.detected[url][app] = apps[app];
w.detected[url][app] = new Application();
}
for ( id in confidence ) { for ( id in confidence ) {
w.detected[url][app].confidence[id] = confidence[id]; w.detected[url][app].confidence[id] = confidence[id];

@ -12,38 +12,82 @@ var wappalyzer = (function() {
/** /**
* Application class * Application class
*/ */
var Application = function(detected) { var Application = function(app, detected) {
this.confidence = {}; var self = this;
this.confidenceTotal = 0;
this.detected = Boolean(detected); self.app = app;
this.versions = []; self.confidence = {};
self.confidenceTotal = 0;
self.detected = Boolean(detected);
self.version = '';
self.versions = [];
/** /**
* Calculate confidence total * Calculate confidence total
*/ */
this.getConfidence = function() { self.getConfidence = function() {
var total = 0; var total = 0;
for ( id in this.confidence ) { for ( id in self.confidence ) {
total += this.confidence[id]; 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() { self.getVersion = function() {
return null; 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) { self.setDetected = function(pattern, type, value, key) {
this.detected = true; 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 ) { 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) { log: function(message, type) {
if ( w.config.environment === 'dev' ) { 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 }); driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type });
} }
@ -172,7 +222,7 @@ var wappalyzer = (function() {
*/ */
analyze: function(hostname, url, data) { analyze: function(hostname, url, data) {
var var
i, j, app, type, regexMeta, regexScript, match, content, meta, header, i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version,
profiler = { profiler = {
regexCount: 0, regexCount: 0,
startTime: new Date().getTime() startTime: new Date().getTime()
@ -195,7 +245,7 @@ var wappalyzer = (function() {
} }
for ( app in w.apps ) { for ( app in w.apps ) {
apps[app] = new Application(); apps[app] = new Application(app);
for ( type in w.apps[app] ) { for ( type in w.apps[app] ) {
switch ( type ) { switch ( type ) {
@ -204,7 +254,7 @@ var wappalyzer = (function() {
profiler.regexCount ++; profiler.regexCount ++;
if ( pattern.regex.test(url) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(match[2]) ) { 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 ++; profiler.regexCount ++;
if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { 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 ++; profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type][i]) ) { 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 // Apply app confidence to implied app
if ( !apps.hasOwnProperty(implied) ) { if ( !apps.hasOwnProperty(implied) ) {
apps[implied] = new Application(true); apps[implied] = new Application(implied, true);
} }
for ( id in confidence ) { for ( id in confidence ) {
@ -349,9 +399,7 @@ var wappalyzer = (function() {
confidence = apps[app].confidence; confidence = apps[app].confidence;
// Per URL // Per URL
if ( !w.detected[url].hasOwnProperty(app)) { w.detected[url][app] = apps[app];
w.detected[url][app] = new Application();
}
for ( id in confidence ) { for ( id in confidence ) {
w.detected[url][app].confidence[id] = confidence[id]; w.detected[url][app].confidence[id] = confidence[id];

@ -136,7 +136,7 @@
*/ */
displayApps: function() { displayApps: function() {
var var
i, j, app, confidence, elements, menuItem, menuSeparator, image, i, j, app, confidence, elements, menuItem, menuSeparator, image, version,
remove = [], remove = [],
container = d.getElementById('wappalyzer-container'), container = d.getElementById('wappalyzer-container'),
menu = d.getElementById('wappalyzer-applications'), menu = d.getElementById('wappalyzer-applications'),
@ -175,6 +175,7 @@
for ( app in w.detected[url] ) { for ( app in w.detected[url] ) {
confidence = w.detected[url][app].confidenceTotal; confidence = w.detected[url][app].confidenceTotal;
version = w.detected[url][app].version;
var j, cat, showCat, categories = []; var j, cat, showCat, categories = [];
@ -191,7 +192,7 @@
menuItem.setAttribute('class', 'wappalyzer-application menuitem-iconic'); menuItem.setAttribute('class', 'wappalyzer-application menuitem-iconic');
menuItem.setAttribute('image', 'chrome://wappalyzer/skin/images/icons/' + app + '.png'); 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('name', app);
menuItem.setAttribute('data-url', w.config.websiteURL + 'applications/' + app.toLowerCase().replace(/ /g, '-').replace(/[^\w-]/g, '')); menuItem.setAttribute('data-url', w.config.websiteURL + 'applications/' + app.toLowerCase().replace(/ /g, '-').replace(/[^\w-]/g, ''));

@ -12,38 +12,82 @@ var wappalyzer = (function() {
/** /**
* Application class * Application class
*/ */
var Application = function(detected) { var Application = function(app, detected) {
this.confidence = {}; var self = this;
this.confidenceTotal = 0;
this.detected = Boolean(detected); self.app = app;
this.versions = []; self.confidence = {};
self.confidenceTotal = 0;
self.detected = Boolean(detected);
self.version = '';
self.versions = [];
/** /**
* Calculate confidence total * Calculate confidence total
*/ */
this.getConfidence = function() { self.getConfidence = function() {
var total = 0; var total = 0;
for ( id in this.confidence ) { for ( id in self.confidence ) {
total += this.confidence[id]; 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() { self.getVersion = function() {
return null; 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) { self.setDetected = function(pattern, type, value, key) {
this.detected = true; 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 ) { 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) { log: function(message, type) {
if ( w.config.environment === 'dev' ) { 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 }); driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type });
} }
@ -172,7 +222,7 @@ var wappalyzer = (function() {
*/ */
analyze: function(hostname, url, data) { analyze: function(hostname, url, data) {
var var
i, j, app, type, regexMeta, regexScript, match, content, meta, header, i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version,
profiler = { profiler = {
regexCount: 0, regexCount: 0,
startTime: new Date().getTime() startTime: new Date().getTime()
@ -195,7 +245,7 @@ var wappalyzer = (function() {
} }
for ( app in w.apps ) { for ( app in w.apps ) {
apps[app] = new Application(); apps[app] = new Application(app);
for ( type in w.apps[app] ) { for ( type in w.apps[app] ) {
switch ( type ) { switch ( type ) {
@ -204,7 +254,7 @@ var wappalyzer = (function() {
profiler.regexCount ++; profiler.regexCount ++;
if ( pattern.regex.test(url) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(match[2]) ) { 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 ++; profiler.regexCount ++;
if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { 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 ++; profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type][i]) ) { 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 // Apply app confidence to implied app
if ( !apps.hasOwnProperty(implied) ) { if ( !apps.hasOwnProperty(implied) ) {
apps[implied] = new Application(true); apps[implied] = new Application(implied, true);
} }
for ( id in confidence ) { for ( id in confidence ) {
@ -349,9 +399,7 @@ var wappalyzer = (function() {
confidence = apps[app].confidence; confidence = apps[app].confidence;
// Per URL // Per URL
if ( !w.detected[url].hasOwnProperty(app)) { w.detected[url][app] = apps[app];
w.detected[url][app] = new Application();
}
for ( id in confidence ) { for ( id in confidence ) {
w.detected[url][app].confidence[id] = confidence[id]; w.detected[url][app].confidence[id] = confidence[id];

@ -12,38 +12,82 @@ var wappalyzer = (function() {
/** /**
* Application class * Application class
*/ */
var Application = function(detected) { var Application = function(app, detected) {
this.confidence = {}; var self = this;
this.confidenceTotal = 0;
this.detected = Boolean(detected); self.app = app;
this.versions = []; self.confidence = {};
self.confidenceTotal = 0;
self.detected = Boolean(detected);
self.version = '';
self.versions = [];
/** /**
* Calculate confidence total * Calculate confidence total
*/ */
this.getConfidence = function() { self.getConfidence = function() {
var total = 0; var total = 0;
for ( id in this.confidence ) { for ( id in self.confidence ) {
total += this.confidence[id]; 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() { self.getVersion = function() {
return null; 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) { self.setDetected = function(pattern, type, value, key) {
this.detected = true; 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 ) { 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) { log: function(message, type) {
if ( w.config.environment === 'dev' ) { 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 }); driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type });
} }
@ -172,7 +222,7 @@ var wappalyzer = (function() {
*/ */
analyze: function(hostname, url, data) { analyze: function(hostname, url, data) {
var var
i, j, app, type, regexMeta, regexScript, match, content, meta, header, i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version,
profiler = { profiler = {
regexCount: 0, regexCount: 0,
startTime: new Date().getTime() startTime: new Date().getTime()
@ -195,7 +245,7 @@ var wappalyzer = (function() {
} }
for ( app in w.apps ) { for ( app in w.apps ) {
apps[app] = new Application(); apps[app] = new Application(app);
for ( type in w.apps[app] ) { for ( type in w.apps[app] ) {
switch ( type ) { switch ( type ) {
@ -204,7 +254,7 @@ var wappalyzer = (function() {
profiler.regexCount ++; profiler.regexCount ++;
if ( pattern.regex.test(url) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(match[2]) ) { 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 ++; profiler.regexCount ++;
if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { 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 ++; profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type][i]) ) { 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 // Apply app confidence to implied app
if ( !apps.hasOwnProperty(implied) ) { if ( !apps.hasOwnProperty(implied) ) {
apps[implied] = new Application(true); apps[implied] = new Application(implied, true);
} }
for ( id in confidence ) { for ( id in confidence ) {
@ -349,9 +399,7 @@ var wappalyzer = (function() {
confidence = apps[app].confidence; confidence = apps[app].confidence;
// Per URL // Per URL
if ( !w.detected[url].hasOwnProperty(app)) { w.detected[url][app] = apps[app];
w.detected[url][app] = new Application();
}
for ( id in confidence ) { for ( id in confidence ) {
w.detected[url][app].confidence[id] = confidence[id]; w.detected[url][app].confidence[id] = confidence[id];

@ -12,38 +12,82 @@ var wappalyzer = (function() {
/** /**
* Application class * Application class
*/ */
var Application = function(detected) { var Application = function(app, detected) {
this.confidence = {}; var self = this;
this.confidenceTotal = 0;
this.detected = Boolean(detected); self.app = app;
this.versions = []; self.confidence = {};
self.confidenceTotal = 0;
self.detected = Boolean(detected);
self.version = '';
self.versions = [];
/** /**
* Calculate confidence total * Calculate confidence total
*/ */
this.getConfidence = function() { self.getConfidence = function() {
var total = 0; var total = 0;
for ( id in this.confidence ) { for ( id in self.confidence ) {
total += this.confidence[id]; 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() { self.getVersion = function() {
return null; 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) { self.setDetected = function(pattern, type, value, key) {
this.detected = true; 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 ) { 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) { log: function(message, type) {
if ( w.config.environment === 'dev' ) { 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 }); driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type });
} }
@ -172,7 +222,7 @@ var wappalyzer = (function() {
*/ */
analyze: function(hostname, url, data) { analyze: function(hostname, url, data) {
var var
i, j, app, type, regexMeta, regexScript, match, content, meta, header, i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version,
profiler = { profiler = {
regexCount: 0, regexCount: 0,
startTime: new Date().getTime() startTime: new Date().getTime()
@ -195,7 +245,7 @@ var wappalyzer = (function() {
} }
for ( app in w.apps ) { for ( app in w.apps ) {
apps[app] = new Application(); apps[app] = new Application(app);
for ( type in w.apps[app] ) { for ( type in w.apps[app] ) {
switch ( type ) { switch ( type ) {
@ -204,7 +254,7 @@ var wappalyzer = (function() {
profiler.regexCount ++; profiler.regexCount ++;
if ( pattern.regex.test(url) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(match[2]) ) { 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 ++; profiler.regexCount ++;
if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { 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 ++; profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type][i]) ) { 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 // Apply app confidence to implied app
if ( !apps.hasOwnProperty(implied) ) { if ( !apps.hasOwnProperty(implied) ) {
apps[implied] = new Application(true); apps[implied] = new Application(implied, true);
} }
for ( id in confidence ) { for ( id in confidence ) {
@ -349,9 +399,7 @@ var wappalyzer = (function() {
confidence = apps[app].confidence; confidence = apps[app].confidence;
// Per URL // Per URL
if ( !w.detected[url].hasOwnProperty(app)) { w.detected[url][app] = apps[app];
w.detected[url][app] = new Application();
}
for ( id in confidence ) { for ( id in confidence ) {
w.detected[url][app].confidence[id] = confidence[id]; w.detected[url][app].confidence[id] = confidence[id];

@ -12,38 +12,82 @@ var wappalyzer = (function() {
/** /**
* Application class * Application class
*/ */
var Application = function(detected) { var Application = function(app, detected) {
this.confidence = {}; var self = this;
this.confidenceTotal = 0;
this.detected = Boolean(detected); self.app = app;
this.versions = []; self.confidence = {};
self.confidenceTotal = 0;
self.detected = Boolean(detected);
self.version = '';
self.versions = [];
/** /**
* Calculate confidence total * Calculate confidence total
*/ */
this.getConfidence = function() { self.getConfidence = function() {
var total = 0; var total = 0;
for ( id in this.confidence ) { for ( id in self.confidence ) {
total += this.confidence[id]; 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() { self.getVersion = function() {
return null; 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) { self.setDetected = function(pattern, type, value, key) {
this.detected = true; 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 ) { 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) { log: function(message, type) {
if ( w.config.environment === 'dev' ) { 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 }); driver('log', { message: '[wappalyzer ' + type + '] ' + message, type: type });
} }
@ -172,7 +222,7 @@ var wappalyzer = (function() {
*/ */
analyze: function(hostname, url, data) { analyze: function(hostname, url, data) {
var var
i, j, app, type, regexMeta, regexScript, match, content, meta, header, i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version,
profiler = { profiler = {
regexCount: 0, regexCount: 0,
startTime: new Date().getTime() startTime: new Date().getTime()
@ -195,7 +245,7 @@ var wappalyzer = (function() {
} }
for ( app in w.apps ) { for ( app in w.apps ) {
apps[app] = new Application(); apps[app] = new Application(app);
for ( type in w.apps[app] ) { for ( type in w.apps[app] ) {
switch ( type ) { switch ( type ) {
@ -204,7 +254,7 @@ var wappalyzer = (function() {
profiler.regexCount ++; profiler.regexCount ++;
if ( pattern.regex.test(url) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(match[2]) ) { 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 ++; profiler.regexCount ++;
if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { 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 ++; profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { 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 ++; profiler.regexCount ++;
if ( pattern.regex.test(data[type][i]) ) { 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 // Apply app confidence to implied app
if ( !apps.hasOwnProperty(implied) ) { if ( !apps.hasOwnProperty(implied) ) {
apps[implied] = new Application(true); apps[implied] = new Application(implied, true);
} }
for ( id in confidence ) { for ( id in confidence ) {
@ -349,9 +399,7 @@ var wappalyzer = (function() {
confidence = apps[app].confidence; confidence = apps[app].confidence;
// Per URL // Per URL
if ( !w.detected[url].hasOwnProperty(app)) { w.detected[url][app] = apps[app];
w.detected[url][app] = new Application();
}
for ( id in confidence ) { for ( id in confidence ) {
w.detected[url][app].confidence[id] = confidence[id]; w.detected[url][app].confidence[id] = confidence[id];

Loading…
Cancel
Save