From e79c9075cdb2554cac15ca17c1db488159cadc0d Mon Sep 17 00:00:00 2001 From: Elbert Alias Date: Mon, 31 Dec 2012 15:02:24 +1100 Subject: [PATCH] Allow arrays and strings in apps.json --- .windows_zip/Download 7-Zip.hta | 98 -- drivers/bookmarklet/js/wappalyzer.js | 110 +- drivers/chrome/js/wappalyzer.js | 110 +- drivers/firefox-jetpack/lib/wappalyzer.js | 110 +- drivers/firefox/content/js/wappalyzer.js | 110 +- drivers/firefox/locale/de-DE/wappalyzer.dtd | 104 +- drivers/firefox/locale/en-US/wappalyzer.dtd | 2 +- drivers/firefox/locale/fr-FR/wappalyzer.dtd | 2 +- drivers/firefox/locale/nl-NL/wappalyzer.dtd | 102 +- drivers/html/js/wappalyzer.js | 110 +- drivers/php/js/wappalyzer.js | 110 +- share/apps.json | 1 + share/js/apps.js.deprecated | 1734 ------------------- share/js/wappalyzer.js | 110 +- 14 files changed, 519 insertions(+), 2294 deletions(-) delete mode 100644 .windows_zip/Download 7-Zip.hta delete mode 100644 share/js/apps.js.deprecated diff --git a/.windows_zip/Download 7-Zip.hta b/.windows_zip/Download 7-Zip.hta deleted file mode 100644 index b8ff9aa72..000000000 --- a/.windows_zip/Download 7-Zip.hta +++ /dev/null @@ -1,98 +0,0 @@ -

Download 7-zip (command line version)

The download will be started automatically.

Place the file in the same folder as Wappalyzer.


License | Source code - - - \ No newline at end of file diff --git a/drivers/bookmarklet/js/wappalyzer.js b/drivers/bookmarklet/js/wappalyzer.js index e61da003b..2bc0c3165 100644 --- a/drivers/bookmarklet/js/wappalyzer.js +++ b/drivers/bookmarklet/js/wappalyzer.js @@ -24,6 +24,26 @@ var wappalyzer = (function() { return w.driver[func](args); }; + /** + * Parse apps.json patterns + */ + var parse = function(patterns) { + var parsed = []; + + // Convert single patterns to an array + if ( typeof patterns === 'string' ) { + patterns = [ patterns ]; + } + + patterns.map(function(pattern) { + parsed.push({ + regex: new RegExp(pattern.replace('/', '\\\/'), 'i') // Escape slashes in regular expression + }); + }); + + return parsed; + }; + /** * Main script */ @@ -91,7 +111,7 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, j, app, confidence, type, regex, regexMeta, regexScript, match, content, meta, header, + i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, profiler = { regexCount: 0, startTime: new Date().getTime() @@ -115,7 +135,6 @@ var wappalyzer = (function() { w.detected[url] = {}; } - appLoop: for ( app in w.apps ) { // Skip if the app has already been detected if ( w.detected[url].hasOwnProperty(app) || apps.indexOf(app) !== -1 ) { @@ -129,15 +148,13 @@ var wappalyzer = (function() { switch ( type ) { case 'url': - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( regex.test(url) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( pattern.regex.test(url) ) { + apps[app] = confidence; + } + }); break; case 'html': @@ -145,15 +162,13 @@ var wappalyzer = (function() { break; } - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( regex.test(data[type]) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( pattern.regex.test(data[type]) ) { + apps[app] = confidence; + } + }); break; case 'script': @@ -161,20 +176,19 @@ var wappalyzer = (function() { break; } - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); regexScript = new RegExp(']+src=("|\')([^"\']+)', 'ig'); - profiler.regexCount ++; - - while ( match = regexScript.exec(data.html) ) { + parse(w.apps[app][type]).map(function(pattern) { profiler.regexCount ++; - if ( regex.test(match[2]) ) { - apps[app] = confidence; + while ( match = regexScript.exec(data.html) ) { + profiler.regexCount ++; - continue appLoop; + if ( pattern.regex.test(match[2]) ) { + apps[app] = confidence; + } } - } + }); break; case 'meta': @@ -193,15 +207,13 @@ var wappalyzer = (function() { if ( new RegExp('name=["\']' + meta + '["\']', 'i').test(match) ) { content = match.toString().match(/content=("|')([^"']+)("|')/i); - regex = new RegExp(w.apps[app].meta[meta].replace('/', '\\\/'), 'i'); + parse(w.apps[app].meta[meta]).map(function(pattern) { + profiler.regexCount ++; - profiler.regexCount ++; - - if ( content && content.length === 4 && regex.test(content[2]) ) { - apps[app] = confidence; - - continue appLoop; - } + if ( content && content.length === 4 && regex.test(content[2]) ) { + apps[app] = confidence; + } + }); } } } @@ -213,15 +225,13 @@ var wappalyzer = (function() { } for ( header in w.apps[app].headers ) { - regex = new RegExp(w.apps[app][type][header].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( typeof data[type][header] === 'string' && regex.test(data[type][header]) ) { - apps[app] = confidence; + parse(w.apps[app][type][header]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { + apps[app] = confidence; + } + }); } break; @@ -230,17 +240,15 @@ var wappalyzer = (function() { break; } - regex = RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - for ( i in data[type] ) { - profiler.regexCount ++; - - if ( regex.test(data[type][i]) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + for ( i in data[type] ) { + profiler.regexCount ++; - continue appLoop; + if ( pattern.regex.test(data[type][i]) ) { + apps[app] = confidence; + } } - } + }); break; } diff --git a/drivers/chrome/js/wappalyzer.js b/drivers/chrome/js/wappalyzer.js index e61da003b..2bc0c3165 100644 --- a/drivers/chrome/js/wappalyzer.js +++ b/drivers/chrome/js/wappalyzer.js @@ -24,6 +24,26 @@ var wappalyzer = (function() { return w.driver[func](args); }; + /** + * Parse apps.json patterns + */ + var parse = function(patterns) { + var parsed = []; + + // Convert single patterns to an array + if ( typeof patterns === 'string' ) { + patterns = [ patterns ]; + } + + patterns.map(function(pattern) { + parsed.push({ + regex: new RegExp(pattern.replace('/', '\\\/'), 'i') // Escape slashes in regular expression + }); + }); + + return parsed; + }; + /** * Main script */ @@ -91,7 +111,7 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, j, app, confidence, type, regex, regexMeta, regexScript, match, content, meta, header, + i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, profiler = { regexCount: 0, startTime: new Date().getTime() @@ -115,7 +135,6 @@ var wappalyzer = (function() { w.detected[url] = {}; } - appLoop: for ( app in w.apps ) { // Skip if the app has already been detected if ( w.detected[url].hasOwnProperty(app) || apps.indexOf(app) !== -1 ) { @@ -129,15 +148,13 @@ var wappalyzer = (function() { switch ( type ) { case 'url': - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( regex.test(url) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( pattern.regex.test(url) ) { + apps[app] = confidence; + } + }); break; case 'html': @@ -145,15 +162,13 @@ var wappalyzer = (function() { break; } - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( regex.test(data[type]) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( pattern.regex.test(data[type]) ) { + apps[app] = confidence; + } + }); break; case 'script': @@ -161,20 +176,19 @@ var wappalyzer = (function() { break; } - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); regexScript = new RegExp(']+src=("|\')([^"\']+)', 'ig'); - profiler.regexCount ++; - - while ( match = regexScript.exec(data.html) ) { + parse(w.apps[app][type]).map(function(pattern) { profiler.regexCount ++; - if ( regex.test(match[2]) ) { - apps[app] = confidence; + while ( match = regexScript.exec(data.html) ) { + profiler.regexCount ++; - continue appLoop; + if ( pattern.regex.test(match[2]) ) { + apps[app] = confidence; + } } - } + }); break; case 'meta': @@ -193,15 +207,13 @@ var wappalyzer = (function() { if ( new RegExp('name=["\']' + meta + '["\']', 'i').test(match) ) { content = match.toString().match(/content=("|')([^"']+)("|')/i); - regex = new RegExp(w.apps[app].meta[meta].replace('/', '\\\/'), 'i'); + parse(w.apps[app].meta[meta]).map(function(pattern) { + profiler.regexCount ++; - profiler.regexCount ++; - - if ( content && content.length === 4 && regex.test(content[2]) ) { - apps[app] = confidence; - - continue appLoop; - } + if ( content && content.length === 4 && regex.test(content[2]) ) { + apps[app] = confidence; + } + }); } } } @@ -213,15 +225,13 @@ var wappalyzer = (function() { } for ( header in w.apps[app].headers ) { - regex = new RegExp(w.apps[app][type][header].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( typeof data[type][header] === 'string' && regex.test(data[type][header]) ) { - apps[app] = confidence; + parse(w.apps[app][type][header]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { + apps[app] = confidence; + } + }); } break; @@ -230,17 +240,15 @@ var wappalyzer = (function() { break; } - regex = RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - for ( i in data[type] ) { - profiler.regexCount ++; - - if ( regex.test(data[type][i]) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + for ( i in data[type] ) { + profiler.regexCount ++; - continue appLoop; + if ( pattern.regex.test(data[type][i]) ) { + apps[app] = confidence; + } } - } + }); break; } diff --git a/drivers/firefox-jetpack/lib/wappalyzer.js b/drivers/firefox-jetpack/lib/wappalyzer.js index e61da003b..2bc0c3165 100644 --- a/drivers/firefox-jetpack/lib/wappalyzer.js +++ b/drivers/firefox-jetpack/lib/wappalyzer.js @@ -24,6 +24,26 @@ var wappalyzer = (function() { return w.driver[func](args); }; + /** + * Parse apps.json patterns + */ + var parse = function(patterns) { + var parsed = []; + + // Convert single patterns to an array + if ( typeof patterns === 'string' ) { + patterns = [ patterns ]; + } + + patterns.map(function(pattern) { + parsed.push({ + regex: new RegExp(pattern.replace('/', '\\\/'), 'i') // Escape slashes in regular expression + }); + }); + + return parsed; + }; + /** * Main script */ @@ -91,7 +111,7 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, j, app, confidence, type, regex, regexMeta, regexScript, match, content, meta, header, + i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, profiler = { regexCount: 0, startTime: new Date().getTime() @@ -115,7 +135,6 @@ var wappalyzer = (function() { w.detected[url] = {}; } - appLoop: for ( app in w.apps ) { // Skip if the app has already been detected if ( w.detected[url].hasOwnProperty(app) || apps.indexOf(app) !== -1 ) { @@ -129,15 +148,13 @@ var wappalyzer = (function() { switch ( type ) { case 'url': - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( regex.test(url) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( pattern.regex.test(url) ) { + apps[app] = confidence; + } + }); break; case 'html': @@ -145,15 +162,13 @@ var wappalyzer = (function() { break; } - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( regex.test(data[type]) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( pattern.regex.test(data[type]) ) { + apps[app] = confidence; + } + }); break; case 'script': @@ -161,20 +176,19 @@ var wappalyzer = (function() { break; } - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); regexScript = new RegExp(']+src=("|\')([^"\']+)', 'ig'); - profiler.regexCount ++; - - while ( match = regexScript.exec(data.html) ) { + parse(w.apps[app][type]).map(function(pattern) { profiler.regexCount ++; - if ( regex.test(match[2]) ) { - apps[app] = confidence; + while ( match = regexScript.exec(data.html) ) { + profiler.regexCount ++; - continue appLoop; + if ( pattern.regex.test(match[2]) ) { + apps[app] = confidence; + } } - } + }); break; case 'meta': @@ -193,15 +207,13 @@ var wappalyzer = (function() { if ( new RegExp('name=["\']' + meta + '["\']', 'i').test(match) ) { content = match.toString().match(/content=("|')([^"']+)("|')/i); - regex = new RegExp(w.apps[app].meta[meta].replace('/', '\\\/'), 'i'); + parse(w.apps[app].meta[meta]).map(function(pattern) { + profiler.regexCount ++; - profiler.regexCount ++; - - if ( content && content.length === 4 && regex.test(content[2]) ) { - apps[app] = confidence; - - continue appLoop; - } + if ( content && content.length === 4 && regex.test(content[2]) ) { + apps[app] = confidence; + } + }); } } } @@ -213,15 +225,13 @@ var wappalyzer = (function() { } for ( header in w.apps[app].headers ) { - regex = new RegExp(w.apps[app][type][header].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( typeof data[type][header] === 'string' && regex.test(data[type][header]) ) { - apps[app] = confidence; + parse(w.apps[app][type][header]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { + apps[app] = confidence; + } + }); } break; @@ -230,17 +240,15 @@ var wappalyzer = (function() { break; } - regex = RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - for ( i in data[type] ) { - profiler.regexCount ++; - - if ( regex.test(data[type][i]) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + for ( i in data[type] ) { + profiler.regexCount ++; - continue appLoop; + if ( pattern.regex.test(data[type][i]) ) { + apps[app] = confidence; + } } - } + }); break; } diff --git a/drivers/firefox/content/js/wappalyzer.js b/drivers/firefox/content/js/wappalyzer.js index e61da003b..2bc0c3165 100644 --- a/drivers/firefox/content/js/wappalyzer.js +++ b/drivers/firefox/content/js/wappalyzer.js @@ -24,6 +24,26 @@ var wappalyzer = (function() { return w.driver[func](args); }; + /** + * Parse apps.json patterns + */ + var parse = function(patterns) { + var parsed = []; + + // Convert single patterns to an array + if ( typeof patterns === 'string' ) { + patterns = [ patterns ]; + } + + patterns.map(function(pattern) { + parsed.push({ + regex: new RegExp(pattern.replace('/', '\\\/'), 'i') // Escape slashes in regular expression + }); + }); + + return parsed; + }; + /** * Main script */ @@ -91,7 +111,7 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, j, app, confidence, type, regex, regexMeta, regexScript, match, content, meta, header, + i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, profiler = { regexCount: 0, startTime: new Date().getTime() @@ -115,7 +135,6 @@ var wappalyzer = (function() { w.detected[url] = {}; } - appLoop: for ( app in w.apps ) { // Skip if the app has already been detected if ( w.detected[url].hasOwnProperty(app) || apps.indexOf(app) !== -1 ) { @@ -129,15 +148,13 @@ var wappalyzer = (function() { switch ( type ) { case 'url': - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( regex.test(url) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( pattern.regex.test(url) ) { + apps[app] = confidence; + } + }); break; case 'html': @@ -145,15 +162,13 @@ var wappalyzer = (function() { break; } - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( regex.test(data[type]) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( pattern.regex.test(data[type]) ) { + apps[app] = confidence; + } + }); break; case 'script': @@ -161,20 +176,19 @@ var wappalyzer = (function() { break; } - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); regexScript = new RegExp(']+src=("|\')([^"\']+)', 'ig'); - profiler.regexCount ++; - - while ( match = regexScript.exec(data.html) ) { + parse(w.apps[app][type]).map(function(pattern) { profiler.regexCount ++; - if ( regex.test(match[2]) ) { - apps[app] = confidence; + while ( match = regexScript.exec(data.html) ) { + profiler.regexCount ++; - continue appLoop; + if ( pattern.regex.test(match[2]) ) { + apps[app] = confidence; + } } - } + }); break; case 'meta': @@ -193,15 +207,13 @@ var wappalyzer = (function() { if ( new RegExp('name=["\']' + meta + '["\']', 'i').test(match) ) { content = match.toString().match(/content=("|')([^"']+)("|')/i); - regex = new RegExp(w.apps[app].meta[meta].replace('/', '\\\/'), 'i'); + parse(w.apps[app].meta[meta]).map(function(pattern) { + profiler.regexCount ++; - profiler.regexCount ++; - - if ( content && content.length === 4 && regex.test(content[2]) ) { - apps[app] = confidence; - - continue appLoop; - } + if ( content && content.length === 4 && regex.test(content[2]) ) { + apps[app] = confidence; + } + }); } } } @@ -213,15 +225,13 @@ var wappalyzer = (function() { } for ( header in w.apps[app].headers ) { - regex = new RegExp(w.apps[app][type][header].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( typeof data[type][header] === 'string' && regex.test(data[type][header]) ) { - apps[app] = confidence; + parse(w.apps[app][type][header]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { + apps[app] = confidence; + } + }); } break; @@ -230,17 +240,15 @@ var wappalyzer = (function() { break; } - regex = RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - for ( i in data[type] ) { - profiler.regexCount ++; - - if ( regex.test(data[type][i]) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + for ( i in data[type] ) { + profiler.regexCount ++; - continue appLoop; + if ( pattern.regex.test(data[type][i]) ) { + apps[app] = confidence; + } } - } + }); break; } diff --git a/drivers/firefox/locale/de-DE/wappalyzer.dtd b/drivers/firefox/locale/de-DE/wappalyzer.dtd index ac3088290..e5c3d6f39 100755 --- a/drivers/firefox/locale/de-DE/wappalyzer.dtd +++ b/drivers/firefox/locale/de-DE/wappalyzer.dtd @@ -1,52 +1,52 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drivers/firefox/locale/en-US/wappalyzer.dtd b/drivers/firefox/locale/en-US/wappalyzer.dtd index daf00b3b4..c6c09d7f6 100755 --- a/drivers/firefox/locale/en-US/wappalyzer.dtd +++ b/drivers/firefox/locale/en-US/wappalyzer.dtd @@ -3,7 +3,7 @@ - + diff --git a/drivers/firefox/locale/fr-FR/wappalyzer.dtd b/drivers/firefox/locale/fr-FR/wappalyzer.dtd index 5dd102713..7584838d5 100644 --- a/drivers/firefox/locale/fr-FR/wappalyzer.dtd +++ b/drivers/firefox/locale/fr-FR/wappalyzer.dtd @@ -3,7 +3,7 @@ - + diff --git a/drivers/firefox/locale/nl-NL/wappalyzer.dtd b/drivers/firefox/locale/nl-NL/wappalyzer.dtd index 30d85e3ab..82cb67d95 100755 --- a/drivers/firefox/locale/nl-NL/wappalyzer.dtd +++ b/drivers/firefox/locale/nl-NL/wappalyzer.dtd @@ -1,51 +1,51 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drivers/html/js/wappalyzer.js b/drivers/html/js/wappalyzer.js index e61da003b..2bc0c3165 100644 --- a/drivers/html/js/wappalyzer.js +++ b/drivers/html/js/wappalyzer.js @@ -24,6 +24,26 @@ var wappalyzer = (function() { return w.driver[func](args); }; + /** + * Parse apps.json patterns + */ + var parse = function(patterns) { + var parsed = []; + + // Convert single patterns to an array + if ( typeof patterns === 'string' ) { + patterns = [ patterns ]; + } + + patterns.map(function(pattern) { + parsed.push({ + regex: new RegExp(pattern.replace('/', '\\\/'), 'i') // Escape slashes in regular expression + }); + }); + + return parsed; + }; + /** * Main script */ @@ -91,7 +111,7 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, j, app, confidence, type, regex, regexMeta, regexScript, match, content, meta, header, + i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, profiler = { regexCount: 0, startTime: new Date().getTime() @@ -115,7 +135,6 @@ var wappalyzer = (function() { w.detected[url] = {}; } - appLoop: for ( app in w.apps ) { // Skip if the app has already been detected if ( w.detected[url].hasOwnProperty(app) || apps.indexOf(app) !== -1 ) { @@ -129,15 +148,13 @@ var wappalyzer = (function() { switch ( type ) { case 'url': - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( regex.test(url) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( pattern.regex.test(url) ) { + apps[app] = confidence; + } + }); break; case 'html': @@ -145,15 +162,13 @@ var wappalyzer = (function() { break; } - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( regex.test(data[type]) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( pattern.regex.test(data[type]) ) { + apps[app] = confidence; + } + }); break; case 'script': @@ -161,20 +176,19 @@ var wappalyzer = (function() { break; } - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); regexScript = new RegExp(']+src=("|\')([^"\']+)', 'ig'); - profiler.regexCount ++; - - while ( match = regexScript.exec(data.html) ) { + parse(w.apps[app][type]).map(function(pattern) { profiler.regexCount ++; - if ( regex.test(match[2]) ) { - apps[app] = confidence; + while ( match = regexScript.exec(data.html) ) { + profiler.regexCount ++; - continue appLoop; + if ( pattern.regex.test(match[2]) ) { + apps[app] = confidence; + } } - } + }); break; case 'meta': @@ -193,15 +207,13 @@ var wappalyzer = (function() { if ( new RegExp('name=["\']' + meta + '["\']', 'i').test(match) ) { content = match.toString().match(/content=("|')([^"']+)("|')/i); - regex = new RegExp(w.apps[app].meta[meta].replace('/', '\\\/'), 'i'); + parse(w.apps[app].meta[meta]).map(function(pattern) { + profiler.regexCount ++; - profiler.regexCount ++; - - if ( content && content.length === 4 && regex.test(content[2]) ) { - apps[app] = confidence; - - continue appLoop; - } + if ( content && content.length === 4 && regex.test(content[2]) ) { + apps[app] = confidence; + } + }); } } } @@ -213,15 +225,13 @@ var wappalyzer = (function() { } for ( header in w.apps[app].headers ) { - regex = new RegExp(w.apps[app][type][header].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( typeof data[type][header] === 'string' && regex.test(data[type][header]) ) { - apps[app] = confidence; + parse(w.apps[app][type][header]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { + apps[app] = confidence; + } + }); } break; @@ -230,17 +240,15 @@ var wappalyzer = (function() { break; } - regex = RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - for ( i in data[type] ) { - profiler.regexCount ++; - - if ( regex.test(data[type][i]) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + for ( i in data[type] ) { + profiler.regexCount ++; - continue appLoop; + if ( pattern.regex.test(data[type][i]) ) { + apps[app] = confidence; + } } - } + }); break; } diff --git a/drivers/php/js/wappalyzer.js b/drivers/php/js/wappalyzer.js index e61da003b..2bc0c3165 100644 --- a/drivers/php/js/wappalyzer.js +++ b/drivers/php/js/wappalyzer.js @@ -24,6 +24,26 @@ var wappalyzer = (function() { return w.driver[func](args); }; + /** + * Parse apps.json patterns + */ + var parse = function(patterns) { + var parsed = []; + + // Convert single patterns to an array + if ( typeof patterns === 'string' ) { + patterns = [ patterns ]; + } + + patterns.map(function(pattern) { + parsed.push({ + regex: new RegExp(pattern.replace('/', '\\\/'), 'i') // Escape slashes in regular expression + }); + }); + + return parsed; + }; + /** * Main script */ @@ -91,7 +111,7 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, j, app, confidence, type, regex, regexMeta, regexScript, match, content, meta, header, + i, j, app, confidence, type, regexMeta, regexScript, match, content, meta, header, profiler = { regexCount: 0, startTime: new Date().getTime() @@ -115,7 +135,6 @@ var wappalyzer = (function() { w.detected[url] = {}; } - appLoop: for ( app in w.apps ) { // Skip if the app has already been detected if ( w.detected[url].hasOwnProperty(app) || apps.indexOf(app) !== -1 ) { @@ -129,15 +148,13 @@ var wappalyzer = (function() { switch ( type ) { case 'url': - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( regex.test(url) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( pattern.regex.test(url) ) { + apps[app] = confidence; + } + }); break; case 'html': @@ -145,15 +162,13 @@ var wappalyzer = (function() { break; } - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( regex.test(data[type]) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( pattern.regex.test(data[type]) ) { + apps[app] = confidence; + } + }); break; case 'script': @@ -161,20 +176,19 @@ var wappalyzer = (function() { break; } - regex = new RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); regexScript = new RegExp(']+src=("|\')([^"\']+)', 'ig'); - profiler.regexCount ++; - - while ( match = regexScript.exec(data.html) ) { + parse(w.apps[app][type]).map(function(pattern) { profiler.regexCount ++; - if ( regex.test(match[2]) ) { - apps[app] = confidence; + while ( match = regexScript.exec(data.html) ) { + profiler.regexCount ++; - continue appLoop; + if ( pattern.regex.test(match[2]) ) { + apps[app] = confidence; + } } - } + }); break; case 'meta': @@ -193,15 +207,13 @@ var wappalyzer = (function() { if ( new RegExp('name=["\']' + meta + '["\']', 'i').test(match) ) { content = match.toString().match(/content=("|')([^"']+)("|')/i); - regex = new RegExp(w.apps[app].meta[meta].replace('/', '\\\/'), 'i'); + parse(w.apps[app].meta[meta]).map(function(pattern) { + profiler.regexCount ++; - profiler.regexCount ++; - - if ( content && content.length === 4 && regex.test(content[2]) ) { - apps[app] = confidence; - - continue appLoop; - } + if ( content && content.length === 4 && regex.test(content[2]) ) { + apps[app] = confidence; + } + }); } } } @@ -213,15 +225,13 @@ var wappalyzer = (function() { } for ( header in w.apps[app].headers ) { - regex = new RegExp(w.apps[app][type][header].replace('/', '\\\/'), 'i'); - - profiler.regexCount ++; - - if ( typeof data[type][header] === 'string' && regex.test(data[type][header]) ) { - apps[app] = confidence; + parse(w.apps[app][type][header]).map(function(pattern) { + profiler.regexCount ++; - continue appLoop; - } + if ( typeof data[type][header] === 'string' && pattern.regex.test(data[type][header]) ) { + apps[app] = confidence; + } + }); } break; @@ -230,17 +240,15 @@ var wappalyzer = (function() { break; } - regex = RegExp(w.apps[app][type].replace('/', '\\\/'), 'i'); - - for ( i in data[type] ) { - profiler.regexCount ++; - - if ( regex.test(data[type][i]) ) { - apps[app] = confidence; + parse(w.apps[app][type]).map(function(pattern) { + for ( i in data[type] ) { + profiler.regexCount ++; - continue appLoop; + if ( pattern.regex.test(data[type][i]) ) { + apps[app] = confidence; + } } - } + }); break; } diff --git a/share/apps.json b/share/apps.json index 0f84ab32d..dfa2d23a9 100644 --- a/share/apps.json +++ b/share/apps.json @@ -331,6 +331,7 @@ "Contao": { "cats": [ 1 ], "html": "(|]+(typolight|contao)\\.css)", + "meta": { "generator": "Contao" }, "implies": [ "PHP" ] }, "Contenido": { diff --git a/share/js/apps.js.deprecated b/share/js/apps.js.deprecated deleted file mode 100644 index bc4729763..000000000 --- a/share/js/apps.js.deprecated +++ /dev/null @@ -1,1734 +0,0 @@ -(function() { - //'use strict'; - - if ( wappalyzer == null ) return; - - var w = wappalyzer; - - w.categories = { - 1: 'cms', - 2: 'message-boards', - 3: 'database-managers', - 4: 'documentation-tools', - 5: 'widgets', - 6: 'web-shops', - 7: 'photo-galleries', - 8: 'wikis', - 9: 'hosting-panels', - 10: 'analytics', - 11: 'blogs', - 12: 'javascript-frameworks', - 13: 'issue-trackers', - 14: 'video-players', - 15: 'comment-systems', - 16: 'captchas', - 17: 'font-scripts', - 18: 'web-frameworks', - 19: 'miscellaneous', - 20: 'editors', - 21: 'lms', - 22: 'web-servers', - 23: 'cache-tools', - 24: 'rich-text editors', - 25: 'javascript-graphics', - 26: 'mobile-frameworks', - 27: 'programming-languages', - 28: 'operating-systems', - 29: 'search-engines', - 30: 'web-mail', - 31: 'cdn' - }; - - w.apps = { - '1C-Bitrix': { - cats: [ 1 ], - headers: { 'X-Powered-CMS': /Bitrix Site Manager/, 'Set-Cookie': /BITRIX_/i }, - html: /]+components\/bitrix|(src|href)=("|')\/bitrix\/(js|templates)/i, - script: /1c\-bitrix/i, - implies: [ 'PHP' ] - }, - '1und1': { - cats: [ 6 ], - url: /\/shop\/catalog\/browse\?sessid\=/, - implies: [ 'PHP' ] - }, - '2z Project': { - cats: [ 1 ], - meta: { 'generator': /2z project/i } - }, - 'Accessible Portal': { - cats: [ 1 ], - meta: { 'generator': /Accessible Portal/i }, - implies: [ 'PHP' ] - }, - 'AddThis': { - cats: [ 5 ], - script: /addthis\.com\/js/, - env: /^addthis$/ - }, - 'Adobe CQ5': { - cats: [ 1 ], - url: /\/etc\/designs\//i, - html: /
]* xmlns:jspwiki=/i - }, - 'Apache Tomcat': { - cats: [ 22 ], - headers: { 'Server': /Apache-Coyote/i } }, - 'Apache Traffic Server': { - cats: [ 22 ], - headers: { 'Server': /YTS/i } }, - 'Arc Forum': { - cats: [ 2 ], - html: /ping\.src = node\.href;/ - }, - 'ATG Web Commerce': { - cats: [ 6 ], - headers: { 'X-ATG-Version': /ATG/i }, - html: /<[^>]+_DARGS/ - }, - 'Atlassian Confluence': { - cats: [ 8 ], - html: /Powered by ]+banshee-php\.org/i, - implies: [ 'PHP' ] - }, - 'BIGACE': { - cats: [ 1 ], - meta: { 'generator': /BIGACE/ }, - html: /Powered by ]+BIGACE|/ - }, - 'CakePHP': { - cats: [ 18 ], - headers: { 'Set-Cookie': /cakephp=/i }, - meta: { 'application-name': /CakePHP/i }, - implies: [ 'PHP' ] - }, - 'Cargo': { - cats: [ 1 ], - meta: {'cargo_title': /.*/ }, - script: /\/cargo\./i, - html: /]+Cargo feed/, - implies: [ 'PHP' ] - }, - 'CentOS': { - cats: [ 28 ], - headers: { 'Server': /CentOS/i, 'X-Powered-By': /CentOS/i } - }, - 'CFML': { - cats: [ 27 ] - }, - 'Chameleon': { - cats: [ 1 ], - meta: { 'generator': /chameleon\-cms/i }, - implies: [ 'Apache', 'PHP' ] - }, - 'Chamilo': { - cats: [ 21 ], - meta: { 'generator': /Chamilo/i }, headers: { 'X-Powered-By': /Chamilo/i }, - implies: [ 'PHP' ] - }, - 'Chartbeat': { - cats: [ 10 ], - html: /function loadChartbeat\(\) {/i - }, - 'Cherokee': { - cats: [ 22 ], - headers: { 'Server': /Cherokee/i } }, - 'CKEditor': { - cats: [ 24 ], - env: /^CKEDITOR$/i, - implies: [ 'PHP' ] - }, - 'ClickHeat': { - cats: [ 10 ], - script: /clickheat.*\.js/i, - env: /^clickHeatBrowser$/, - implies: [ 'PHP' ] - }, - 'ClickTale': { - cats: [ 10 ], - html: /if\(typeof ClickTale(Tag)*==("|')function("|')\)/, - env: /^ClickTale/i - }, - 'Clicky': { - cats: [ 10 ], - script: /static\.getclicky\.com/, - env: /^clicky$/ - }, - 'CloudFlare': { - cats: [ 31 ], - headers: { 'Server': /cloudflare/i } - }, - 'CMS Made Simple': { - cats: [ 1 ], - meta: { 'generator': /CMS Made Simple/i }, - implies: [ 'PHP' ] - }, - 'CO2Stats': { - cats: [ 10 ], - html: /src=("|')http:\/\/www\.co2stats\.com\/propres\.php/ - }, - 'CodeIgniter': { - cats: [ 18 ], - headers: { 'Set-Cookie': /(exp_last_activity|exp_tracker|ci_session)/ }, - implies: [ 'PHP' ] - }, - 'Commerce Server': { - cats: [ 6 ], - headers: { 'COMMERCE-SERVER-SOFTWARE': /.+/ }, - implies: [ 'Microsoft ASP.NET', 'IIS', 'Windows Server' ] - }, - 'comScore': { - cats: [ 10 ], - html: /]* (id=("|')comscore("|')|scr=[^>]+comscore)/, - env: /^_?COMSCORE$/i - }, - 'Concrete5': { - cats: [ 1 ], - script: /concrete\/js\//, - meta: { 'generator': /concrete5/i }, - env: /CCM_IMAGE_PATH/, - implies: [ 'PHP' ] - }, - 'Connect': { - cats: [ 18 ], - headers: { 'X-Powered-By': /^Connect$/i }, - implies: [ 'node.js' ] - }, - 'Contao': { - cats: [ 1, 6 ], - html: /(/, - implies: [ 'PHP' ] - }, - 'Gauges': { - cats: [ 10 ], - html: /t\.src = '\/\/secure\.gaug\.es\/track\.js/, - env: /^_gauges$/ - }, - 'Gentoo' : { - cats: [ 28 ], - headers: { 'X-Powered-By': /-?gentoo/} - }, - 'Get Satisfaction': { - cats: [ 13 ], - html: /var feedback_widget = new GSFN\.feedback_widget\(feedback_widget_options\)/ - }, - 'GetSimple CMS': { - cats: [ 1 ], - meta: {'generator': /GetSimple/ }, - implies: [ 'PHP' ] - }, - 'Google Analytics': { - cats: [ 10 ], - html: /_gaq\.push\(\['_setAccount/, - script: /(\.google\-analytics\.com\/ga\.js|google-analytics\.com\/urchin\.js)/, - headers: { 'Set-Cookie': /__utma/ }, - env: /^gaGlobal$/ - }, - 'Google App Engine': { - cats: [ 22 ], - headers: { 'Server': /Google Frontend/i } - }, - 'Google Font API': { - cats: [ 17 ], - script: /googleapis.com\/.+webfont/, - html: /]* href=("|')http:\/\/fonts\.googleapis\.com/, - env: /^WebFont/ - }, - 'Google Maps': { - cats: [ 5 ], - script: /(maps\.google\.com\/maps\?file=api|maps\.google\.com\/maps\/api\/staticmap)/ - }, - 'Google Sites': { - cats: [ 1 ], - url: /sites.google.com/ - }, - 'GoStats': { - cats: [ 10 ], - env: /^_go(stats|_track)/i - }, - 'Graffiti CMS': { - cats: [ 1 ], - meta: { 'generator': /Graffiti CMS/i } - }, - 'Gravatar': { - cats: [ 19 ], - env: /^Gravatar$/ - }, - 'Gravity Insights': { - cats: [ 10 ], - html: /gravityInsightsParams\.site_guid = '/, - env: /^GravityInsights$/ - }, - 'Handlebars': { - cats: [ 12 ], - env: /^Handlebars$/ - }, - 'Hiawatha': { - cats: [ 22 ], - headers: { 'Server': /Hiawatha/i } - }, - 'Highcharts': { - cats: [ 25 ], - script: /highcharts.*\.js/, - env: /^Highcharts$/ - }, - 'Hotaru CMS': { - cats: [ 1 ], - meta: { 'generator': /Hotaru CMS/i } - }, - 'Hybris': { - cats: [ 6 ], - html: /\/sys_master\/|\/hybr\//, - headers: { 'Set-Cookie': /_hybris/ }, - implies: [ 'Java' ] - }, - 'IBM HTTP Server': { - cats: [ 22 ], - headers: { 'Server': /IBM_HTTP_Server/i } - }, - 'IBM WebSphere Portal': { - cats: [ 1 ], - headers: { 'IBM-Web2-Location': /.*/ }, - url: /\/wps\//, - implies: [ 'Java' ] - }, - 'IBM WebSphere Commerce': { - cats: [ 6 ], - url: /\/wcs\//, - implies: [ 'Java' ] - }, - 'IIS': { - cats: [ 22 ], - headers: { 'Server': /IIS/i }, - implies: [ 'Windows Server' ] - }, - 'ImpressCMS': { - cats: [ 1 ], - script: /include\/linkexternal\.js/, - meta: { 'generator': /ImpressCMS/ }, - headers: { 'X-Powered-By': /ImpressCMS/ }, - implies: [ 'PHP' ] - }, - 'ImpressPages': { - cats: [ 1 ], - meta: { 'generator': /ImpressPages/i }, - implies: [ 'PHP' ] - }, - 'Indexhibit': { - cats: [ 1 ], - html: /<(link|a href) [^>]+ndxz-studio/i, - implies: [ 'PHP', 'Apache' ] - }, - 'InstantCMS': { - cats: [ 1 ], - meta: { 'generator': /InstantCMS/i } - }, - 'Intershop': { - cats: [ 6 ], - url: /is-bin|INTERSHOP/i, - script: /is-bin|INTERSHOP/i - }, - 'IPB': { - cats: [ 2 ], - script: /jscripts\/ips_/, - env: /^IPBoard/, - html: /]+ipb_[^>]+\.css/ - }, - 'iWeb': { - cats: [ 20 ], - meta: { 'generator': /iWeb/i } - }, - 'Jalios': { - cats: [ 1 ], - meta: { 'generator': /Jalios/i } - }, - 'Java': { - cats: [ 27 ], - headers: { 'Set-Cookie': /JSESSIONID/ } - }, - 'Javascript Infovis Toolkit': { - cats: [ 25 ], - script: /jit.*\.js/, - env: /^\$jit$/ - }, - 'Jo': { - cats: [ 26, 12 ], - env: /^jo(Cache|DOM|Event)$/ - }, - 'JobberBase': { - cats: [ 19 ], - meta: { 'generator': /Jobberbase/i }, - env: /^Jobber$/ - }, - 'Joomla': { - cats: [ 1 ], - url: /option=com_/i, - meta: { 'generator': /Joomla/i }, - html: /(]+(feed|components)\/com_)/i, - headers: { 'X-Content-Encoded-By': /Joomla/ }, - env: /^(jcomments)$/i - }, - 'jqPlot': { - cats: [ 25 ], - script: /jqplot.*\.js/, - env: /^jQuery.jqplot$/ - }, - 'jQTouch': { - cats: [ 26 ], - script: /jqtouch.*\.js/i, - env:/^jQT$/ - }, - 'jQuery': { - cats: [ 12 ], - script: /jquery.*.js/, - env: /^jQuery$/ - }, - 'jQuery Mobile': { - cats: [ 26 ], - script: /jquery\.mobile.*\.js/i - }, - 'jQuery Sparklines': { - cats: [ 25 ], - script: /jquery\.sparkline.*\.js/i - }, - 'jQuery UI': { - cats: [ 12 ], - script: /jquery\-ui.*\.js/, - implies: [ 'jQuery' ] - }, - 'JS Charts': { - cats: [ 25 ], - script: /jscharts.*\.js/i, - env: /^JSChart$/ - }, - 'JTL Shop': { - cats: [ 6 ], - html: /(]+name=('|")JTLSHOP|]+ alt=("|')Powered by Mantis Bugtracker/i - }, - 'MaxSite CMS': { - cats: [ 1 ], - meta: { 'generator': /MaxSite CMS/i } - }, - 'MediaElement.js': { - cats: [ 14 ], - env: /^mejs$/ - }, - 'MediaWiki': { - cats: [ 8 ], - meta: { 'generator': /MediaWiki/i }, - html: /(]+>Powered by MediaWiki<\/a>|<[^>]+id=("|')t\-specialpages)/i - }, - 'Meebo': { - cats: [ 5 ], - html: /(