Removed deprecated drivers in favour of PhantomJS driver

main
Elbert Alias 8 years ago
parent 14c537fbc0
commit 9e9555ecdc

12
.gitignore vendored

@ -1,19 +1,9 @@
.vagrant
build/*
drivers/npm/node_modules
drivers/npm/npm-debug.log
src/icons/converted/*
package.json
node_modules/
node_modules
npm-debug.log
Thumbs.db
ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
!.gitkeep

@ -50,10 +50,6 @@ node $WAPPALYZER_NODE_PATH/node_modules/imagemin-cli/cli.js $WAPPALYZER_ROOT/src
wappalyzer links
# Npm Module
mkdir -p $WAPPALYZER_ROOT/build/wappalyzer_npm/
cp -R $WAPPALYZER_ROOT/src/drivers/npm/* $WAPPALYZER_ROOT/build/wappalyzer_npm/
# Mozilla Firefox
echo "Building Firefox driver..."

@ -1,4 +0,0 @@
apps.json
images/icons/*.png
images/icons/*.svg
js/wappalyzer.js

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

@ -1,30 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Wappalyzer</title>
<link rel="icon" type="image/png" href="images/icon.png"/>
<script type="text/javascript" src="js/wappalyzer.js"></script>
<script type="text/javascript" src="js/driver.js"></script>
<style type="text/css">
body {
font-family: Verdana, Arial, sans-serif;
font-size: 12px;
}
#apps {
line-height: 20px;
}
#apps img {
vertical-align: middle;
}
</style>
</head>
<body>
<div id="apps"></div>
</body>
</html>

@ -1,67 +0,0 @@
(function() {
if ( wappalyzer == null ) { return };
var w = wappalyzer;
w.driver = {
/**
* Log messages to console
*/
log: function(args) {
if ( console != null ) { console[args.type](args.message) };
},
/**
* Initialize
*/
init: function() {
// Load apps.json
var xhr = new XMLHttpRequest();
xhr.open('GET', 'apps.json', true);
xhr.overrideMimeType('application/json');
xhr.onload = function() {
var json = JSON.parse(xhr.responseText);
w.categories = json.categories;
w.apps = json.apps;
window.document.addEventListener('DOMContentLoaded', function() {
w.analyze('google.com', 'http://google.com', {
html: '<script src="jquery.js"><meta name="generator" content="WordPress"/>',
headers: { 'Server': 'Apache' },
env: [ 'Mootools' ]
});
});
};
xhr.send(null);
},
/**
* Display apps
*/
displayApps: function() {
var
app,
url = Object.keys(w.detected)[0];
document.getElementById('apps').innerHTML = '';
for ( app in w.detected[url] ) {
document.getElementById('apps').innerHTML += '<img src="images/icons/' + w.apps[app].icon + '" width="16" height="16"/> ' + app + '<br/>';
};
},
/**
* Go to URL
*/
goToURL: function(args) {
window.open(args.url);
}
};
w.init();
})();

@ -1,14 +0,0 @@
root = true
[*]
indent_style = tab
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.{js,py}]
charset = utf-8
[*.py]
indent_style = space
indent_size = 4

@ -1,3 +0,0 @@
wappalyzer.js
apps.json
node_modules/

@ -1,5 +0,0 @@
{
"node" : true,
"browser" : "false",
"predef": []
}

@ -1,172 +0,0 @@
# Wappalyzer
## Install
Install wappalyzer from NPM with:
```bash
npm install wappalyzer
```
## Quickstart
```javascript
// load in the lib
var wappalyzer = require("wappalyzer");
// set our options
var options={
url : "http://codelanka.github.io/Presentation-Engines",
hostname:"codelanka.github.io",
debug:false
}
// detect from the url directly, library will make a request
wappalyzer.detectFromUrl(options,function (err,apps,appInfo) {
// output for the test
console.dir(apps);
console.dir(appInfo);
})
// sample data
var data = {
url: options.url,
headers: {
test: 1
},
html: '<p>HTML CONTENT OF PAGE HERE</p>'
};
// detect from content you have already
wappalyzer.detectFromHTML(options,function (err,apps,appInfo) {
// output for the test
console.dir(apps);
console.log(appInfo);
})
```
### Output from QuickStart
```javascript
// Apps
[
'CloudFlare',
'Font Awesome',
'Google Maps',
'Modernizr',
'Nginx',
'RequireJS',
'jQuery'
]
// Detailed info on links
{
CloudFlare: {
app: 'CloudFlare',
confidence: { 'headers Server /cloudflare/i': 100 },
confidenceTotal: 100,
detected: true,
excludes: [],
version: '',
versions: []
},
'Font Awesome': {
app: 'Font Awesome',
confidence: { 'html /<link[^>]* href=[^>]+font-awesome(?:\.min)?\.css/i': 100 },
confidenceTotal: 100,
detected: true,
excludes: [],
version: '',
versions: []
},
'Google Maps': {
app: 'Google Maps',
confidence: { 'script ///maps.googleapis.com/maps/api/js/i': 100 },
confidenceTotal: 100,
detected: true,
excludes: [],
version: '',
versions: []
},
'Modernizr': {
app: 'Modernizr',
confidence: { 'script /modernizr(?:-([\d.]*[\d]))?.*\.js/i': 100 },
confidenceTotal: 100,
detected: true,
excludes: [],
version: '2.6.2',
versions: [ '2.6.2' ]
},
'Nginx': {
app: 'Nginx',
confidence: { 'headers Server /nginx(?:/([\d.]+))?/i': 100 },
confidenceTotal: 100,
detected: true,
excludes: [],
version: '',
versions: []
},
'RequireJS': {
app: 'RequireJS',
confidence: { 'script /require.*\.js/i': 100 },
confidenceTotal: 100,
detected: true,
excludes: [],
version: '',
versions: []
},
'jQuery': {
app: 'jQuery',
confidence:
{ 'script //([\d.]+)/jquery(\.min)?\.js/i': 100,
'script /jquery.*\.js/i': 100 },
confidenceTotal: 100,
detected: true,
excludes: [],
version: '1.10.1',
versions: [ '1.10.1' ]
}
}
```
## Credits
### Wappalyzer Author - Elbert Alias
[Wappalyzer](https://wappalyzer.com/) is a
[cross-platform](https://github.com/AliasIO/Wappalyzer/wiki/Drivers) utility that uncovers the
technologies used on websites. It detects
[content management systems](https://wappalyzer.com/categories/cms),
[eCommerce platforms](https://wappalyzer.com/categories/ecommerce),
[web servers](https://wappalyzer.com/categories/web-servers),
[JavaScript frameworks](https://wappalyzer.com/categories/javascript-frameworks),
[analytics tools](https://wappalyzer.com/categories/analytics) and
[many more](https://wappalyzer.com/applications).
Refer to the [wiki](https://github.com/AliasIO/Wappalyzer/wiki) for
[screenshots](https://github.com/AliasIO/Wappalyzer/wiki/Screenshots), information on how to
[contribute](https://github.com/AliasIO/Wappalyzer/wiki/Contributing) and
[more](https://github.com/AliasIO/Wappalyzer/wiki/_pages).
### NPM Module
* [Pasindu De Silva](https://github.com/pasindud) - Initial version with tests
* [Johann du Toit](http://johanndutoit.net) from [Passmarked](http://passmarked.com) - Updated to support just passing data and helped publish to NPMJS
## License
*Licensed under the [GPL](https://github.com/AliasIO/Wappalyzer/blob/master/LICENSE).*
## Donations
Donate Bitcoin: 16gb4uGDAjaeRJwKVmKr2EXa8x2fmvT8EQ - *Thanks!*
![QR Code](https://wappalyzer.com/sites/default/themes/wappalyzer/images/bitcoinqrcode.png)

@ -1,11 +0,0 @@
var wappalyzer = require("./index");
var options={
url : "http://codelanka.github.io/Presentation-Engines",
hostname:"codelanka.github.io",
debug:false
}
wappalyzer.detectFromUrl(options,function (err,apps,appInfo) {
console.log(err,apps,appInfo);
})

@ -1,151 +0,0 @@
'use strict';
var request = require('request');
var fs = require('fs');
var path = require('path');
/**
* Does the actual detection with information passed
**/
exports.detect = function(options, data, cb) {
// run the wrapper function that will
// trigger the actual library to run
runWrappalyer(options, data, cb);
};
/**
* Wraps the detect method, just kept to reuse old method names
* and not break anything. Although this was just stubbed out.
**/
exports.detectFromHTML = function(options, data, cb) {
// run the detect method
exports.detect(options, data, cb);
};
/**
* Do a actual request for the body & headers, then
* run through detection
**/
exports.detectFromUrl = function(options, cb) {
// ensure options and url were
if(!options || !options.url) {
// send back a error ...
cb(new Error("\"url\" is a required option to run"
+ " wappalyzer and get the page content"))
} else {
// local variables to
var url = options.url;
// get the body content from the url
getHTMLFromUrl(url, function(err, data) {
// check for error or if we got no data back
if (err || data === null) {
// handle the error and don't do anything else ..
cb(err, null);
} else {
// run actual detection
exports.detect(options, data, cb);
}
});
}
};
function getHTMLFromUrl(url, cb) {
request(url, function(error, response, body) {
if (!error && response.statusCode == 200) {
var data = {
html: body,
url: url,
headers: response.headers
};
cb(null, data);
} else {
cb(error, null);
}
});
}
function getAppsJson(cb) {
// depending on evironment select a direction to the path
var appsFileStr = path.resolve(__dirname, './apps.json');
// handle the environment variable if it's there
if(process.env.NODE_ENV == 'testing') {
// set the apps.json to testing stage
appsFileStr = path.resolve(__dirname, '../../apps.json');
}
// read in the file
fs.readFile(appsFileStr, 'utf8', function(err, data) {
if (err) throw err;
return cb(null, JSON.parse(data));
});
}
function runWrappalyer(options, data, cb) {
var debug = options.debug || false;
// according to environment check it
var wappalyzer = null;
// change depending on the environment
if( process.env.NODE_ENV == 'testing' ) {
wappalyzer = require('../../wappalyzer').wappalyzer;
} else {
wappalyzer = require('./wappalyzer').wappalyzer;
}
getAppsJson(function(err, apps) {
var w = wappalyzer;
w.driver = {
log: function(args) {
if (debug) {
console.log(args.message);
}
},
init: function() {
w.categories = apps.categories;
w.apps = apps.apps;
},
displayApps: function() {
var app, url = Object.keys(w.detected)[0];
var detectedApps = [];
for (app in w.detected[url]) {
detectedApps.push(app);
if (debug) {
console.log(app);
}
}
cb(null, detectedApps, w.detected[url]);
}
};
w.init();
w.detected = [];
w.analyze(options.hostname, options.url, data);
});
}

@ -1,39 +0,0 @@
{
"name": "wappalyzer",
"version": "2.0.3",
"description": "NPM Module that uncovers the technologies used on websites",
"main": "index.js",
"scripts": {
"test": "NODE_ENV=testing mocha -t 15000"
},
"repository": {
"type": "git",
"url": "https://github.com/AliasIO/Wappalyzer"
},
"keywords": [
"wappalyzer",
"detect",
"stack",
"technologies"
],
"contributors": [
{
"name": "Pasindu De Silva"
},
{
"name": "Johann du Toit"
}
],
"author": "Elbert Alias",
"license": "GPLv3",
"bugs": {
"url": "https://github.com/AliasIO/Wappalyzer/issues"
},
"homepage": "https://github.com/AliasIO/Wappalyzer",
"directories": {
"test": "test"
},
"dependencies": {
"request": "^2.51.0"
}
}

@ -1,20 +0,0 @@
{
"Date":"Fri, 17 Jul 2015 11:05:08 GMT",
"Content-Encoding":"gzip",
"Age":"0",
"X-Cache":"MISS",
"Connection":"keep-alive",
"Content-Length":"1940",
"Via":"1.1 varnish",
"X-Served-By":"cache-lcy1122-LCY",
"Last-Modified":"Thu, 16 Apr 2015 14:24:18 GMT",
"Server":"GitHub.com",
"X-Timer":"S1437131108.300792,VS0,VE84",
"Vary":"Accept-Encoding",
"Content-Type":"text/html; charset=utf-8",
"Access-Control-Allow-Origin":"*",
"Expires":"Fri, 17 Jul 2015 11:10:54 GMT",
"Cache-Control":"max-age=600",
"Accept-Ranges":"bytes",
"X-Cache-Hits":"0"
}

@ -1,149 +0,0 @@
<!DOCTYPE html>
<html lang="en" ng-app="presen" >
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Preso Engines | CodeLanka</title>
<!-- Bootstrap CSS -->
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<script src="//code.jquery.com/jquery.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
<link href='//fonts.googleapis.com/css?family=Ubuntu' rel='stylesheet' type='text/css'>
<link href="css/style.css" rel="stylesheet">
<script type="text/javascript">
$(function () {
"use strict";
var $bgobj = $(".ha-bg-parallax"); // assigning the object
$(window).on("scroll", function () {
var yPos = -($(window).scrollTop() / $bgobj.data('speed'));
// Put together our final background position
var coords = '100% ' + yPos + 'px';
// Move the background
$bgobj.css({ backgroundPosition: coords });
});
$('div.product-chooser').not('.disabled').find('div.product-chooser-item').on('click', function(){
$(this).parent().parent().find('div.product-chooser-item').removeClass('selected');
$(this).addClass('selected');
$(this).find('input[type="radio"]').prop("checked", true);
});
});
</script>
</head>
<body>
<div class="container-fluid">
<div>
<div class="ha-bg-parallax text-center block-marginb-none" data-type="background" data-speed="20">
<div class="ha-parallax-body">
<div class="ha-content ha-content-whitecolor">
<h1 id="headernav">Preso Engines</h1>
"Presentation Engines"
</div>
<div class="ha-parallax-divider-wrapper">
<span class="ha-diamond-divider-md img-responsive"></span>
</div>
<div class="ha-heading-parallax">By | CodeLanka</div>
</div>
</div>
<div class="container" ng-controller="presentationController">
<h2></h2>
<div class="row form-group product-chooser">
<div class="col-xs-12 col-sm-12 col-md-4 col-lg-4"
ng-repeat="presentation in presentations">
<div class="product-chooser-item">
<div class="col-xs-8 col-sm-8 col-md-12 col-lg-12">
<hr/>
<span class="title">
{{presentation.name}}
</span>
<span class="website">
<a href="{{presentation.website}}">{{presentation.website}}</a>
</span>
<span class="description">
{{presentation.description}}</span>
<input type="radio" name="product" value="mobile_desktop"
checked="checked">
<hr/>
<div class="col-xs-4 col-sm-4 col-md-4 col-lg-4 text-center">
<i class="fa fa-star"></i>
<h2>{{presentation.stargazers_count}}</h2>
</div>
<div class="col-xs-4 col-sm-4 col-md-4 col-lg-4 text-center">
<i class="fa fa-users"></i>
<h2>{{presentation.watchers_count}}</h2>
</div>
<div class="col-xs-4 col-sm-4 col-md-4 col-lg-4 text-center">
<i class="fa fa-bug"></i>
<h2>{{presentation.open_issues_count}}</h2>
</div>
<div class="clear"></div>
<hr>
<p>Github -
<a href="http://github.com/{{presentation.github}}">{{presentation.github}}</a>
</p>
<p>Demo -
<a href="{{presentation.demo}}">{{presentation.demo}}</a>
</p>
<p>License - {{presentation.license}} </p>
<p>Language - {{presentation.language}} </p>
<hr/>
</div>
<div class="clear"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- jQuery -->
<!-- Bootstrap JavaScript -->
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script>
var phonecatApp = angular.module('presen', []);
phonecatApp.controller('presentationController', function ($scope,$http) {
var github = "https://api.github.com/repos/";
$http.get('data.json').
success(function(data, status, headers, config) {
$scope.presentations=data.engines;
for (var i = data.engines.length - 1; i >= 0; i--) {
$scope.presentations[i].stargazers_count=0;
$scope.presentations[i].watchers_count=0;
$scope.presentations[i].open_issues_count=0;
(function(no){
var githuburl = github+data.engines[no].github;
$http.get(githuburl)
.success(function(data, status, headers, config) {
$scope.presentations[no].stargazers_count=data.stargazers_count;
$scope.presentations[no].watchers_count=data.watchers_count;
$scope.presentations[no].open_issues_count=data.open_issues_count;
})
.error(function(data, status, headers, config) {});
}(i));
};
}).
error(function(data, status, headers, config) {});
});
</script>
</body>
</html>

@ -1,65 +0,0 @@
var assert = require("assert")
var fs = require('fs')
describe('wappalyzer', function(){
describe('detectFromUrl', function(){
it('should have the expected apps detected', function(done){
var wappalyzer = require("../index");
var expect = ['AngularJS','Font Awesome','Google Font API','Twitter Bootstrap','jQuery'];
var options={
url : "http://codelanka.github.io/Presentation-Engines",
hostname:"codelanka.github.io",
debug:false
}
wappalyzer.detectFromUrl(options,function (err,apps) {
assert.equal(expect[0], apps[0]);
assert.equal(expect[1], apps[1]);
assert.equal(expect[2], apps[2]);
assert.equal(expect[3], apps[3]);
done();
})
})
})
describe('detectFromHTML', function(){
it('should have the expected apps detected when passed raw info', function(done){
var wappalyzer = require("../index");
var expect = ['AngularJS','Font Awesome','Google Font API','Twitter Bootstrap','jQuery'];
var options={
url : "http://codelanka.github.io/Presentation-Engines",
hostname:"codelanka.github.io",
debug:false
}
var data = {
url: options.url,
headers: require('./sample.headers.json'),
html: fs.readFileSync('./test/sample.html').toString(),
headers: {
headers: {}
}
};
wappalyzer.detectFromHTML(options, data, function (err,apps) {
assert.equal(expect[0], apps[0]);
assert.equal(expect[1], apps[1]);
assert.equal(expect[2], apps[2]);
assert.equal(expect[3], apps[3]);
done();
})
})
})
})

@ -1,30 +1,31 @@
FROM phusion/baseimage
FROM ubuntu:latest
MAINTAINER Elbert Alias <elbert@alias.io>
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/archive\.ubuntu\.com/au.archive.ubuntu.com/g' /etc/apt/sources.list
RUN \
apt-get update && apt-get install -y \
bzip2 \
libfreetype6 \
libfontconfig \
nodejs \
npm \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
WORKDIR /usr/local
RUN ln -s $(which nodejs) /usr/bin/node
# PhantomJS
RUN \
mkdir phantomjs && \
curl -L https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-x86_64.tar.bz2 | tar xvjC phantomjs --strip 1
RUN mkdir /usr/local/wappalyzer
# Wappalyzer
RUN \
mkdir wappalyzer && \
curl -sSL https://github.com/AliasIO/Wappalyzer/archive/master.tar.gz | tar xzC wappalyzer --strip 1
WORKDIR /usr/local/wappalyzer
RUN wappalyzer/bin/wappalyzer-links wappalyzer
ADD apps.json .
ADD driver.js .
ADD index.js .
ADD package.json .
ADD wappalyzer.js .
WORKDIR wappalyzer/src/drivers/phantomjs
RUN npm i
ENTRYPOINT ["/usr/local/phantomjs/bin/phantomjs", "--load-images=false", "--ignore-ssl-errors=yes", "--ssl-protocol=any", "driver.js"]
ENTRYPOINT ["node", "index.js"]

@ -0,0 +1,57 @@
# Wappalyzer
[Wappalyzer](https://wappalyzer.com/) is a
[cross-platform](https://github.com/AliasIO/Wappalyzer/wiki/Drivers) utility that uncovers the
technologies used on websites. It detects
[content management systems](https://wappalyzer.com/categories/cms),
[eCommerce platforms](https://wappalyzer.com/categories/ecommerce),
[web servers](https://wappalyzer.com/categories/web-servers),
[JavaScript frameworks](https://wappalyzer.com/categories/javascript-frameworks),
[analytics tools](https://wappalyzer.com/categories/analytics) and
[many more](https://wappalyzer.com/applications).
## Installation
```shell
$ npm i wappalyzer
```
## Run from the command line
```shell
$ node index.js https://wappalyzer.com --quiet
```
## Run from a script
```javascript
const wappalyzer = require('@wappalyzer/wappalyzer');
wappalyzer.run(['https://wappalyzer.com', '--quiet'], function(stdout, stderr) {
if ( stdout ) {
process.stdout.write(stdout);
}
if ( stderr ) {
process.stderr.write(stderr);
}
});
```
## Arguments
**-v, --verbose**
Display debug output.
**-q, --quiet**
Suppress errors.
**--resource-timeout=ms**
Abort the connection after 'ms' milliseconds.

@ -163,6 +163,10 @@
}
};
page.onResourceError = function(resourceError) {
wappalyzer.log(resourceError.errorString, 'error');
};
page.open(url, function(status) {
var html, environmentVars;

@ -0,0 +1,32 @@
'use strict';
const
path = require('path'),
spawn = require('child_process').spawn,
phantomjs = require('phantomjs-prebuilt');
exports.run = function(args, callback) {
args.push.apply(['--web-security=no', '--load-images=false', '--ignore-ssl-errors=yes', '--ssl-protocol=any']);
var driver = phantomjs.exec('driver.js', args);
driver.stdout.on('data', (data) => {
callback(`${data}`, null);
});
driver.stderr.on('data', (data) => {
callback(null, `${data}`);
});
}
if ( !module.parent ) {
exports.run(process.argv.slice(2), function(stdout, stderr) {
if ( stdout ) {
process.stdout.write(stdout);
}
if ( stderr ) {
process.stderr.write(stderr);
}
});
}

@ -0,0 +1,21 @@
{
"name": "wappalyzer",
"description": "Uncovers the technologies used on websites",
"homepage": "https://github.com/AliasIO/Wappalyzer",
"version": "3.0.3",
"author": "Elbert Alias",
"license": "GPL-3.0",
"repository": {
"type": "git",
"url": "https://github.com/AliasIO/Wappalyzer"
},
"main": "index.js",
"files": [
"apps.json",
"driver.js",
"wappalyzer.js"
],
"dependencies": {
"phantomjs-prebuilt": "*"
}
}

@ -1,2 +0,0 @@
js/wappalyzer.js
apps.json

@ -1,193 +0,0 @@
<?php
class Wappalyzer
{
public
$debug = false,
$curlUserAgent = 'Mozilla/5.0 (X11; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1',
$curlFollowLocation = true,
$curlTimeout = 5,
$curlMaxRedirects = 3
;
protected
$v8,
$apps,
$categories
;
/**
* Constructor
*/
public function __construct($url)
{
chdir(dirname(__FILE__));
$this->v8 = new V8Js();
$this->url = $url;
$json = json_decode(file_get_contents('apps.json'));
$this->apps = $json->apps;
$this->categories = $json->categories;
}
/**
* Analyze a website
* @param string $url
*/
public function analyze()
{
try {
$this->load(array('wappalyzer.js', 'driver.js'));
$result = $this->curl($this->url);
//$env = $this->executeScripts($result);
$json = json_encode(array(
'host' => $result->host,
'url' => $result->url,
'html' => $result->html,
'headers' => $result->headers,
//'env' => $env
));
$result = $this->v8->executeString('
w.apps = ' . json_encode($this->apps) . ';
w.categories = ' . json_encode($this->categories) . ';
w.driver.debug = ' . ( $this->debug ? 'true' : 'false' ) . ';
w.driver.data = ' . $json . ';
w.driver.init();
');
return json_decode($result);
} catch ( V8JsException $e ) {
throw new WappalyzerException('JavaScript error: ' . $e->getMessage());
}
}
/**
* Load and execute one or more JavaScript files
* @param mixed $files
*/
protected function load($files)
{
if ( !is_array($files) ) {
$files = array($files);
}
foreach ( $files as $file ) {
$this->v8->executeString(file_get_contents('js/' . $file), $file);
}
}
/**
* Perform a cURL request
* @param string $url
*/
protected function curl($url)
{
if ( $this->debug ) {
echo 'cURL request: ' . $url . "\n";
}
$ch = curl_init($url);
curl_setopt_array($ch, array(
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => $this->curlFollowLocation,
CURLOPT_MAXREDIRS => $this->curlMaxRedirects,
CURLOPT_TIMEOUT => $this->curlTimeout,
CURLOPT_USERAGENT => $this->curlUserAgent
));
$response = curl_exec($ch);
if ( curl_errno($ch) !== 0 ) {
throw new WappalyzerException('cURL error: ' . curl_error($ch));
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ( $httpCode != 200 ) {
throw new WappalyzerException('cURL request returned HTTP code ' . $httpCode);
}
$result = new stdClass();
$result->url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
$result->host = parse_url($result->url, PHP_URL_HOST);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$result->html = substr($response, $headerSize);
$result->html = mb_check_encoding($result->html, 'UTF-8') ? $result->html : utf8_encode($result->html);
$headers = trim(substr($response, 0, $headerSize));
$headers = preg_split('/^\s*$/m', $headers);
$headers = end($headers);
$lines = array_slice(explode("\n", $headers), 1);
foreach ( $lines as $line ) {
if ( strpos(trim($line), ': ') !== false ) {
list($key, $value) = explode(': ', trim($line, "\r"));
$result->headers[strtolower($key)] = $value;
}
}
return $result;
}
/**
*
*/
protected function executeScripts($page)
{
preg_match_all('/<script[^>]+src=("|\')(.+?)\1/i', $page->html, $matches);
if ( $urls = $matches[2] ) {
foreach ( $urls as $url ) {
if ( !preg_match('/^https?:\/\//', $url) ) {
$url = $page->url . '/' . $url;
}
try {
$result = $this->curl($url);
} catch ( WappalyzerException $e ) {
if ( $this->debug ) echo $e->getMessage() . "\n";
continue;
}
$v8 = new V8Js();
try {
$v8->executeString('
var
document = {},
window = { document: document }
;
');
$v8->executeString($result->html, $url);
$result = $v8->executeString('Object.keys(window);');
var_dump($result);
} catch ( V8JsException $e ) {
if ( $this->debug ) echo "\n", print_r($e->getJsTrace()), "\n\n";
continue;
}
}
}
}
}

@ -1,4 +0,0 @@
<?php
class WappalyzerException extends Exception
{ }

@ -1,36 +0,0 @@
<?php
require('WappalyzerException.php');
require('Wappalyzer.php');
try {
if ( php_sapi_name() !== 'cli' ) {
exit('Run me from the command line');
}
$url = !empty($argv[1]) ? $argv[1] : '';
if ( !$url ) {
echo "Usage: php {$argv[0]} <url>\n";
exit(0);
}
$wappalyzer = new Wappalyzer($url);
$detectedApps = $wappalyzer->analyze();
if ( $detectedApps ) {
foreach ( $detectedApps as $detectedApp => $data ) {
echo $detectedApp . ', ' . $data->version . ', ', $data->confidence . '%, ', implode(', ', $data->categories) . "\n";
}
} else {
echo "No applications detected\n";
}
exit(0);
} catch ( Exception $e ) {
echo $e->getMessage() . "\n";
exit(1);
}

@ -1,46 +0,0 @@
var w = wappalyzer;
w.driver = {
debug: false,
data: {},
timeout: 5000,
/**
* Log messages to console
*/
log: function(args) {
if ( w.driver.debug ) { print(args.type + ': ' + args.message + "\n"); }
},
/**
* 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
});
for ( app in w.detected[w.driver.data.url] ) {
apps[app] = {
categories: [],
confidence: w.detected[w.driver.data.url][app].confidenceTotal,
version: w.detected[w.driver.data.url][app].version
};
w.apps[app].cats.forEach(function(cat) {
apps[app].categories.push(w.categories[cat]);
});
};
return JSON.stringify(apps);
},
/**
* Dummy
*/
displayApps: function() {
}
};

@ -1,2 +0,0 @@
js/wappalyzer.js
apps.json

@ -1,59 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import PyV8
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
from urlparse import urlparse
try:
import json
except ImportError:
import simplejson as json
class Wappalyzer(object):
def __init__(self, url):
self.file_dir = os.path.dirname(__file__)
f = open(os.path.join(self.file_dir, 'apps.json'))
data = json.loads(f.read())
f.close()
self.categories = data['categories']
self.apps = data['apps']
self.url = url
def analyze(self):
ctxt = PyV8.JSContext()
ctxt.enter()
f1 = open(os.path.join(self.file_dir, 'js/wappalyzer.js'))
f2 = open(os.path.join(self.file_dir, '../php/js/driver.js'))
ctxt.eval(f1.read())
ctxt.eval(f2.read())
f1.close()
f2.close()
host = urlparse(self.url).hostname
response = requests.get(self.url, verify=False)
html = response.text
headers = dict(response.headers)
data = {'host': host, 'url': self.url, 'html': html, 'headers': headers}
apps = json.dumps(self.apps)
categories = json.dumps(self.categories)
return ctxt.eval("w.apps = %s; w.categories = %s; w.driver.data = %s; w.driver.init();" % (apps, categories, json.dumps(data)))
if __name__ == '__main__':
try:
w = Wappalyzer(sys.argv[1])
print w.analyze()
except IndexError:
print ('Usage: python %s <url>' % sys.argv[0])

@ -1,2 +0,0 @@
js/wappalyzer.js
apps.json

@ -1,46 +0,0 @@
var w = wappalyzer;
w.driver = {
debug: false,
data: {},
timeout: 5000,
/**
* Log messages to console
*/
log: function(args) {
if ( w.driver.debug ) { print(args.type + ': ' + args.message + "\n"); }
},
/**
* 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
});
for ( app in w.detected[w.driver.data.url] ) {
apps[app] = {
categories: [],
confidence: w.detected[w.driver.data.url][app].confidenceTotal,
version: w.detected[w.driver.data.url][app].version
};
w.apps[app].cats.forEach(function(cat) {
apps[app].categories.push(w.categories[cat]);
});
};
return JSON.stringify(apps);
},
/**
* Dummy
*/
displayApps: function() {
}
};

@ -1,43 +0,0 @@
#!/usr/bin/env ruby
require 'net/http'
require 'v8'
require 'json'
require 'openssl'
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
Encoding.default_external = Encoding::UTF_8
class Wappalyzer
def initialize
@realdir = File.dirname(File.realpath(__FILE__))
file = File.join(@realdir, 'apps.json')
@json = JSON.parse(IO.read(file))
@categories, @apps = @json['categories'], @json['apps']
end
def analyze(url)
uri, body, headers = URI(url), nil, {}
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https', :open_timeout => 5) do |http|
resp = http.get(uri.request_uri)
resp.each_header{|k,v| headers[k.downcase] = v}
body = resp.body.encode('UTF-8', :invalid => :replace, :undef => :replace)
end
cxt = V8::Context.new
cxt.load File.join(@realdir, 'js', 'wappalyzer.js')
cxt.load File.join(@realdir, 'js', 'driver.js')
data = {'host' => uri.hostname, 'url' => url, 'html' => body, 'headers' => headers}
output = cxt.eval("w.apps = #{@apps.to_json}; w.categories = #{@categories.to_json}; w.driver.data = #{data.to_json}; w.driver.init();")
JSON.load(output)
end
end
if $0 == __FILE__
url = ARGV[0]
if url
puts JSON.pretty_generate(Wappalyzer.new.analyze(ARGV[0]))
else
puts "Usage: #{__FILE__} http://example.com"
end
end