|
|
|
@ -20,6 +20,13 @@ class Driver {
|
|
|
|
|
userAgent: 'Mozilla/5.0 (compatible; Wappalyzer)',
|
|
|
|
|
}, options || {});
|
|
|
|
|
|
|
|
|
|
this.options.debug = Boolean(this.options.debug);
|
|
|
|
|
this.options.recursive = Boolean(this.options.recursive);
|
|
|
|
|
this.options.delay = this.options.recursive ? parseInt(this.options.delay, 10) : 0;
|
|
|
|
|
this.options.maxDepth = parseInt(this.options.maxDepth, 10);
|
|
|
|
|
this.options.maxUrls = parseInt(this.options.maxUrls, 10);
|
|
|
|
|
this.options.maxWait = parseInt(this.options.maxWait, 10);
|
|
|
|
|
|
|
|
|
|
this.origPageUrl = url.parse(pageUrl);
|
|
|
|
|
this.analyzedPageUrls = [];
|
|
|
|
|
this.apps = [];
|
|
|
|
@ -38,9 +45,7 @@ class Driver {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log(message, source, type) {
|
|
|
|
|
if ( Boolean(this.options.debug) ) {
|
|
|
|
|
console.log('[wappalyzer ' + type + ']', '[' + source + ']', message);
|
|
|
|
|
}
|
|
|
|
|
this.options.debug && console.log('[wappalyzer ' + type + ']', '[' + source + ']', message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
displayApps(detected) {
|
|
|
|
@ -71,7 +76,7 @@ class Driver {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fetch(pageUrl, index, depth) {
|
|
|
|
|
return new Promise(async resolve => {
|
|
|
|
|
return new Promise(resolve => {
|
|
|
|
|
// Return when the URL is a duplicate or maxUrls has been reached
|
|
|
|
|
if ( this.analyzedPageUrls.indexOf(pageUrl.href) !== -1 || this.analyzedPageUrls.length >= this.options.maxUrls ) {
|
|
|
|
|
return resolve();
|
|
|
|
@ -81,16 +86,13 @@ class Driver {
|
|
|
|
|
|
|
|
|
|
this.wappalyzer.log('depth: ' + depth + '; delay: ' + ( this.options.delay * index ) + 'ms; url: ' + pageUrl.href, 'driver');
|
|
|
|
|
|
|
|
|
|
// Be nice
|
|
|
|
|
if ( this.options.delay ) {
|
|
|
|
|
await this.sleep(this.options.delay * index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const browser = new Browser({
|
|
|
|
|
userAgent: this.options.userAgent,
|
|
|
|
|
waitDuration: this.options.maxWait + 'ms',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.sleep(this.options.delay * index)
|
|
|
|
|
.then(() => {
|
|
|
|
|
browser.visit(pageUrl.href, error => {
|
|
|
|
|
if ( !browser.resources['0'] || !browser.resources['0'].response ) {
|
|
|
|
|
this.wappalyzer.log('No response from server', 'browser', 'error');
|
|
|
|
@ -131,30 +133,29 @@ class Driver {
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async crawl(pageUrl, index = 1, depth = 1) {
|
|
|
|
|
try {
|
|
|
|
|
var links = await this.fetch(pageUrl, index, depth);
|
|
|
|
|
|
|
|
|
|
if ( this.options.recursive && depth < this.options.maxDepth && links ) {
|
|
|
|
|
links = Array.from(links).filter(link => link.hostname === this.origPageUrl.hostname);
|
|
|
|
|
|
|
|
|
|
await Promise.all(links.map(async (link, index) => {
|
|
|
|
|
link.hash = '';
|
|
|
|
|
|
|
|
|
|
return this.crawl(link, index + 1, depth + 1);
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Promise.resolve(this.apps);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return Promise.reject(error);
|
|
|
|
|
crawl(pageUrl, index = 1, depth = 1) {
|
|
|
|
|
return new Promise(resolve => {
|
|
|
|
|
this.fetch(pageUrl, index, depth)
|
|
|
|
|
.then(links => {
|
|
|
|
|
if ( links && Boolean(this.options.recursive) && depth < this.options.maxDepth ) {
|
|
|
|
|
links = Array.from(links)
|
|
|
|
|
.filter(link => link.hostname === this.origPageUrl.hostname)
|
|
|
|
|
.map(link => { link.hash = ''; return link });
|
|
|
|
|
|
|
|
|
|
return Promise.all(links.map((link, index) => this.crawl(link, index + 1, depth + 1)));
|
|
|
|
|
} else {
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.then(() => resolve(this.apps));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sleep(ms) {
|
|
|
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
|
|
|
return ms ? new Promise(resolve => setTimeout(resolve, ms)) : Promise.resolve();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|