Added confidence level

main
Elbert Alias 12 years ago
parent ecf1d1c7b6
commit 7877da87c1

@ -30,8 +30,8 @@ var wappalyzer = (function() {
var w = {
apps: null,
cats: null,
ping: {},
detected: [],
ping: { hostnames: {} },
detected: {},
config: {
environment: 'dev', // dev | live
@ -103,11 +103,11 @@ var wappalyzer = (function() {
}
if ( typeof w.detected[url] === 'undefined' ) {
w.detected[url] = [];
w.detected[url] = {};
}
var
i, app, type, regex, regexMeta, regexScript, match, content, meta, header,
i, app, confidence, type, regex, regexMeta, regexScript, match, content, meta, header,
profiler = {
regexCount: 0,
startTime: new Date().getTime()
@ -118,11 +118,15 @@ var wappalyzer = (function() {
appLoop:
for ( app in w.apps ) {
// Skip if the app has already been detected
if ( w.detected[url].indexOf(app) !== -1 || apps.indexOf(app) !== -1 ) {
if ( w.detected[url].hasOwnProperty(app) || apps.indexOf(app) !== -1 ) {
continue;
}
for ( type in w.apps[app] ) {
confidence = {};
confidence[type] = w.apps[app].hasOwnProperty('confidence') && w.apps[app].confidence.hasOwnProperty(type) ? w.apps[app].confidence[type] : 100;
switch ( type ) {
case 'url':
regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i');
@ -130,7 +134,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(url) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -146,7 +150,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -166,7 +170,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(match[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -194,7 +198,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( content && content.length === 4 && regex.test(content[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -214,7 +218,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && regex.test(data[type][header]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -232,7 +236,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type][i]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -250,9 +254,11 @@ var wappalyzer = (function() {
for ( i = 0; i < 3; i ++ ) {
for ( j in apps ) {
if ( w.apps[apps[j]] && w.apps[apps[j]].implies ) {
for ( k in w.apps[apps[j]].implies ) {
implied = w.apps[apps[j]].implies[k];
app = apps[j].app;
if ( w.apps[app] && w.apps[app].implies ) {
for ( k in w.apps[app].implies ) {
implied = w.apps[app].implies[k];
if ( !w.apps[implied] ) {
w.log('Implied application ' + implied + ' does not exist');
@ -260,45 +266,72 @@ var wappalyzer = (function() {
continue;
}
if ( w.detected[url].indexOf(implied) === -1 && apps.indexOf(implied) === -1 ) {
apps.push(implied);
if ( !w.detected[url].hasOwnProperty(implied) && apps.indexOf(implied) === -1 ) {
apps.push({ app: implied, confidence: apps[j].confidence });
}
}
}
}
}
w.log(apps.length + ' apps detected: ' + apps.join(', ') + ' on ' + url);
w.log(apps.reduce(function(reduced, app) {
var i;
for ( i in app.confidence ) {
return app.app + ' (' + app.confidence[i] + '%) ';
}
}, Object.keys(apps).length + ' apps detected: ') + 'on ' + url);
// Keep history of detected apps
var i, app, regex, regexMeta, match;
for ( i in apps ) {
app = apps[i];
app = apps[i].app;
// Per hostname
if ( /^[a-z0-9._\-]+\.[a-z]+/.test(hostname) && !/((local|dev|development|stage|staging|test|testing|demo|admin)\.|\/admin|\.local)/.test(url) ) {
if ( typeof w.ping.hostnames === 'undefined' ) {
w.ping.hostnames = {};
confidence = apps[i].confidence;
// Per URL
if ( !w.detected[url].hasOwnProperty(app)) {
w.detected[url][app] = {};
}
for ( type in confidence ) {
w.detected[url][app][type] = confidence[type];
}
if ( typeof w.ping.hostnames[hostname] === 'undefined' ) {
// Calculate confidence total
w.detected[url][app].total = 0;
for ( type in w.detected[url][app] ) {
if ( type !== 'total' ) {
w.detected[url][app].total += w.detected[url][app][type];
w.detected[url][app].total = Math.min(w.detected[url][app].total, 100);
}
}
if ( w.detected[url][app].total >= 100 ) {
// Per hostname
if ( /(www.)?((.+?)\.(([a-z]{2,3}\.)?[a-z]{2,6}))$/.test(hostname) && !/((local|dev(elopment)?|stag(e|staging)?|test(ing)?|demo(shop)?|admin)\.|\/admin|\.local)/.test(url) ) {
if ( !w.ping.hostnames.hasOwnProperty(hostname) ) {
w.ping.hostnames[hostname] = { applications: {}, meta: {} };
}
if ( typeof w.ping.hostnames[hostname].applications[app] === 'undefined' ) {
if ( !w.ping.hostnames[hostname].applications.hasOwnProperty(app) ) {
w.ping.hostnames[hostname].applications[app] = 1;
}
w.ping.hostnames[hostname].applications[app] ++;
} else {
w.log('Ignoring hostname "' + hostname + '"');
}
// Per URL
if ( w.detected[url].indexOf(app) === -1 ) { w.detected[url].push(app); }
}
}
w.log(JSON.stringify(w.detected));
// Additional information
if ( typeof w.ping.hostnames !== 'undefined' && typeof w.ping.hostnames[hostname] !== 'undefined' ) {
if ( w.ping.hostnames.hasOwnProperty(hostname) ) {
if ( typeof data.html === 'string' && data.html ) {
match = data.html.match(/<html[^>]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i);
@ -322,7 +355,7 @@ var wappalyzer = (function() {
w.log(hostname + ': ' + JSON.stringify(w.ping.hostnames[hostname]));
}
if ( typeof w.ping.hostnames === 'object' && Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
if ( Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
apps = null;
data = null;

@ -1380,8 +1380,9 @@
"cats": [ 18 ],
"script": "/assets/application-[a-z\\d]{32}/\\.js",
"meta": { "csrf-param": "authenticity_token" },
"headers": { "Server": "(mod_rails|mod_rack|Phusion\\.Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion\\.Passenger)" },
"implies": [ "Ruby" ]
"headers": { "Server": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)" },
"implies": [ "Ruby" ],
"confidence": { "script": 50, "meta": 50, "headers": 50 }
},
"S.Builder": {
"cats": [ 1 ],
@ -1581,7 +1582,7 @@
"Tumblr": {
"cats": [ 11 ],
"html": "<iframe src=\\\"[^>]+tumblr\\.com",
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/"
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/",
"headers": { "X-Tumblr-Usec": ".*" }
},
"Twilight CMS": {

@ -1380,8 +1380,9 @@
"cats": [ 18 ],
"script": "/assets/application-[a-z\\d]{32}/\\.js",
"meta": { "csrf-param": "authenticity_token" },
"headers": { "Server": "(mod_rails|mod_rack|Phusion\\.Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion\\.Passenger)" },
"implies": [ "Ruby" ]
"headers": { "Server": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)" },
"implies": [ "Ruby" ],
"confidence": { "script": 50, "meta": 50, "headers": 50 }
},
"S.Builder": {
"cats": [ 1 ],
@ -1581,7 +1582,7 @@
"Tumblr": {
"cats": [ 11 ],
"html": "<iframe src=\\\"[^>]+tumblr\\.com",
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/"
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/",
"headers": { "X-Tumblr-Usec": ".*" }
},
"Twilight CMS": {

@ -125,7 +125,7 @@
* Display apps
*/
displayApps: function() {
var count = w.detected[tab.url].length.toString();
var count = Object.keys(w.detected[tab.url]).length.toString();
if ( tabCache[tab.id] == null ) {
tabCache[tab.id] = {
@ -140,11 +140,11 @@
if ( count > 0 ) {
// Find the main application to display
var i, appName, found = false;
var i, appName, confidence, found = false;
w.driver.categoryOrder.map(function(match) {
for ( i in w.detected[tab.url] ) {
appName = w.detected[tab.url][i];
for ( appName in w.detected[tab.url] ) {
confidence = w.detected[tab.url][appName].total;
w.apps[appName].cats.map(function(cat) {
if ( cat == match && !found ) {

@ -42,6 +42,8 @@ document.addEventListener('DOMContentLoaded', function() {
},
displayApps: function() {
var appName, confidence;
chrome.tabs.getSelected(null, function(tab) {
chrome.extension.sendRequest({ id: 'get_apps', tab: tab }, function(response) {
if ( response.tabCache.analyzed.indexOf('headers') > 0 ) {
@ -55,12 +57,14 @@ document.addEventListener('DOMContentLoaded', function() {
if ( response.tabCache.count > 0 ) {
detectedApps.innerHTML = '';
response.tabCache.appsDetected.map(function(appName) {
for ( appName in response.tabCache.appsDetected ) {
confidence = response.tabCache.appsDetected[appName].total;
html =
'<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">' +
'<img src="images/icons/' + appName + '.png"/>' +
'<span class="label">' + appName + '</span>' +
'<span class="label">' + appName + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' ) + '</span>' +
'</a>';
response.apps[appName].cats.map(function(cat) {
@ -75,7 +79,7 @@ document.addEventListener('DOMContentLoaded', function() {
'</div>';
detectedApps.innerHTML = detectedApps.innerHTML + html;
});
}
}
});
});

@ -30,8 +30,8 @@ var wappalyzer = (function() {
var w = {
apps: null,
cats: null,
ping: {},
detected: [],
ping: { hostnames: {} },
detected: {},
config: {
environment: 'dev', // dev | live
@ -103,11 +103,11 @@ var wappalyzer = (function() {
}
if ( typeof w.detected[url] === 'undefined' ) {
w.detected[url] = [];
w.detected[url] = {};
}
var
i, app, type, regex, regexMeta, regexScript, match, content, meta, header,
i, app, confidence, type, regex, regexMeta, regexScript, match, content, meta, header,
profiler = {
regexCount: 0,
startTime: new Date().getTime()
@ -118,11 +118,15 @@ var wappalyzer = (function() {
appLoop:
for ( app in w.apps ) {
// Skip if the app has already been detected
if ( w.detected[url].indexOf(app) !== -1 || apps.indexOf(app) !== -1 ) {
if ( w.detected[url].hasOwnProperty(app) || apps.indexOf(app) !== -1 ) {
continue;
}
for ( type in w.apps[app] ) {
confidence = {};
confidence[type] = w.apps[app].hasOwnProperty('confidence') && w.apps[app].confidence.hasOwnProperty(type) ? w.apps[app].confidence[type] : 100;
switch ( type ) {
case 'url':
regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i');
@ -130,7 +134,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(url) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -146,7 +150,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -166,7 +170,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(match[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -194,7 +198,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( content && content.length === 4 && regex.test(content[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -214,7 +218,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && regex.test(data[type][header]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -232,7 +236,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type][i]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -250,9 +254,11 @@ var wappalyzer = (function() {
for ( i = 0; i < 3; i ++ ) {
for ( j in apps ) {
if ( w.apps[apps[j]] && w.apps[apps[j]].implies ) {
for ( k in w.apps[apps[j]].implies ) {
implied = w.apps[apps[j]].implies[k];
app = apps[j].app;
if ( w.apps[app] && w.apps[app].implies ) {
for ( k in w.apps[app].implies ) {
implied = w.apps[app].implies[k];
if ( !w.apps[implied] ) {
w.log('Implied application ' + implied + ' does not exist');
@ -260,45 +266,72 @@ var wappalyzer = (function() {
continue;
}
if ( w.detected[url].indexOf(implied) === -1 && apps.indexOf(implied) === -1 ) {
apps.push(implied);
if ( !w.detected[url].hasOwnProperty(implied) && apps.indexOf(implied) === -1 ) {
apps.push({ app: implied, confidence: apps[j].confidence });
}
}
}
}
}
w.log(apps.length + ' apps detected: ' + apps.join(', ') + ' on ' + url);
w.log(apps.reduce(function(reduced, app) {
var i;
for ( i in app.confidence ) {
return app.app + ' (' + app.confidence[i] + '%) ';
}
}, Object.keys(apps).length + ' apps detected: ') + 'on ' + url);
// Keep history of detected apps
var i, app, regex, regexMeta, match;
for ( i in apps ) {
app = apps[i];
app = apps[i].app;
// Per hostname
if ( /^[a-z0-9._\-]+\.[a-z]+/.test(hostname) && !/((local|dev|development|stage|staging|test|testing|demo|admin)\.|\/admin|\.local)/.test(url) ) {
if ( typeof w.ping.hostnames === 'undefined' ) {
w.ping.hostnames = {};
confidence = apps[i].confidence;
// Per URL
if ( !w.detected[url].hasOwnProperty(app)) {
w.detected[url][app] = {};
}
for ( type in confidence ) {
w.detected[url][app][type] = confidence[type];
}
if ( typeof w.ping.hostnames[hostname] === 'undefined' ) {
// Calculate confidence total
w.detected[url][app].total = 0;
for ( type in w.detected[url][app] ) {
if ( type !== 'total' ) {
w.detected[url][app].total += w.detected[url][app][type];
w.detected[url][app].total = Math.min(w.detected[url][app].total, 100);
}
}
if ( w.detected[url][app].total >= 100 ) {
// Per hostname
if ( /(www.)?((.+?)\.(([a-z]{2,3}\.)?[a-z]{2,6}))$/.test(hostname) && !/((local|dev(elopment)?|stag(e|staging)?|test(ing)?|demo(shop)?|admin)\.|\/admin|\.local)/.test(url) ) {
if ( !w.ping.hostnames.hasOwnProperty(hostname) ) {
w.ping.hostnames[hostname] = { applications: {}, meta: {} };
}
if ( typeof w.ping.hostnames[hostname].applications[app] === 'undefined' ) {
if ( !w.ping.hostnames[hostname].applications.hasOwnProperty(app) ) {
w.ping.hostnames[hostname].applications[app] = 1;
}
w.ping.hostnames[hostname].applications[app] ++;
} else {
w.log('Ignoring hostname "' + hostname + '"');
}
// Per URL
if ( w.detected[url].indexOf(app) === -1 ) { w.detected[url].push(app); }
}
}
w.log(JSON.stringify(w.detected));
// Additional information
if ( typeof w.ping.hostnames !== 'undefined' && typeof w.ping.hostnames[hostname] !== 'undefined' ) {
if ( w.ping.hostnames.hasOwnProperty(hostname) ) {
if ( typeof data.html === 'string' && data.html ) {
match = data.html.match(/<html[^>]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i);
@ -322,7 +355,7 @@ var wappalyzer = (function() {
w.log(hostname + ': ' + JSON.stringify(w.ping.hostnames[hostname]));
}
if ( typeof w.ping.hostnames === 'object' && Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
if ( Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
apps = null;
data = null;

@ -1380,8 +1380,9 @@
"cats": [ 18 ],
"script": "/assets/application-[a-z\\d]{32}/\\.js",
"meta": { "csrf-param": "authenticity_token" },
"headers": { "Server": "(mod_rails|mod_rack|Phusion\\.Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion\\.Passenger)" },
"implies": [ "Ruby" ]
"headers": { "Server": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)" },
"implies": [ "Ruby" ],
"confidence": { "script": 50, "meta": 50, "headers": 50 }
},
"S.Builder": {
"cats": [ 1 ],
@ -1581,7 +1582,7 @@
"Tumblr": {
"cats": [ 11 ],
"html": "<iframe src=\\\"[^>]+tumblr\\.com",
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/"
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/",
"headers": { "X-Tumblr-Usec": ".*" }
},
"Twilight CMS": {

@ -30,8 +30,8 @@ var wappalyzer = (function() {
var w = {
apps: null,
cats: null,
ping: {},
detected: [],
ping: { hostnames: {} },
detected: {},
config: {
environment: 'dev', // dev | live
@ -103,11 +103,11 @@ var wappalyzer = (function() {
}
if ( typeof w.detected[url] === 'undefined' ) {
w.detected[url] = [];
w.detected[url] = {};
}
var
i, app, type, regex, regexMeta, regexScript, match, content, meta, header,
i, app, confidence, type, regex, regexMeta, regexScript, match, content, meta, header,
profiler = {
regexCount: 0,
startTime: new Date().getTime()
@ -118,11 +118,15 @@ var wappalyzer = (function() {
appLoop:
for ( app in w.apps ) {
// Skip if the app has already been detected
if ( w.detected[url].indexOf(app) !== -1 || apps.indexOf(app) !== -1 ) {
if ( w.detected[url].hasOwnProperty(app) || apps.indexOf(app) !== -1 ) {
continue;
}
for ( type in w.apps[app] ) {
confidence = {};
confidence[type] = w.apps[app].hasOwnProperty('confidence') && w.apps[app].confidence.hasOwnProperty(type) ? w.apps[app].confidence[type] : 100;
switch ( type ) {
case 'url':
regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i');
@ -130,7 +134,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(url) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -146,7 +150,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -166,7 +170,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(match[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -194,7 +198,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( content && content.length === 4 && regex.test(content[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -214,7 +218,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && regex.test(data[type][header]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -232,7 +236,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type][i]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -250,9 +254,11 @@ var wappalyzer = (function() {
for ( i = 0; i < 3; i ++ ) {
for ( j in apps ) {
if ( w.apps[apps[j]] && w.apps[apps[j]].implies ) {
for ( k in w.apps[apps[j]].implies ) {
implied = w.apps[apps[j]].implies[k];
app = apps[j].app;
if ( w.apps[app] && w.apps[app].implies ) {
for ( k in w.apps[app].implies ) {
implied = w.apps[app].implies[k];
if ( !w.apps[implied] ) {
w.log('Implied application ' + implied + ' does not exist');
@ -260,45 +266,72 @@ var wappalyzer = (function() {
continue;
}
if ( w.detected[url].indexOf(implied) === -1 && apps.indexOf(implied) === -1 ) {
apps.push(implied);
if ( !w.detected[url].hasOwnProperty(implied) && apps.indexOf(implied) === -1 ) {
apps.push({ app: implied, confidence: apps[j].confidence });
}
}
}
}
}
w.log(apps.length + ' apps detected: ' + apps.join(', ') + ' on ' + url);
w.log(apps.reduce(function(reduced, app) {
var i;
for ( i in app.confidence ) {
return app.app + ' (' + app.confidence[i] + '%) ';
}
}, Object.keys(apps).length + ' apps detected: ') + 'on ' + url);
// Keep history of detected apps
var i, app, regex, regexMeta, match;
for ( i in apps ) {
app = apps[i];
app = apps[i].app;
// Per hostname
if ( /^[a-z0-9._\-]+\.[a-z]+/.test(hostname) && !/((local|dev|development|stage|staging|test|testing|demo|admin)\.|\/admin|\.local)/.test(url) ) {
if ( typeof w.ping.hostnames === 'undefined' ) {
w.ping.hostnames = {};
confidence = apps[i].confidence;
// Per URL
if ( !w.detected[url].hasOwnProperty(app)) {
w.detected[url][app] = {};
}
for ( type in confidence ) {
w.detected[url][app][type] = confidence[type];
}
if ( typeof w.ping.hostnames[hostname] === 'undefined' ) {
// Calculate confidence total
w.detected[url][app].total = 0;
for ( type in w.detected[url][app] ) {
if ( type !== 'total' ) {
w.detected[url][app].total += w.detected[url][app][type];
w.detected[url][app].total = Math.min(w.detected[url][app].total, 100);
}
}
if ( w.detected[url][app].total >= 100 ) {
// Per hostname
if ( /(www.)?((.+?)\.(([a-z]{2,3}\.)?[a-z]{2,6}))$/.test(hostname) && !/((local|dev(elopment)?|stag(e|staging)?|test(ing)?|demo(shop)?|admin)\.|\/admin|\.local)/.test(url) ) {
if ( !w.ping.hostnames.hasOwnProperty(hostname) ) {
w.ping.hostnames[hostname] = { applications: {}, meta: {} };
}
if ( typeof w.ping.hostnames[hostname].applications[app] === 'undefined' ) {
if ( !w.ping.hostnames[hostname].applications.hasOwnProperty(app) ) {
w.ping.hostnames[hostname].applications[app] = 1;
}
w.ping.hostnames[hostname].applications[app] ++;
} else {
w.log('Ignoring hostname "' + hostname + '"');
}
// Per URL
if ( w.detected[url].indexOf(app) === -1 ) { w.detected[url].push(app); }
}
}
w.log(JSON.stringify(w.detected));
// Additional information
if ( typeof w.ping.hostnames !== 'undefined' && typeof w.ping.hostnames[hostname] !== 'undefined' ) {
if ( w.ping.hostnames.hasOwnProperty(hostname) ) {
if ( typeof data.html === 'string' && data.html ) {
match = data.html.match(/<html[^>]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i);
@ -322,7 +355,7 @@ var wappalyzer = (function() {
w.log(hostname + ': ' + JSON.stringify(w.ping.hostnames[hostname]));
}
if ( typeof w.ping.hostnames === 'object' && Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
if ( Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
apps = null;
data = null;

@ -1380,8 +1380,9 @@
"cats": [ 18 ],
"script": "/assets/application-[a-z\\d]{32}/\\.js",
"meta": { "csrf-param": "authenticity_token" },
"headers": { "Server": "(mod_rails|mod_rack|Phusion\\.Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion\\.Passenger)" },
"implies": [ "Ruby" ]
"headers": { "Server": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)" },
"implies": [ "Ruby" ],
"confidence": { "script": 50, "meta": 50, "headers": 50 }
},
"S.Builder": {
"cats": [ 1 ],
@ -1581,7 +1582,7 @@
"Tumblr": {
"cats": [ 11 ],
"html": "<iframe src=\\\"[^>]+tumblr\\.com",
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/"
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/",
"headers": { "X-Tumblr-Usec": ".*" }
},
"Twilight CMS": {

@ -136,7 +136,7 @@
*/
displayApps: function() {
var
i, j, elements, menuItem, menuSeparator, image,
i, j, app, confidence, elements, menuItem, menuSeparator, image,
remove = [],
container = d.getElementById('wappalyzer-container'),
menu = d.getElementById('wappalyzer-applications'),
@ -145,7 +145,7 @@
if ( !container ) { return; }
if ( w.detected[url] != null && w.detected[url].length ) {
if ( w.detected[url] != null && Object.keys(w.detected[url]).length ) {
// No change
if ( w.driver.lastDisplayed === JSON.stringify(w.detected[url]) ) { return; }
} else {
@ -164,7 +164,7 @@
}
}
if ( w.detected[url] != null && w.detected[url].length ) {
if ( w.detected[url] != null && Object.keys(w.detected[url]).length ) {
if ( !prefs.getBoolPref('showIcons') ) {
image = d.createElement('image');
@ -173,7 +173,9 @@
container.appendChild(image);
}
w.detected[url].map(function(app, i) {
for ( app in w.detected[url] ) {
confidence = w.detected[url][app].total;
var j, cat, showCat, categories = [];
for ( i in w.apps[app].cats ) {
@ -189,7 +191,7 @@
menuItem.setAttribute('class', 'wappalyzer-application menuitem-iconic');
menuItem.setAttribute('image', 'chrome://wappalyzer/skin/images/icons/' + app + '.png');
menuItem.setAttribute('label', app);
menuItem.setAttribute('label', app + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' ));
menuItem.setAttribute('name', app);
menuItem.addEventListener('command', function() {
@ -228,7 +230,7 @@
break;
}
}
});
}
w.driver.lastDisplayed = JSON.stringify(w.detected[url]);
} else {

@ -30,8 +30,8 @@ var wappalyzer = (function() {
var w = {
apps: null,
cats: null,
ping: {},
detected: [],
ping: { hostnames: {} },
detected: {},
config: {
environment: 'dev', // dev | live
@ -103,11 +103,11 @@ var wappalyzer = (function() {
}
if ( typeof w.detected[url] === 'undefined' ) {
w.detected[url] = [];
w.detected[url] = {};
}
var
i, app, type, regex, regexMeta, regexScript, match, content, meta, header,
i, app, confidence, type, regex, regexMeta, regexScript, match, content, meta, header,
profiler = {
regexCount: 0,
startTime: new Date().getTime()
@ -118,11 +118,15 @@ var wappalyzer = (function() {
appLoop:
for ( app in w.apps ) {
// Skip if the app has already been detected
if ( w.detected[url].indexOf(app) !== -1 || apps.indexOf(app) !== -1 ) {
if ( w.detected[url].hasOwnProperty(app) || apps.indexOf(app) !== -1 ) {
continue;
}
for ( type in w.apps[app] ) {
confidence = {};
confidence[type] = w.apps[app].hasOwnProperty('confidence') && w.apps[app].confidence.hasOwnProperty(type) ? w.apps[app].confidence[type] : 100;
switch ( type ) {
case 'url':
regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i');
@ -130,7 +134,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(url) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -146,7 +150,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -166,7 +170,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(match[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -194,7 +198,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( content && content.length === 4 && regex.test(content[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -214,7 +218,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && regex.test(data[type][header]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -232,7 +236,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type][i]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -250,9 +254,11 @@ var wappalyzer = (function() {
for ( i = 0; i < 3; i ++ ) {
for ( j in apps ) {
if ( w.apps[apps[j]] && w.apps[apps[j]].implies ) {
for ( k in w.apps[apps[j]].implies ) {
implied = w.apps[apps[j]].implies[k];
app = apps[j].app;
if ( w.apps[app] && w.apps[app].implies ) {
for ( k in w.apps[app].implies ) {
implied = w.apps[app].implies[k];
if ( !w.apps[implied] ) {
w.log('Implied application ' + implied + ' does not exist');
@ -260,45 +266,72 @@ var wappalyzer = (function() {
continue;
}
if ( w.detected[url].indexOf(implied) === -1 && apps.indexOf(implied) === -1 ) {
apps.push(implied);
if ( !w.detected[url].hasOwnProperty(implied) && apps.indexOf(implied) === -1 ) {
apps.push({ app: implied, confidence: apps[j].confidence });
}
}
}
}
}
w.log(apps.length + ' apps detected: ' + apps.join(', ') + ' on ' + url);
w.log(apps.reduce(function(reduced, app) {
var i;
for ( i in app.confidence ) {
return app.app + ' (' + app.confidence[i] + '%) ';
}
}, Object.keys(apps).length + ' apps detected: ') + 'on ' + url);
// Keep history of detected apps
var i, app, regex, regexMeta, match;
for ( i in apps ) {
app = apps[i];
app = apps[i].app;
// Per hostname
if ( /^[a-z0-9._\-]+\.[a-z]+/.test(hostname) && !/((local|dev|development|stage|staging|test|testing|demo|admin)\.|\/admin|\.local)/.test(url) ) {
if ( typeof w.ping.hostnames === 'undefined' ) {
w.ping.hostnames = {};
confidence = apps[i].confidence;
// Per URL
if ( !w.detected[url].hasOwnProperty(app)) {
w.detected[url][app] = {};
}
for ( type in confidence ) {
w.detected[url][app][type] = confidence[type];
}
if ( typeof w.ping.hostnames[hostname] === 'undefined' ) {
// Calculate confidence total
w.detected[url][app].total = 0;
for ( type in w.detected[url][app] ) {
if ( type !== 'total' ) {
w.detected[url][app].total += w.detected[url][app][type];
w.detected[url][app].total = Math.min(w.detected[url][app].total, 100);
}
}
if ( w.detected[url][app].total >= 100 ) {
// Per hostname
if ( /(www.)?((.+?)\.(([a-z]{2,3}\.)?[a-z]{2,6}))$/.test(hostname) && !/((local|dev(elopment)?|stag(e|staging)?|test(ing)?|demo(shop)?|admin)\.|\/admin|\.local)/.test(url) ) {
if ( !w.ping.hostnames.hasOwnProperty(hostname) ) {
w.ping.hostnames[hostname] = { applications: {}, meta: {} };
}
if ( typeof w.ping.hostnames[hostname].applications[app] === 'undefined' ) {
if ( !w.ping.hostnames[hostname].applications.hasOwnProperty(app) ) {
w.ping.hostnames[hostname].applications[app] = 1;
}
w.ping.hostnames[hostname].applications[app] ++;
} else {
w.log('Ignoring hostname "' + hostname + '"');
}
// Per URL
if ( w.detected[url].indexOf(app) === -1 ) { w.detected[url].push(app); }
}
}
w.log(JSON.stringify(w.detected));
// Additional information
if ( typeof w.ping.hostnames !== 'undefined' && typeof w.ping.hostnames[hostname] !== 'undefined' ) {
if ( w.ping.hostnames.hasOwnProperty(hostname) ) {
if ( typeof data.html === 'string' && data.html ) {
match = data.html.match(/<html[^>]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i);
@ -322,7 +355,7 @@ var wappalyzer = (function() {
w.log(hostname + ': ' + JSON.stringify(w.ping.hostnames[hostname]));
}
if ( typeof w.ping.hostnames === 'object' && Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
if ( Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
apps = null;
data = null;

@ -1380,8 +1380,9 @@
"cats": [ 18 ],
"script": "/assets/application-[a-z\\d]{32}/\\.js",
"meta": { "csrf-param": "authenticity_token" },
"headers": { "Server": "(mod_rails|mod_rack|Phusion\\.Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion\\.Passenger)" },
"implies": [ "Ruby" ]
"headers": { "Server": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)" },
"implies": [ "Ruby" ],
"confidence": { "script": 50, "meta": 50, "headers": 50 }
},
"S.Builder": {
"cats": [ 1 ],
@ -1581,7 +1582,7 @@
"Tumblr": {
"cats": [ 11 ],
"html": "<iframe src=\\\"[^>]+tumblr\\.com",
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/"
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/",
"headers": { "X-Tumblr-Usec": ".*" }
},
"Twilight CMS": {

@ -30,8 +30,8 @@ var wappalyzer = (function() {
var w = {
apps: null,
cats: null,
ping: {},
detected: [],
ping: { hostnames: {} },
detected: {},
config: {
environment: 'dev', // dev | live
@ -103,11 +103,11 @@ var wappalyzer = (function() {
}
if ( typeof w.detected[url] === 'undefined' ) {
w.detected[url] = [];
w.detected[url] = {};
}
var
i, app, type, regex, regexMeta, regexScript, match, content, meta, header,
i, app, confidence, type, regex, regexMeta, regexScript, match, content, meta, header,
profiler = {
regexCount: 0,
startTime: new Date().getTime()
@ -118,11 +118,15 @@ var wappalyzer = (function() {
appLoop:
for ( app in w.apps ) {
// Skip if the app has already been detected
if ( w.detected[url].indexOf(app) !== -1 || apps.indexOf(app) !== -1 ) {
if ( w.detected[url].hasOwnProperty(app) || apps.indexOf(app) !== -1 ) {
continue;
}
for ( type in w.apps[app] ) {
confidence = {};
confidence[type] = w.apps[app].hasOwnProperty('confidence') && w.apps[app].confidence.hasOwnProperty(type) ? w.apps[app].confidence[type] : 100;
switch ( type ) {
case 'url':
regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i');
@ -130,7 +134,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(url) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -146,7 +150,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -166,7 +170,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(match[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -194,7 +198,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( content && content.length === 4 && regex.test(content[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -214,7 +218,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && regex.test(data[type][header]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -232,7 +236,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type][i]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -250,9 +254,11 @@ var wappalyzer = (function() {
for ( i = 0; i < 3; i ++ ) {
for ( j in apps ) {
if ( w.apps[apps[j]] && w.apps[apps[j]].implies ) {
for ( k in w.apps[apps[j]].implies ) {
implied = w.apps[apps[j]].implies[k];
app = apps[j].app;
if ( w.apps[app] && w.apps[app].implies ) {
for ( k in w.apps[app].implies ) {
implied = w.apps[app].implies[k];
if ( !w.apps[implied] ) {
w.log('Implied application ' + implied + ' does not exist');
@ -260,45 +266,72 @@ var wappalyzer = (function() {
continue;
}
if ( w.detected[url].indexOf(implied) === -1 && apps.indexOf(implied) === -1 ) {
apps.push(implied);
if ( !w.detected[url].hasOwnProperty(implied) && apps.indexOf(implied) === -1 ) {
apps.push({ app: implied, confidence: apps[j].confidence });
}
}
}
}
}
w.log(apps.length + ' apps detected: ' + apps.join(', ') + ' on ' + url);
w.log(apps.reduce(function(reduced, app) {
var i;
for ( i in app.confidence ) {
return app.app + ' (' + app.confidence[i] + '%) ';
}
}, Object.keys(apps).length + ' apps detected: ') + 'on ' + url);
// Keep history of detected apps
var i, app, regex, regexMeta, match;
for ( i in apps ) {
app = apps[i];
app = apps[i].app;
// Per hostname
if ( /^[a-z0-9._\-]+\.[a-z]+/.test(hostname) && !/((local|dev|development|stage|staging|test|testing|demo|admin)\.|\/admin|\.local)/.test(url) ) {
if ( typeof w.ping.hostnames === 'undefined' ) {
w.ping.hostnames = {};
confidence = apps[i].confidence;
// Per URL
if ( !w.detected[url].hasOwnProperty(app)) {
w.detected[url][app] = {};
}
for ( type in confidence ) {
w.detected[url][app][type] = confidence[type];
}
if ( typeof w.ping.hostnames[hostname] === 'undefined' ) {
// Calculate confidence total
w.detected[url][app].total = 0;
for ( type in w.detected[url][app] ) {
if ( type !== 'total' ) {
w.detected[url][app].total += w.detected[url][app][type];
w.detected[url][app].total = Math.min(w.detected[url][app].total, 100);
}
}
if ( w.detected[url][app].total >= 100 ) {
// Per hostname
if ( /(www.)?((.+?)\.(([a-z]{2,3}\.)?[a-z]{2,6}))$/.test(hostname) && !/((local|dev(elopment)?|stag(e|staging)?|test(ing)?|demo(shop)?|admin)\.|\/admin|\.local)/.test(url) ) {
if ( !w.ping.hostnames.hasOwnProperty(hostname) ) {
w.ping.hostnames[hostname] = { applications: {}, meta: {} };
}
if ( typeof w.ping.hostnames[hostname].applications[app] === 'undefined' ) {
if ( !w.ping.hostnames[hostname].applications.hasOwnProperty(app) ) {
w.ping.hostnames[hostname].applications[app] = 1;
}
w.ping.hostnames[hostname].applications[app] ++;
} else {
w.log('Ignoring hostname "' + hostname + '"');
}
// Per URL
if ( w.detected[url].indexOf(app) === -1 ) { w.detected[url].push(app); }
}
}
w.log(JSON.stringify(w.detected));
// Additional information
if ( typeof w.ping.hostnames !== 'undefined' && typeof w.ping.hostnames[hostname] !== 'undefined' ) {
if ( w.ping.hostnames.hasOwnProperty(hostname) ) {
if ( typeof data.html === 'string' && data.html ) {
match = data.html.match(/<html[^>]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i);
@ -322,7 +355,7 @@ var wappalyzer = (function() {
w.log(hostname + ': ' + JSON.stringify(w.ping.hostnames[hostname]));
}
if ( typeof w.ping.hostnames === 'object' && Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
if ( Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
apps = null;
data = null;

@ -54,7 +54,7 @@ class Wappalyzer
//'env' => $env
));
return $this->v8->executeString('
$result = $this->v8->executeString('
w.apps = ' . json_encode($this->apps) . ';
w.categories = ' . json_encode($this->categories) . ';
w.driver.debug = ' . ( $this->debug ? 'true' : 'false' ) . ';
@ -62,6 +62,8 @@ class Wappalyzer
w.driver.init();
');
return json_decode($result);
} catch ( V8JsException $e ) {
throw new WappalyzerException('JavaScript error: ' . $e->getMessage());
}

@ -1380,8 +1380,9 @@
"cats": [ 18 ],
"script": "/assets/application-[a-z\\d]{32}/\\.js",
"meta": { "csrf-param": "authenticity_token" },
"headers": { "Server": "(mod_rails|mod_rack|Phusion\\.Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion\\.Passenger)" },
"implies": [ "Ruby" ]
"headers": { "Server": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)" },
"implies": [ "Ruby" ],
"confidence": { "script": 50, "meta": 50, "headers": 50 }
},
"S.Builder": {
"cats": [ 1 ],
@ -1581,7 +1582,7 @@
"Tumblr": {
"cats": [ 11 ],
"html": "<iframe src=\\\"[^>]+tumblr\\.com",
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/"
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/",
"headers": { "X-Tumblr-Usec": ".*" }
},
"Twilight CMS": {

@ -21,7 +21,9 @@ try {
$detectedApps = $wappalyzer->analyze();
if ( $detectedApps ) {
echo implode("\n", $detectedApps) . "\n";
foreach ( $detectedApps as $detectedApp => $data ) {
echo $detectedApp . ', ' . $data->confidence . '%, ', implode(', ', $data->categories) . "\n";
}
} else {
echo "No applications detected\n";
}

@ -15,20 +15,25 @@ w.driver = {
* Initialize
*/
init: function() {
var app, apps = {};
w.analyze(w.driver.data.host, w.driver.data.url, {
html: w.driver.data.html,
headers: w.driver.data.headers
});
/* Return categories
w.detected[w.driver.data.url].map(function(app, i) {
for ( app in w.detected[w.driver.data.url] ) {
apps[app] = {
categories: [],
confidence: w.detected[w.driver.data.url][app].total
};
w.apps[app].cats.map(function(cat) {
w.detected[w.driver.data.url][i] += ' ' + w.categories[cat];
apps[app].categories.push(w.categories[cat]);
});
});
*/
};
return w.detected[w.driver.data.url];
return JSON.stringify(apps);
},
/**

@ -30,8 +30,8 @@ var wappalyzer = (function() {
var w = {
apps: null,
cats: null,
ping: {},
detected: [],
ping: { hostnames: {} },
detected: {},
config: {
environment: 'dev', // dev | live
@ -103,11 +103,11 @@ var wappalyzer = (function() {
}
if ( typeof w.detected[url] === 'undefined' ) {
w.detected[url] = [];
w.detected[url] = {};
}
var
i, app, type, regex, regexMeta, regexScript, match, content, meta, header,
i, app, confidence, type, regex, regexMeta, regexScript, match, content, meta, header,
profiler = {
regexCount: 0,
startTime: new Date().getTime()
@ -118,11 +118,15 @@ var wappalyzer = (function() {
appLoop:
for ( app in w.apps ) {
// Skip if the app has already been detected
if ( w.detected[url].indexOf(app) !== -1 || apps.indexOf(app) !== -1 ) {
if ( w.detected[url].hasOwnProperty(app) || apps.indexOf(app) !== -1 ) {
continue;
}
for ( type in w.apps[app] ) {
confidence = {};
confidence[type] = w.apps[app].hasOwnProperty('confidence') && w.apps[app].confidence.hasOwnProperty(type) ? w.apps[app].confidence[type] : 100;
switch ( type ) {
case 'url':
regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i');
@ -130,7 +134,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(url) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -146,7 +150,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -166,7 +170,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(match[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -194,7 +198,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( content && content.length === 4 && regex.test(content[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -214,7 +218,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && regex.test(data[type][header]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -232,7 +236,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type][i]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -250,9 +254,11 @@ var wappalyzer = (function() {
for ( i = 0; i < 3; i ++ ) {
for ( j in apps ) {
if ( w.apps[apps[j]] && w.apps[apps[j]].implies ) {
for ( k in w.apps[apps[j]].implies ) {
implied = w.apps[apps[j]].implies[k];
app = apps[j].app;
if ( w.apps[app] && w.apps[app].implies ) {
for ( k in w.apps[app].implies ) {
implied = w.apps[app].implies[k];
if ( !w.apps[implied] ) {
w.log('Implied application ' + implied + ' does not exist');
@ -260,45 +266,72 @@ var wappalyzer = (function() {
continue;
}
if ( w.detected[url].indexOf(implied) === -1 && apps.indexOf(implied) === -1 ) {
apps.push(implied);
if ( !w.detected[url].hasOwnProperty(implied) && apps.indexOf(implied) === -1 ) {
apps.push({ app: implied, confidence: apps[j].confidence });
}
}
}
}
}
w.log(apps.length + ' apps detected: ' + apps.join(', ') + ' on ' + url);
w.log(apps.reduce(function(reduced, app) {
var i;
for ( i in app.confidence ) {
return app.app + ' (' + app.confidence[i] + '%) ';
}
}, Object.keys(apps).length + ' apps detected: ') + 'on ' + url);
// Keep history of detected apps
var i, app, regex, regexMeta, match;
for ( i in apps ) {
app = apps[i];
app = apps[i].app;
// Per hostname
if ( /^[a-z0-9._\-]+\.[a-z]+/.test(hostname) && !/((local|dev|development|stage|staging|test|testing|demo|admin)\.|\/admin|\.local)/.test(url) ) {
if ( typeof w.ping.hostnames === 'undefined' ) {
w.ping.hostnames = {};
confidence = apps[i].confidence;
// Per URL
if ( !w.detected[url].hasOwnProperty(app)) {
w.detected[url][app] = {};
}
for ( type in confidence ) {
w.detected[url][app][type] = confidence[type];
}
if ( typeof w.ping.hostnames[hostname] === 'undefined' ) {
// Calculate confidence total
w.detected[url][app].total = 0;
for ( type in w.detected[url][app] ) {
if ( type !== 'total' ) {
w.detected[url][app].total += w.detected[url][app][type];
w.detected[url][app].total = Math.min(w.detected[url][app].total, 100);
}
}
if ( w.detected[url][app].total >= 100 ) {
// Per hostname
if ( /(www.)?((.+?)\.(([a-z]{2,3}\.)?[a-z]{2,6}))$/.test(hostname) && !/((local|dev(elopment)?|stag(e|staging)?|test(ing)?|demo(shop)?|admin)\.|\/admin|\.local)/.test(url) ) {
if ( !w.ping.hostnames.hasOwnProperty(hostname) ) {
w.ping.hostnames[hostname] = { applications: {}, meta: {} };
}
if ( typeof w.ping.hostnames[hostname].applications[app] === 'undefined' ) {
if ( !w.ping.hostnames[hostname].applications.hasOwnProperty(app) ) {
w.ping.hostnames[hostname].applications[app] = 1;
}
w.ping.hostnames[hostname].applications[app] ++;
} else {
w.log('Ignoring hostname "' + hostname + '"');
}
// Per URL
if ( w.detected[url].indexOf(app) === -1 ) { w.detected[url].push(app); }
}
}
w.log(JSON.stringify(w.detected));
// Additional information
if ( typeof w.ping.hostnames !== 'undefined' && typeof w.ping.hostnames[hostname] !== 'undefined' ) {
if ( w.ping.hostnames.hasOwnProperty(hostname) ) {
if ( typeof data.html === 'string' && data.html ) {
match = data.html.match(/<html[^>]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i);
@ -322,7 +355,7 @@ var wappalyzer = (function() {
w.log(hostname + ': ' + JSON.stringify(w.ping.hostnames[hostname]));
}
if ( typeof w.ping.hostnames === 'object' && Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
if ( Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
apps = null;
data = null;

@ -1380,8 +1380,9 @@
"cats": [ 18 ],
"script": "/assets/application-[a-z\\d]{32}/\\.js",
"meta": { "csrf-param": "authenticity_token" },
"headers": { "Server": "(mod_rails|mod_rack|Phusion\\.Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion\\.Passenger)" },
"implies": [ "Ruby" ]
"headers": { "Server": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)", "X-Powered-By": "(mod_rails|mod_rack|Phusion(\\.|_)Passenger)" },
"implies": [ "Ruby" ],
"confidence": { "script": 50, "meta": 50, "headers": 50 }
},
"S.Builder": {
"cats": [ 1 ],
@ -1581,7 +1582,7 @@
"Tumblr": {
"cats": [ 11 ],
"html": "<iframe src=\\\"[^>]+tumblr\\.com",
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/"
"url": "^https?://(www\\.)?[^/]+\\.tumblr\\.com/",
"headers": { "X-Tumblr-Usec": ".*" }
},
"Twilight CMS": {

@ -30,8 +30,8 @@ var wappalyzer = (function() {
var w = {
apps: null,
cats: null,
ping: {},
detected: [],
ping: { hostnames: {} },
detected: {},
config: {
environment: 'dev', // dev | live
@ -103,11 +103,11 @@ var wappalyzer = (function() {
}
if ( typeof w.detected[url] === 'undefined' ) {
w.detected[url] = [];
w.detected[url] = {};
}
var
i, app, type, regex, regexMeta, regexScript, match, content, meta, header,
i, app, confidence, type, regex, regexMeta, regexScript, match, content, meta, header,
profiler = {
regexCount: 0,
startTime: new Date().getTime()
@ -118,11 +118,15 @@ var wappalyzer = (function() {
appLoop:
for ( app in w.apps ) {
// Skip if the app has already been detected
if ( w.detected[url].indexOf(app) !== -1 || apps.indexOf(app) !== -1 ) {
if ( w.detected[url].hasOwnProperty(app) || apps.indexOf(app) !== -1 ) {
continue;
}
for ( type in w.apps[app] ) {
confidence = {};
confidence[type] = w.apps[app].hasOwnProperty('confidence') && w.apps[app].confidence.hasOwnProperty(type) ? w.apps[app].confidence[type] : 100;
switch ( type ) {
case 'url':
regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i');
@ -130,7 +134,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(url) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -146,7 +150,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -166,7 +170,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(match[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -194,7 +198,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( content && content.length === 4 && regex.test(content[2]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -214,7 +218,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( typeof data[type][header] === 'string' && regex.test(data[type][header]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -232,7 +236,7 @@ var wappalyzer = (function() {
profiler.regexCount ++;
if ( regex.test(data[type][i]) ) {
apps.push(app);
apps.push({ app: app, confidence: confidence });
continue appLoop;
}
@ -250,9 +254,11 @@ var wappalyzer = (function() {
for ( i = 0; i < 3; i ++ ) {
for ( j in apps ) {
if ( w.apps[apps[j]] && w.apps[apps[j]].implies ) {
for ( k in w.apps[apps[j]].implies ) {
implied = w.apps[apps[j]].implies[k];
app = apps[j].app;
if ( w.apps[app] && w.apps[app].implies ) {
for ( k in w.apps[app].implies ) {
implied = w.apps[app].implies[k];
if ( !w.apps[implied] ) {
w.log('Implied application ' + implied + ' does not exist');
@ -260,45 +266,72 @@ var wappalyzer = (function() {
continue;
}
if ( w.detected[url].indexOf(implied) === -1 && apps.indexOf(implied) === -1 ) {
apps.push(implied);
if ( !w.detected[url].hasOwnProperty(implied) && apps.indexOf(implied) === -1 ) {
apps.push({ app: implied, confidence: apps[j].confidence });
}
}
}
}
}
w.log(apps.length + ' apps detected: ' + apps.join(', ') + ' on ' + url);
w.log(apps.reduce(function(reduced, app) {
var i;
for ( i in app.confidence ) {
return app.app + ' (' + app.confidence[i] + '%) ';
}
}, Object.keys(apps).length + ' apps detected: ') + 'on ' + url);
// Keep history of detected apps
var i, app, regex, regexMeta, match;
for ( i in apps ) {
app = apps[i];
app = apps[i].app;
// Per hostname
if ( /^[a-z0-9._\-]+\.[a-z]+/.test(hostname) && !/((local|dev|development|stage|staging|test|testing|demo|admin)\.|\/admin|\.local)/.test(url) ) {
if ( typeof w.ping.hostnames === 'undefined' ) {
w.ping.hostnames = {};
confidence = apps[i].confidence;
// Per URL
if ( !w.detected[url].hasOwnProperty(app)) {
w.detected[url][app] = {};
}
for ( type in confidence ) {
w.detected[url][app][type] = confidence[type];
}
if ( typeof w.ping.hostnames[hostname] === 'undefined' ) {
// Calculate confidence total
w.detected[url][app].total = 0;
for ( type in w.detected[url][app] ) {
if ( type !== 'total' ) {
w.detected[url][app].total += w.detected[url][app][type];
w.detected[url][app].total = Math.min(w.detected[url][app].total, 100);
}
}
if ( w.detected[url][app].total >= 100 ) {
// Per hostname
if ( /(www.)?((.+?)\.(([a-z]{2,3}\.)?[a-z]{2,6}))$/.test(hostname) && !/((local|dev(elopment)?|stag(e|staging)?|test(ing)?|demo(shop)?|admin)\.|\/admin|\.local)/.test(url) ) {
if ( !w.ping.hostnames.hasOwnProperty(hostname) ) {
w.ping.hostnames[hostname] = { applications: {}, meta: {} };
}
if ( typeof w.ping.hostnames[hostname].applications[app] === 'undefined' ) {
if ( !w.ping.hostnames[hostname].applications.hasOwnProperty(app) ) {
w.ping.hostnames[hostname].applications[app] = 1;
}
w.ping.hostnames[hostname].applications[app] ++;
} else {
w.log('Ignoring hostname "' + hostname + '"');
}
// Per URL
if ( w.detected[url].indexOf(app) === -1 ) { w.detected[url].push(app); }
}
}
w.log(JSON.stringify(w.detected));
// Additional information
if ( typeof w.ping.hostnames !== 'undefined' && typeof w.ping.hostnames[hostname] !== 'undefined' ) {
if ( w.ping.hostnames.hasOwnProperty(hostname) ) {
if ( typeof data.html === 'string' && data.html ) {
match = data.html.match(/<html[^>]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i);
@ -322,7 +355,7 @@ var wappalyzer = (function() {
w.log(hostname + ': ' + JSON.stringify(w.ping.hostnames[hostname]));
}
if ( typeof w.ping.hostnames === 'object' && Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
if ( Object.keys(w.ping.hostnames).length >= 50 ) { driver('ping'); }
apps = null;
data = null;

Loading…
Cancel
Save