From 0421560970fa045f25f5380d7d46cb72eedb9c7e Mon Sep 17 00:00:00 2001 From: ormaechea Date: Thu, 14 Feb 2019 15:44:18 +0100 Subject: [PATCH 1/2] Remove double escaping and add tests --- package.json | 2 +- src/wappalyzer.js | 2 +- test/analyze.spec.js | 144 +++++++++++++++++++++++++++++++ {src => test}/wappalyzer.spec.js | 0 4 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 test/analyze.spec.js rename {src => test}/wappalyzer.spec.js (100%) diff --git a/package.json b/package.json index e7bee5930..be41133c7 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "mocha": "^5.2.0" }, "scripts": { - "test": "mocha -R spec src", + "test": "mocha -R spec ./test", "lint": "eslint src", "lint:fix": "eslint src --fix" } diff --git a/src/wappalyzer.js b/src/wappalyzer.js index a50ddb913..7a2c3e368 100644 --- a/src/wappalyzer.js +++ b/src/wappalyzer.js @@ -370,7 +370,7 @@ class Wappalyzer { attrs.string = attr; try { - attrs.regex = new RegExp(attr.replace('/', '\\/'), 'i'); // Escape slashes in regular expression + attrs.regex = new RegExp(attr.replace('/', '\/'), 'i'); // Escape slashes in regular expression } catch (error) { attrs.regex = new RegExp(); diff --git a/test/analyze.spec.js b/test/analyze.spec.js new file mode 100644 index 000000000..99cf6a516 --- /dev/null +++ b/test/analyze.spec.js @@ -0,0 +1,144 @@ +/* eslint-env mocha */ + +'use strict'; + +const assert = require('chai').assert; +const Wappalyzer = require('../src/wappalyzer'); + +describe('should analyze website elements properly', function () { + + it('should analyze html', async () => { + const html = ` + + + + Page title | Html detection + + + +

Technologies Test Page | Html detection

+ + + + + + `; + const wappalyzer = new Wappalyzer(); + wappalyzer.apps = { + "Google Tag Manager": { + "html": [ + "googletagmanager\\.com/ns\\.html[^>]+>", + "" + ] + } + }; + var applications = null; + wappalyzer.driver = { + log () {}, + displayApps (detectedMap) { + applications = detectedMap; + } + }; + + await wappalyzer.analyze({ canonical: 'example.com' }, { html }); + assert.equal(applications['Google Tag Manager'].name, 'Google Tag Manager'); + }); + + it('should analyze scripts', async () => { + const scripts = [ + 'http://www.google-analytics.com/analytics.js', + 'http://example.com/assets/js/jquery.min.js' + ]; + const wappalyzer = new Wappalyzer(); + wappalyzer.apps = { + "Google Analytics": { + "cats": [ + 10 + ], + "script": "google-analytics\\.com\\/(?:ga|urchin|(analytics))\\.js\\;version:\\1?UA:" + }, + "jQuery": { + "script": [ + "jquery(?:\\-|\\.)([\\d.]*\\d)[^/]*\\.js\\;version:\\1", + "/([\\d.]+)/jquery(?:\\.min)?\\.js\\;version:\\1", + "jquery.*\\.js(?:\\?ver(?:sion)?=([\\d.]+))?\\;version:\\1" + ] + } + }; + var applications = null; + wappalyzer.driver = { + log () {}, + displayApps (detectedMap) { + applications = detectedMap; + } + }; + + await wappalyzer.analyze({ canonical: 'example.com' }, { scripts }); + assert.equal(applications['Google Analytics'].name, 'Google Analytics'); + assert.equal(applications['jQuery'].name, 'jQuery'); + }); + + it('should analyze headers', async () => { + const headers = { + 'date': [ 'Thu, 01 Feb 2018 11:34:18 GMT' ], + 'connection': [ 'keep-alive' ], + 'x-powered-by': [ 'Express'], + 'etag': [ 'W/125-1jQLmiya7mfec43xR3Eb3pjdu64s' ], + 'content-length': [ '293' ], + 'content-type': [ 'text/html; charset=utf-8' ] + }; + const wappalyzer = new Wappalyzer(); + wappalyzer.apps = { + "Express": { + "headers": { + "X-Powered-By": "^Express$" + } + } + }; + var applications = null; + wappalyzer.driver = { + log () {}, + displayApps (detectedMap) { + applications = detectedMap; + } + }; + + await wappalyzer.analyze({ canonical: 'example.com' }, { headers }); + assert.equal(applications['Express'].name, 'Express'); + }); + + it('should analyze js globals', async () => { + const js = { + 'Moment.js': { 'moment': { '0': true } }, + 'Google Font API': { 'WebFonts': { '0': true } } + }; + const wappalyzer = new Wappalyzer(); + wappalyzer.apps = { + "Moment.js": { + "js": { + "moment": "", + "moment.version": "(.*)\\;version:\\1" + } + }, + "Google Font API": { + "js": { + "WebFonts": "" + } + } + }; + var applications = null; + wappalyzer.driver = { + log () {}, + displayApps (detectedMap) { + applications = detectedMap; + } + }; + + wappalyzer.parseJsPatterns(); + await wappalyzer.analyze({ canonical: 'example.com' }, { js }); + + assert.equal(applications['Google Font API'].name, 'Google Font API'); + assert.equal(applications['Moment.js'].name, 'Moment.js'); + }); +}); diff --git a/src/wappalyzer.spec.js b/test/wappalyzer.spec.js similarity index 100% rename from src/wappalyzer.spec.js rename to test/wappalyzer.spec.js From 0f711679d7a9a52c8b9ec637bf9ec43a754cf75b Mon Sep 17 00:00:00 2001 From: ormaechea Date: Thu, 14 Feb 2019 16:31:36 +0100 Subject: [PATCH 2/2] Keep the same project-folder structure --- package.json | 2 +- src/wappalyzer.spec.js | 278 ++++++++++++++++++++++++++++++++++++++++ test/analyze.spec.js | 144 --------------------- test/wappalyzer.spec.js | 143 --------------------- 4 files changed, 279 insertions(+), 288 deletions(-) create mode 100644 src/wappalyzer.spec.js delete mode 100644 test/analyze.spec.js delete mode 100644 test/wappalyzer.spec.js diff --git a/package.json b/package.json index be41133c7..e7bee5930 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "mocha": "^5.2.0" }, "scripts": { - "test": "mocha -R spec ./test", + "test": "mocha -R spec src", "lint": "eslint src", "lint:fix": "eslint src --fix" } diff --git a/src/wappalyzer.spec.js b/src/wappalyzer.spec.js new file mode 100644 index 000000000..f51d7fb10 --- /dev/null +++ b/src/wappalyzer.spec.js @@ -0,0 +1,278 @@ +/* eslint-env mocha */ + +const { assert, expect } = require('chai'); +const Wappalyzer = require('../src/wappalyzer'); + +const appsJson = { + appUrl: { + url: 'test', + }, + appCookies: { + cookies: { + test: 'test', + }, + }, + appUppercaseCookies: { + cookies: { + Test: 'Test', + }, + }, + appHeaders: { + headers: { + 'X-Powered-By': 'test', + }, + }, + appHtml: { + html: 'test v(\\d)\\;confidence:50\\;version:\\1', + implies: 'appImplies', + excludes: 'appExcludes', + }, + appMeta: { + meta: { + generator: 'test', + }, + }, + appScript: { + script: 'test', + }, + appJs: { + js: { + key: 'value', + }, + }, + appImplies: { + }, + appExcludes: { + html: 'test', + }, +}; + +const driverData = { + cookies: [ + { + name: 'test', + value: 'test', + domain: '', + path: '', + }, + ], + headers: { + 'x-powered-by': [ + 'test', + ], + }, + html: ' html test v1', + scripts: [ + 'test', + ], + js: { + appJs: { + key: [ + 'value', + ], + }, + }, +}; + +describe('Wappalyzer', () => { + describe('#analyze()', () => { + let apps; + + before(async () => { + const wappalyzer = new Wappalyzer(); + + wappalyzer.apps = appsJson; + + wappalyzer.parseJsPatterns(); + + wappalyzer.driver.displayApps = (detected) => { + apps = detected; + }; + + await wappalyzer.analyze({ canonical: 'test' }, driverData); + }); + + it('should identify technologies using URLs', () => { + expect(apps).to.have.any.keys('appUrl'); + }); + + it('should identify technologies using HTML', () => { + expect(apps).to.have.any.keys('appHtml'); + }); + + it('should identify technologies using meta tags', () => { + expect(apps).to.have.any.keys('appMeta'); + }); + + it('should identify technologies using script URLs', () => { + expect(apps).to.have.any.keys('appScript'); + }); + + it('should identify technologies using headers', () => { + expect(apps).to.have.any.keys('appHeaders'); + }); + + it('should identify technologies using cookies', () => { + expect(apps).to.have.any.keys('appCookies'); + }); + + it('should identify technologies using uppercase named cookies', () => { + expect(apps).to.have.any.keys('appUppercaseCookies'); + }); + + it('should identify technologies using JavaScript', () => { + expect(apps).to.have.any.keys('appJs'); + }); + + it('should return the implied technology', () => { + expect(apps).to.have.any.keys('appImplies'); + }); + + it('should not return the excluded technology', () => { + expect(apps).to.not.have.any.keys('appExcludes'); + }); + + it('should return the confidence value', () => { + assert.equal(apps.appHtml.confidenceTotal, 50); + }); + + it('should return the version number', () => { + assert.equal(apps.appHtml.version, '1'); + }); + + it('should analyze html', async () => { + const html = ` + + + + Page title | Html detection + + + +

Technologies Test Page | Html detection

+ + + + + + `; + const wappalyzer = new Wappalyzer(); + wappalyzer.apps = { + "Google Tag Manager": { + "html": [ + "googletagmanager\\.com/ns\\.html[^>]+>", + "" + ] + } + }; + var applications = null; + wappalyzer.driver = { + log () {}, + displayApps (detectedMap) { + applications = detectedMap; + } + }; + + await wappalyzer.analyze({ canonical: 'example.com' }, { html }); + assert.equal(applications['Google Tag Manager'].name, 'Google Tag Manager'); + }); + + it('should analyze scripts', async () => { + const scripts = [ + 'http://www.google-analytics.com/analytics.js', + 'http://example.com/assets/js/jquery.min.js' + ]; + const wappalyzer = new Wappalyzer(); + wappalyzer.apps = { + "Google Analytics": { + "cats": [ + 10 + ], + "script": "google-analytics\\.com\\/(?:ga|urchin|(analytics))\\.js\\;version:\\1?UA:" + }, + "jQuery": { + "script": [ + "jquery(?:\\-|\\.)([\\d.]*\\d)[^/]*\\.js\\;version:\\1", + "/([\\d.]+)/jquery(?:\\.min)?\\.js\\;version:\\1", + "jquery.*\\.js(?:\\?ver(?:sion)?=([\\d.]+))?\\;version:\\1" + ] + } + }; + var applications = null; + wappalyzer.driver = { + log () {}, + displayApps (detectedMap) { + applications = detectedMap; + } + }; + + await wappalyzer.analyze({ canonical: 'example.com' }, { scripts }); + assert.equal(applications['Google Analytics'].name, 'Google Analytics'); + assert.equal(applications['jQuery'].name, 'jQuery'); + }); + + it('should analyze headers', async () => { + const headers = { + 'date': [ 'Thu, 01 Feb 2018 11:34:18 GMT' ], + 'connection': [ 'keep-alive' ], + 'x-powered-by': [ 'Express'], + 'etag': [ 'W/125-1jQLmiya7mfec43xR3Eb3pjdu64s' ], + 'content-length': [ '293' ], + 'content-type': [ 'text/html; charset=utf-8' ] + }; + const wappalyzer = new Wappalyzer(); + wappalyzer.apps = { + "Express": { + "headers": { + "X-Powered-By": "^Express$" + } + } + }; + var applications = null; + wappalyzer.driver = { + log () {}, + displayApps (detectedMap) { + applications = detectedMap; + } + }; + + await wappalyzer.analyze({ canonical: 'example.com' }, { headers }); + assert.equal(applications['Express'].name, 'Express'); + }); + + it('should analyze js globals', async () => { + const js = { + 'Moment.js': { 'moment': { '0': true } }, + 'Google Font API': { 'WebFonts': { '0': true } } + }; + const wappalyzer = new Wappalyzer(); + wappalyzer.apps = { + "Moment.js": { + "js": { + "moment": "", + "moment.version": "(.*)\\;version:\\1" + } + }, + "Google Font API": { + "js": { + "WebFonts": "" + } + } + }; + var applications = null; + wappalyzer.driver = { + log () {}, + displayApps (detectedMap) { + applications = detectedMap; + } + }; + + wappalyzer.parseJsPatterns(); + await wappalyzer.analyze({ canonical: 'example.com' }, { js }); + + assert.equal(applications['Google Font API'].name, 'Google Font API'); + assert.equal(applications['Moment.js'].name, 'Moment.js'); + }); + }); +}); diff --git a/test/analyze.spec.js b/test/analyze.spec.js deleted file mode 100644 index 99cf6a516..000000000 --- a/test/analyze.spec.js +++ /dev/null @@ -1,144 +0,0 @@ -/* eslint-env mocha */ - -'use strict'; - -const assert = require('chai').assert; -const Wappalyzer = require('../src/wappalyzer'); - -describe('should analyze website elements properly', function () { - - it('should analyze html', async () => { - const html = ` - - - - Page title | Html detection - - - -

Technologies Test Page | Html detection

- - - - - - `; - const wappalyzer = new Wappalyzer(); - wappalyzer.apps = { - "Google Tag Manager": { - "html": [ - "googletagmanager\\.com/ns\\.html[^>]+>", - "" - ] - } - }; - var applications = null; - wappalyzer.driver = { - log () {}, - displayApps (detectedMap) { - applications = detectedMap; - } - }; - - await wappalyzer.analyze({ canonical: 'example.com' }, { html }); - assert.equal(applications['Google Tag Manager'].name, 'Google Tag Manager'); - }); - - it('should analyze scripts', async () => { - const scripts = [ - 'http://www.google-analytics.com/analytics.js', - 'http://example.com/assets/js/jquery.min.js' - ]; - const wappalyzer = new Wappalyzer(); - wappalyzer.apps = { - "Google Analytics": { - "cats": [ - 10 - ], - "script": "google-analytics\\.com\\/(?:ga|urchin|(analytics))\\.js\\;version:\\1?UA:" - }, - "jQuery": { - "script": [ - "jquery(?:\\-|\\.)([\\d.]*\\d)[^/]*\\.js\\;version:\\1", - "/([\\d.]+)/jquery(?:\\.min)?\\.js\\;version:\\1", - "jquery.*\\.js(?:\\?ver(?:sion)?=([\\d.]+))?\\;version:\\1" - ] - } - }; - var applications = null; - wappalyzer.driver = { - log () {}, - displayApps (detectedMap) { - applications = detectedMap; - } - }; - - await wappalyzer.analyze({ canonical: 'example.com' }, { scripts }); - assert.equal(applications['Google Analytics'].name, 'Google Analytics'); - assert.equal(applications['jQuery'].name, 'jQuery'); - }); - - it('should analyze headers', async () => { - const headers = { - 'date': [ 'Thu, 01 Feb 2018 11:34:18 GMT' ], - 'connection': [ 'keep-alive' ], - 'x-powered-by': [ 'Express'], - 'etag': [ 'W/125-1jQLmiya7mfec43xR3Eb3pjdu64s' ], - 'content-length': [ '293' ], - 'content-type': [ 'text/html; charset=utf-8' ] - }; - const wappalyzer = new Wappalyzer(); - wappalyzer.apps = { - "Express": { - "headers": { - "X-Powered-By": "^Express$" - } - } - }; - var applications = null; - wappalyzer.driver = { - log () {}, - displayApps (detectedMap) { - applications = detectedMap; - } - }; - - await wappalyzer.analyze({ canonical: 'example.com' }, { headers }); - assert.equal(applications['Express'].name, 'Express'); - }); - - it('should analyze js globals', async () => { - const js = { - 'Moment.js': { 'moment': { '0': true } }, - 'Google Font API': { 'WebFonts': { '0': true } } - }; - const wappalyzer = new Wappalyzer(); - wappalyzer.apps = { - "Moment.js": { - "js": { - "moment": "", - "moment.version": "(.*)\\;version:\\1" - } - }, - "Google Font API": { - "js": { - "WebFonts": "" - } - } - }; - var applications = null; - wappalyzer.driver = { - log () {}, - displayApps (detectedMap) { - applications = detectedMap; - } - }; - - wappalyzer.parseJsPatterns(); - await wappalyzer.analyze({ canonical: 'example.com' }, { js }); - - assert.equal(applications['Google Font API'].name, 'Google Font API'); - assert.equal(applications['Moment.js'].name, 'Moment.js'); - }); -}); diff --git a/test/wappalyzer.spec.js b/test/wappalyzer.spec.js deleted file mode 100644 index ea68c22e0..000000000 --- a/test/wappalyzer.spec.js +++ /dev/null @@ -1,143 +0,0 @@ -/* eslint-env mocha */ - -const { assert, expect } = require('chai'); -const Wappalyzer = require('../src/wappalyzer'); - -const appsJson = { - appUrl: { - url: 'test', - }, - appCookies: { - cookies: { - test: 'test', - }, - }, - appUppercaseCookies: { - cookies: { - Test: 'Test', - }, - }, - appHeaders: { - headers: { - 'X-Powered-By': 'test', - }, - }, - appHtml: { - html: 'test v(\\d)\\;confidence:50\\;version:\\1', - implies: 'appImplies', - excludes: 'appExcludes', - }, - appMeta: { - meta: { - generator: 'test', - }, - }, - appScript: { - script: 'test', - }, - appJs: { - js: { - key: 'value', - }, - }, - appImplies: { - }, - appExcludes: { - html: 'test', - }, -}; - -const driverData = { - cookies: [ - { - name: 'test', - value: 'test', - domain: '', - path: '', - }, - ], - headers: { - 'x-powered-by': [ - 'test', - ], - }, - html: ' html test v1', - scripts: [ - 'test', - ], - js: { - appJs: { - key: [ - 'value', - ], - }, - }, -}; - -describe('Wappalyzer', () => { - describe('#analyze()', () => { - let apps; - - before(async () => { - const wappalyzer = new Wappalyzer(); - - wappalyzer.apps = appsJson; - - wappalyzer.parseJsPatterns(); - - wappalyzer.driver.displayApps = (detected) => { - apps = detected; - }; - - await wappalyzer.analyze({ canonical: 'test' }, driverData); - }); - - it('should identify technologies using URLs', () => { - expect(apps).to.have.any.keys('appUrl'); - }); - - it('should identify technologies using HTML', () => { - expect(apps).to.have.any.keys('appHtml'); - }); - - it('should identify technologies using meta tags', () => { - expect(apps).to.have.any.keys('appMeta'); - }); - - it('should identify technologies using script URLs', () => { - expect(apps).to.have.any.keys('appScript'); - }); - - it('should identify technologies using headers', () => { - expect(apps).to.have.any.keys('appHeaders'); - }); - - it('should identify technologies using cookies', () => { - expect(apps).to.have.any.keys('appCookies'); - }); - - it('should identify technologies using uppercase named cookies', () => { - expect(apps).to.have.any.keys('appUppercaseCookies'); - }); - - it('should identify technologies using JavaScript', () => { - expect(apps).to.have.any.keys('appJs'); - }); - - it('should return the implied technology', () => { - expect(apps).to.have.any.keys('appImplies'); - }); - - it('should not return the excluded technology', () => { - expect(apps).to.not.have.any.keys('appExcludes'); - }); - - it('should return the confidence value', () => { - assert.equal(apps.appHtml.confidenceTotal, 50); - }); - - it('should return the version number', () => { - assert.equal(apps.appHtml.version, '1'); - }); - }); -});