Merge pull request #5 from AliasIO/master

Sync no.5
main
Daniel Zdziebko 7 years ago committed by GitHub
commit 7cdfe916ea

8
run

@ -10,13 +10,7 @@ fi
cmd="docker run --rm -v "$(pwd):/opt/wappalyzer" -it wappalyzer/dev"
$cmd yarn install
pushd src/drivers/webextension
$cmd yarn install
popd
$cmd sh -c "yarn install; cd src/drivers/webextension; yarn install"
$cmd ./bin/run links
$cmd ./bin/run $@

@ -401,7 +401,7 @@
"headers": {
"X-Akamai-Transformed": ""
},
"icon": "Akamai.png",
"icon": "akamai.svg",
"website": "http://akamai.com"
},
"Akka HTTP": {
@ -939,6 +939,14 @@
"script": "bittads\\.com/js/bitt\\.js$",
"website": "http://bittads.com"
},
"Bizweb":{
"cats": [
"6"
],
"env": "^Bizweb$",
"icon": "bizweb.png",
"website": "https://www.bizweb.vn"
},
"Blesta": {
"cats": [
"6"
@ -5331,7 +5339,7 @@
"cats": [
"12"
],
"icon": "moon.png",
"icon": "moon.svg",
"script": "/moon(?:\\.min)?\\.js$",
"website": "http://moonjs.ga/"
},
@ -5585,6 +5593,24 @@
"icon": "New Relic.png",
"website": "http://newrelic.com"
},
"Next.js": {
"cats": [
"18",
"22"
],
"headers": {
"x-powered-by": "^Next.js ?([0-9.]+)?\\;version:\\1"
},
"html": "<[^>]+__next",
"env": "^__NEXT_DATA__$",
"icon": "zeit.svg",
"implies": [
"React",
"webpack",
"Node.js"
],
"website": "https://zeit.co/next"
},
"Nginx": {
"cats": [
"22"
@ -5614,6 +5640,16 @@
"script": "^/nodebb\\.min\\.js\\?",
"website": "https://nodebb.org"
},
"Now": {
"cats": [
"22"
],
"headers": {
"server": "now"
},
"icon": "zeit.svg",
"website": "https://zeit.co/now"
},
"OWL Carousel": {
"cats": [
"5"
@ -8430,6 +8466,10 @@
],
"icon": "typecho.svg",
"implies": "PHP",
"env": "^TypechoComment$",
"meta": {
"generator": "Typecho( [\\d.]+)?\\;version:\\1"
},
"url": "/admin/login\\.php?referer=http%3A%2F%2F",
"website": "http://typecho.org/"
},
@ -8521,7 +8561,7 @@
},
"UMI.CMS": {
"cats": [
1
"1"
],
"headers": {
"X-Generated-By": "UMI.CMS"

@ -105,9 +105,9 @@
'</a>' +
'<div id="wappalyzer-apps">';
if ( w.detected[url] != null && Object.keys(w.detected[url]).length ) {
for ( app in w.detected[url] ) {
if ( !hasOwn.call(w.detected[url], app) ) {
if ( detected[url] != null && Object.keys(detected[url]).length ) {
for ( app in detected[url] ) {
if ( !hasOwn.call(detected[url], app) ) {
continue;
}
@ -154,5 +154,5 @@
}
};
w.init();
w.driver.init();
})();

@ -1,19 +1,21 @@
'use strict';
const wappalyzer = require('./wappalyzer');
const Wappalyzer = require('./wappalyzer');
const request = require('request');
const fs = require('fs');
const Browser = require('zombie');
const json = JSON.parse(fs.readFileSync(__dirname + '/apps.json'));
wappalyzer.apps = json.apps;
wappalyzer.categories = json.categories;
const driver = {
quiet: true,
analyze: url => {
const wappalyzer = new Wappalyzer();
wappalyzer.apps = json.apps;
wappalyzer.categories = json.categories;
return new Promise((resolve, reject) => {
wappalyzer.driver.log = (message, source, type) => {
if ( type === 'error' ) {

@ -2,7 +2,7 @@
"name": "wappalyzer",
"description": "Uncovers the technologies used on websites",
"homepage": "https://github.com/AliasIO/Wappalyzer",
"version": "5.0.5",
"version": "5.1.0",
"author": "Elbert Alias",
"license": "GPL-3.0",
"repository": {

@ -1,31 +1,95 @@
body {
background: #fff;
color: #4a4a4a;
font-family: Helvetica, Arial, sans-serif;
font-size: 13px;
line-height: 16px;
font-size: .8rem;
height: 20.8rem;
margin: 0;
min-width: 200px;
overflow-x: hidden;
padding: 15px;
overflow: hidden;
width: 30rem;
}
a {
color: #4a4a4a;
.header {
align-items: center;
background: linear-gradient(160deg, #32067c, #150233);
height: 4rem;
display: flex;
}
a:focus {
outline: 0;
.header__link:focus {
outline: none;
}
img {
.header__logo {
display: inline-block;
margin: .2rem 0 0 1.5rem;
-webkit-backface-visibility: hidden;
-webkit-transform: translateZ(0) scale(1.0, 1.0);
transform: translateZ(0);
height: 2rem;
}
.container {
height: 15.8rem;
overflow: scroll;
padding: 1rem 1.5rem 0rem 1.5rem;
}
.detected {
columns: 2;
column-gap: 1.5rem;
line-height: 1.4rem;
}
.detected__category {
break-inside: avoid-column;
padding-bottom: 1rem;
}
.detected__category-link {
border-bottom: 1px solid #dbdbdb;
display: block;
margin-bottom: .5rem;
text-decoration: none;
}
.detected__category-name {
color: #4608ad;
display: block;
font-weight: bold;
line-height: 2rem;
}
.detected__category-link:hover .detected__category-name {
color: #4a4a4a;
}
.detected__app {
display: block;
line-height: 1.7rem;
text-decoration: none;
}
.detected__app:focus {
display: block;
outline: 0;
}
.detected__app-icon {
display: inline-block;
height: 16px;
margin-right: 8px;
vertical-align: top;
margin-right: .5rem;
vertical-align: -.2rem;
width: 16px;
}
.detected__app-name {
color: #4a4a4a;
}
.detected__app:hover .detected__app-name {
border-bottom: 1px solid #4a4a4a;
}
.detected-app {
padding: 7px 0;
}
@ -39,40 +103,12 @@ img {
padding-bottom: 0;
}
.detected-app a {
color: #4608ad;
display: block;
text-decoration: none;
}
.detected-app a .label .name {
border-bottom: 1px solid transparent;
}
.detected-app a:hover .label .name {
border-bottom: 1px solid #4608ad;
}
.detected-app a .category .name {
color: #4a4a4a;
border-bottom: 1px solid transparent;
}
.detected-app a:hover .category .name {
border-bottom: 1px solid #4a4a4a;
}
.label {
font-weight: bold;
}
.category {
display: block;
margin: 5px 0 0 24px;
.empty {
display: flex;
height: 16rem;
align-items: center;
justify-content: center;
}
.empty {
color: #999;
font-style: italic;
text-align: center;
.empty__text {
}

@ -11,5 +11,12 @@
<script src="../js/popup.js"></script>
</head>
<body>
<div class="header">
<a href="https://wappalyzer.com/" class="header__link" target="_blank">
<img class="header__logo" src="../images/logo-white.svg">
</a>
</div>
<div class="container"></div>
</body>
</html>

@ -3,7 +3,9 @@
*/
/** global: browser */
/** global: wappalyzer */
/** global: Wappalyzer */
const wappalyzer = new Wappalyzer();
var tabCache = {};
var headersCache = {};
@ -26,7 +28,7 @@ function getOption(name, defaultValue) {
// Chrome, Firefox
browser.storage.local.get(name)
.then(callback)
.catch(console.error);
.catch(error => wappalyzer.log(error, 'driver', 'error'));
} catch ( e ) {
// Edge
browser.storage.local.get(name, callback);
@ -123,7 +125,7 @@ var callback = tabs => {
try {
browser.tabs.query({})
.then(callback)
.catch(console.error);
.catch(error => wappalyzer.log(error, 'driver', 'error'));
} catch ( e ) {
browser.tabs.query({}, callback);
}
@ -279,10 +281,10 @@ wappalyzer.driver.getRobotsTxt = (host, secure = false) => {
fetch('http' + ( secure ? 's' : '' ) + '://' + host + '/robots.txt')
.then(response => {
if ( !response.ok ) {
if (response.status === 404) {
return '';
if ( response.status === 404 ) {
return '';
} else {
throw 'GET ' + response.url + ' was not ok';
throw 'GET ' + response.url + ' was not ok';
}
}

@ -181,7 +181,7 @@ var exports = {};
video_assets: opt_video_assets,
assets: opt_assets,
version: '3',
mrev: '082d7cb-d',
mrev: '4d79384-d',
msgNum: this.msgNum,
timestamp: new Date().getTime(),
pageVis: document.visibilityState,
@ -890,7 +890,7 @@ var exports = {};
var _pageTags;
var INIT_MS_BW_SEARCHES = 2000;
var PAGE_TAG_RE = new RegExp('gpt|oascentral');
var POST_MSG_ID = '1501281986-4236-27733-5465-12184';
var POST_MSG_ID = '1503096304-372-12333-31563-11152';
var AD_SERVER_RE = new RegExp('^(google_ads_iframe|oas_frame|atwAdFrame)');
function getPageTags(doc) {
@ -1104,6 +1104,23 @@ var exports = {};
}
},
blockedRobotsMsgGen: function(sendFcn, origUrl) {
if ( origUrl.indexOf('google.com/_/chrome/newtab') === -1 ) {
var onBlockedRobotsMessage = function() {
var log;
log = _logGen.log('invalid-robotstxt', []);
log.doc.finalPageUrl = log.doc.url;
log.doc.url = exports.utils.normalizeUrl(origUrl);
sendFcn(log);
};
return onBlockedRobotsMessage;
} else {
return function() {};
}
},
init: function(onAdFound) {
if ( exports.utils.SCRIPT_IN_FRIENDLY_IFRAME ) {
@ -1137,6 +1154,8 @@ if ( exports.utils.SCRIPT_IN_WINDOW_TOP ) {
init: exports.coordinator.init,
addPostMessageListener: exports.coordinator.addPostMessageListener,
askIfTrackingEnabled: exports.utils.askIfTrackingEnabled,
blockedRobotsMsgGen: exports.coordinator.blockedRobotsMsgGen,
inWindowTop: exports.utils.SCRIPT_IN_WINDOW_TOP,
sendToBackground: exports.utils.sendToBackground
};
} else {
@ -1149,18 +1168,18 @@ if ( exports.utils.SCRIPT_IN_WINDOW_TOP ) {
);
}
})(window);
(function(adparser) {
(function(adparser, pageUrl) {
function onAdFound(log) {
adparser.sendToBackground({ id: 'ad_log', subject: log }, 'ad_log', '', function(){});
}
if ( window === window.top ) {
if ( adparser && adparser.inWindowTop ) {
adparser.addPostMessageListener();
adparser.askIfTrackingEnabled(
function() {
adparser.init(onAdFound);
},
function() {}
adparser.blockedRobotsMsgGen(onAdFound, pageUrl)
)
}
})(window.adparser);
})(window.adparser, window.location.href);

@ -66,6 +66,7 @@
'washingtonpost.com'
];
var robotsTxtAllows = wappalyzer.robotsTxtAllows;
if ( !String.prototype.endsWith ) {
String.prototype.endsWith = function(searchString, position) {
var subjectString = this.toString();
@ -114,10 +115,10 @@
}
}
function ifTrackingEnabled(url, ifCallback, elseCallback) {
function ifTrackingEnabled(details, ifCallback, elseCallback) {
var fullIfCallback = function() {
allowedByRobotsTxt(url, ifCallback, elseCallback);
allowedByRobotsTxt(details, ifCallback, elseCallback);
};
browser.storage.local.get('tracking').then(function(item) {
@ -135,9 +136,9 @@
}
function allowedByRobotsTxt(url, ifCallback, elseCallback) {
if ( ! url.startsWith('chrome://') ) {
wappalyzer.robotsTxtAllows(url).then(ifCallback, elseCallback);
function allowedByRobotsTxt(details, ifCallback, elseCallback) {
if ( details.url && !details.url.startsWith('chrome://') ) {
robotsTxtAllows(details.url).then(ifCallback, elseCallback);
} else {
elseCallback();
}
@ -219,7 +220,7 @@
this.cleanupCollector(tabId);
ifTrackingEnabled(
details.url,
details,
function() {
if ( !areListenersRegistered ) {
@ -279,18 +280,20 @@
browserProxy.tabs.sendMessage(this.tabId, message);
};
PageNetworkTrafficCollector.prototype.sendToTab = function(assetReq, reqs, curPageUrl, isValidAd) {
PageNetworkTrafficCollector.prototype.sendToTab = function(assetReq, reqs, curPageUrl, nonAdTrackingEvent) {
var msg = {};
msg.assets = [];
msg.requests = [];
msg.event_data = {};
if ( isValidAd ) {
if ( !nonAdTrackingEvent ) {
msg.event = 'new-video-ad';
msg.requests = reqs;
msg.requests.sort(function(reqA, reqB) {return reqA.requestTimestamp - reqB.requestTimestamp;});
if ( assetReq ) {
msg.assets = [assetReq];
}
} else {
} else if ( nonAdTrackingEvent === 'new-invalid-video-ad' ) {
msg.event = nonAdTrackingEvent;
msg.requests = reqs.map(function(request) {
return parseHostnameFromUrl(request.url);
});
@ -301,7 +304,8 @@
contentType: assetReq.contentType,
size: assetReq.size
}];
msg.event = 'new-invalid-video-ad';
} else if ( nonAdTrackingEvent === 'robots-txt-no-scraping' ) {
msg.event = nonAdTrackingEvent;
}
msg.origUrl = curPageUrl;
msg.displayAdFound = this.displayAdFound;
@ -805,7 +809,7 @@
browserProxy.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if ( request === 'is_tracking_enabled' ) {
ifTrackingEnabled(
sender.tab.url,
sender.tab,
function() {
try {sendResponse({'tracking_enabled': true});}
catch(err) {} },

@ -32,26 +32,16 @@ function replaceDomWhenReady(dom) {
}
function replaceDom(domTemplate) {
var body = document.body;
var container = document.getElementsByClassName('container')[0];
while ( body.firstChild ) {
body.removeChild(body.firstChild);
while ( container.firstChild ) {
container.removeChild(container.firstChild);
}
body.appendChild(jsonToDOM(domTemplate, document, {}));
container.appendChild(jsonToDOM(domTemplate, document, {}));
var nodes = document.querySelectorAll('[data-i18n]');
for ( let ms = 200; ms < 500; ms += 50 ) {
setTimeout(() => {
let div = document.createElement('div');
div.style.display = 'none';
body.appendChild(div);
}, ms);
};
Array.prototype.forEach.call(nodes, node => {
node.childNodes[0].nodeValue = browser.i18n.getMessage(node.dataset.i18n);
});
@ -63,65 +53,87 @@ function appsToDomTemplate(response) {
template = [];
if ( response.tabCache && Object.keys(response.tabCache.detected).length > 0 ) {
for ( appName in response.tabCache.detected ) {
confidence = response.tabCache.detected[appName].confidenceTotal;
version = response.tabCache.detected[appName].version;
categories = [];
const categories = {};
// Group apps by category
for ( appName in response.tabCache.detected ) {
response.apps[appName].cats.forEach(cat => {
categories.push(
categories[cat] = categories[cat] || { apps: [] };
categories[cat].apps[appName] = appName;
});
}
for ( cat in categories ) {
const apps = [];
for ( appName in categories[cat].apps ) {
confidence = response.tabCache.detected[appName].confidenceTotal;
version = response.tabCache.detected[appName].version;
apps.push(
[
'a', {
class: 'detected__app',
target: '_blank',
href: 'https://wappalyzer.com/categories/' + slugify(response.categories[cat].name)
href: 'https://wappalyzer.com/applications/' + slugify(appName)
}, [
'img', {
class: 'detected__app-icon',
src: '../images/icons/' + ( response.apps[appName].icon || 'default.svg' )
},
], [
'span', {
class: 'category'
}, [
'span', {
class: 'name'
},
browser.i18n.getMessage('categoryName' + cat)
]
class: 'detected__app-name'
},
appName + ( version ? ' ' + version : '' ) + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' )
]
]
);
});
}
template.push(
[
'div', {
class: 'detected-app'
class: 'detected__category'
}, [
'a', {
class: 'detected__category-link',
target: '_blank',
href: 'https://wappalyzer.com/applications/' + slugify(appName)
href: 'https://wappalyzer.com/categories/' + slugify(response.categories[cat].name)
}, [
'img', {
src: '../images/icons/' + ( response.apps[appName].icon || 'default.svg' )
}
], [
'span', {
class: 'label'
}, [
'span', {
class: 'name'
},
appName
],
( version ? ' ' + version : '' ) + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' )
class: 'detected__category-name'
},
browser.i18n.getMessage('categoryName' + cat)
]
],
categories
], [
'div', {
class: 'detected__apps'
},
apps
]
]
);
}
template = [
'div', {
class: 'detected'
},
template
];
} else {
template = [
'div', {
class: 'empty'
},
browser.i18n.getMessage('noAppsDetected')
[
'span', {
class: 'empty__text'
},
browser.i18n.getMessage('noAppsDetected')
],
];
}

@ -4,7 +4,7 @@
"author": "Elbert Alias",
"homepage_url": "https://wappalyzer.com/",
"description": "Identify web technologies",
"version": "5.0.5",
"version": "5.1.0",
"default_locale": "en",
"manifest_version": 2,
"icons": {

@ -4,7 +4,7 @@
"author": "Elbert Alias",
"homepage_url": "https://wappalyzer.com/",
"description": "Identify web technologies",
"version": "5.0.5",
"version": "5.1.0",
"default_locale": "en",
"manifest_version": 2,
"icons": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 845 B

@ -1 +1,4 @@
<svg width="59" height="61" viewBox="0 0 59 61" xmlns="http://www.w3.org/2000/svg"><title>rock-logo</title><path d="M57.705 60.063L41.387 40.936s11.83-.026 11.928-.028a5.456 5.456 0 0 0 3.736-1.259 5.504 5.504 0 0 0 .693-7.752L32.396 2.151a5.562 5.562 0 0 0-.836-.891c-.039-.029-.084-.051-.121-.082-.012-.01-.027-.018-.039-.025a5.887 5.887 0 0 0-.867-.563c-.018-.009-.039-.014-.059-.021a5.377 5.377 0 0 0-.922-.366c-.057-.013-.119-.025-.178-.039-.277-.063-.557-.129-.84-.15-.172-.021-.346-.008-.516-.008-.172 0-.34-.014-.514.008-.281.021-.559.087-.84.15l-.174.039a5.18 5.18 0 0 0-.924.366c-.021.009-.039.014-.057.021a5.204 5.204 0 0 0-.869.563c-.018.009-.025.017-.037.025-.039.031-.084.053-.123.082-.32.271-.594.57-.84.885L0 29.86h14.461l13.557-15.891 13.604 15.967-12.104.008c-.045 0-.088.013-.133.017-.287 0-.578.026-.865.071a7.39 7.39 0 0 0-.244.054 5 5 0 0 0-.775.229 2 2 0 0 0-.266.117 4.44 4.44 0 0 0-.957.549c-.117.081-.238.143-.346.229-.076.067-.137.147-.211.221a4.613 4.613 0 0 0-.258.264 5.523 5.523 0 0 0-.453.531c-.068.105-.131.205-.195.308a5.154 5.154 0 0 0-.332.601c-.059.126-.107.255-.156.384-.072.199-.145.398-.191.605a4.218 4.218 0 0 0-.084.451 5.182 5.182 0 0 0-.07.606c-.006.074-.023.137-.023.209 0 .101.023.189.027.294.012.188.023.368.051.557a5.735 5.735 0 0 0 .246 1.012c.072.199.154.397.248.588.061.119.119.234.188.35.123.215.26.414.408.605.045.057.068.115.115.168l18.004 21.104h14.459v-.005z" fill="#EE7624" fill-rule="evenodd"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:#ED7726;}
</style><circle class="st0" cx="203" cy="208.1" r="184.8"/><path class="st1" d="M200 0C89.5 0 0 89.5 0 200s89.5 200 200 200 200-89.5 200-200S310.5 0 200 0zM327 338.3h-72.6l-90.3-105.9c-0.2-0.3-0.4-0.6-0.6-0.8 -0.7-1-1.4-2-2-3 -0.3-0.6-0.6-1.2-0.9-1.8 -0.5-0.9-0.9-2-1.2-2.9 -0.3-0.8-0.5-1.5-0.7-2.3 -0.2-0.9-0.4-1.8-0.6-2.8 -0.1-0.9-0.2-1.9-0.3-2.8 0-0.5-0.1-1-0.1-1.5 0-0.4 0.1-0.7 0.1-1.1 0.1-1 0.2-2 0.4-3 0.1-0.8 0.2-1.5 0.4-2.3 0.2-1 0.6-2 1-3 0.2-0.6 0.5-1.3 0.8-1.9 0.5-1 1-2 1.7-3 0.3-0.5 0.6-1 1-1.5 0.7-0.9 1.4-1.8 2.3-2.7 0.4-0.5 0.9-0.9 1.3-1.3 0.4-0.4 0.7-0.8 1.1-1.1 0.5-0.4 1.1-0.7 1.7-1.1 0.5-0.3 1-0.7 1.4-1 1.1-0.7 2.2-1.3 3.4-1.8 0.4-0.2 0.9-0.4 1.3-0.6 1.3-0.5 2.6-0.9 3.9-1.1 0.4-0.1 0.8-0.2 1.2-0.3 1.4-0.2 2.9-0.4 4.3-0.4 0.2 0 0.4-0.1 0.7-0.1l60.7 0L178 107.1l-68 79.7H37.5l118.6-139c1.2-1.6 2.6-3.1 4.2-4.4 0.2-0.1 0.4-0.3 0.6-0.4 0.1-0.1 0.1-0.1 0.2-0.1 1.4-1.1 2.8-2 4.4-2.8 0.1 0 0.2-0.1 0.3-0.1 1.5-0.8 3-1.4 4.6-1.8 0.3-0.1 0.6-0.1 0.9-0.2 1.4-0.3 2.8-0.6 4.2-0.8 0.9-0.1 1.7 0 2.6 0 0.9 0 1.7-0.1 2.6 0 1.4 0.1 2.8 0.4 4.2 0.8 0.3 0.1 0.6 0.1 0.9 0.2 1.6 0.5 3.1 1.1 4.6 1.8 0.1 0 0.2 0.1 0.3 0.1 1.5 0.8 2.9 1.7 4.4 2.8 0.1 0 0.1 0.1 0.2 0.1 0.2 0.2 0.4 0.3 0.6 0.4 1.6 1.4 3 2.9 4.2 4.5L327.2 197c9.8 11.7 8.2 29.1-3.5 38.9 -5.4 4.6-12.2 6.6-18.7 6.3 -0.5 0-59.8 0.1-59.8 0.1L327 338.3z"/></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><g fill="#008cdb"><path d="M273.971 437.617c-78.241-23.9-135.099-96.163-135.099-181.622 0-86.376 58.091-159.287 137.634-182.373 8.13-2.355 5.994-7.622-3.799-7.622C166.942 66 81.22 151.063 81.22 255.995 81.22 360.937 166.942 446 272.708 446c9.797 0 10.192-5.652 1.263-8.383z"/><path d="M175.135 300.485c-5.643-54.204 20.877-162.662 150.07-166.31 78.744-2.224 102.435 35.2 105.355 32.898 3.214-2.531-28.582-72.253-121.088-72.253-83.323 0-150.859 67.547-150.859 150.869 0 19.243 3.613 37.629 10.192 54.551 2.77 7.112 7.042 7.136 6.33.245z"/><path d="M238.342 191.77c39.194-17.083 88.473-17.561 136.878-.668 32.503 11.348 51.371 27.538 52.902 26.895 2.565-1.111-18.921-35.132-57.686-49.83-46.943-17.814-97.543-8.495-134.376 20.385-4.073 3.178-2.527 5.319 2.282 3.218z"/></g></svg>

After

Width:  |  Height:  |  Size: 863 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg width="145.61mm" height="168.42mm" version="1.1" viewBox="0 0 550.32981 636.55663" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xlink="http://www.w3.org/1999/xlink"><metadata><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title>Moon Logo</dc:title></cc:Work></rdf:RDF></metadata><title>Moon Logo</title><g transform="matrix(1.1168 0 0 1.0609 -223.35 -212.19)"><g transform="translate(-3102,-6459)"><clipPath id="f" clip-rule="evenodd"><path d="m3102 6459h1e3v1e3h-1e3z" fill="#fff"/></clipPath><g clip-path="url(#f)"><use transform="translate(3302,6659)" width="100%" height="100%" fill="url(#d)" xlink:href="#e"/></g></g></g><defs><linearGradient id="d" x2="1" gradientTransform="matrix(348 600 -195.66 352.44 97.83 -176.22)" gradientUnits="userSpaceOnUse"><stop stop-color="#007EFF" offset="0"/><stop stop-color="#B22BFF" offset=".97238"/></linearGradient><path id="e" d="m491.47 530.96c6.198-5.145 3.529-15.01-4.221-17.208-125.37-35.561-217.25-151.37-217.25-288.75 0-79.162 30.508-151.16 80.353-204.78 5.473-5.886 2.646-15.667-5.301-16.864-14.695-2.2131-29.74-3.3603-45.052-3.3603-165.69 0-300 134.31-300 300s134.31 300 300 300c72.788 0 139.52-25.923 191.47-69.039z" fill-rule="evenodd"/></defs></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><title>Zeit</title><desc>Created with Sketch.</desc><defs><linearGradient x1="100.686%" y1="181.283%" x2="41.808%" y2="100%" id="a"><stop stop-color="#fff" offset="0%"/><stop offset="100%"/></linearGradient></defs><path d="M15.766 3l14.766 26.134h-29.531z" fill-rule="nonzero" fill="url(#a)"/></svg>

After

Width:  |  Height:  |  Size: 382 B

@ -13,517 +13,523 @@ const validation = {
hostnameBlacklist: /((local|dev(elopment)?|stag(e|ing)?|test(ing)?|demo(shop)?|admin|google|cache)\.|\/admin|\.local)/
};
var wappalyzer = {
apps: {},
categories: {},
driver: {}
};
class Wappalyzer {
constructor() {
this.apps = {};
this.categories = {};
this.driver = {};
this.detected = {};
this.hostnameCache = {};
this.adCache = [];
this.config = {
websiteURL: 'https://wappalyzer.com/',
twitterURL: 'https://twitter.com/Wappalyzer',
githubURL: 'https://github.com/AliasIO/Wappalyzer',
};
}
var detected = {};
var hostnameCache = {};
var adCache = [];
/**
* Log messages to console
*/
log(message, source, type) {
this.driver.log(message, source || '', type || 'debug');
}
wappalyzer.config = {
websiteURL: 'https://wappalyzer.com/',
twitterURL: 'https://twitter.com/Wappalyzer',
githubURL: 'https://github.com/AliasIO/Wappalyzer',
};
analyze(hostname, url, data, context) {
var apps = {};
/**
* Log messages to console
*/
wappalyzer.log = (message, source, type) => {
wappalyzer.driver.log(message, source || '', type || 'debug');
};
// Remove hash from URL
data.url = url = url.split('#')[0];
wappalyzer.analyze = (hostname, url, data, context) => {
var apps = {};
// Remove hash from URL
data.url = url = url.split('#')[0];
if ( typeof data.html !== 'string' ) {
data.html = '';
}
if ( typeof data.html !== 'string' ) {
data.html = '';
}
if ( this.detected[url] === undefined ) {
this.detected[url] = {};
}
if ( detected[url] === undefined ) {
detected[url] = {};
}
Object.keys(this.apps).forEach(appName => {
apps[appName] = this.detected[url] && this.detected[url][appName] ? this.detected[url][appName] : new Application(appName, this.apps[appName]);
Object.keys(wappalyzer.apps).forEach(appName => {
apps[appName] = detected[url] && detected[url][appName] ? detected[url][appName] : new Application(appName, wappalyzer.apps[appName]);
var app = apps[appName];
var app = apps[appName];
if ( url ) {
this.analyzeUrl(app, url);
}
if ( url ) {
analyzeUrl(app, url);
}
if ( data.html ) {
this.analyzeHtml(app, data.html);
this.analyzeScript(app, data.html);
this.analyzeMeta(app, data.html);
}
if ( data.html ) {
analyzeHtml(app, data.html);
analyzeScript(app, data.html);
analyzeMeta(app, data.html);
}
if ( data.headers ) {
this.analyzeHeaders(app, data.headers);
}
if ( data.headers ) {
analyzeHeaders(app, data.headers);
}
if ( data.env ) {
this.analyzeEnv(app, data.env);
}
if ( data.env ) {
analyzeEnv(app, data.env);
}
if ( data.robotsTxt ) {
this.analyzeRobotsTxt(app, data.robotsTxt);
}
})
if ( data.robotsTxt ) {
analyzeRobotsTxt(app, data.robotsTxt);
}
})
Object.keys(apps).forEach(appName => {
var app = apps[appName];
Object.keys(apps).forEach(appName => {
var app = apps[appName];
if ( !app.detected || !app.getConfidence() ) {
delete apps[app.name];
}
});
if ( !app.detected || !app.getConfidence() ) {
delete apps[app.name];
}
});
this.resolveExcludes(apps);
this.resolveImplies(apps, url);
resolveExcludes(apps);
resolveImplies(apps, url);
this.cacheDetectedApps(apps, url);
this.trackDetectedApps(apps, url, hostname, data.html);
cacheDetectedApps(apps, url);
trackDetectedApps(apps, url, hostname, data.html);
if ( Object.keys(apps).length ) {
this.log(Object.keys(apps).length + ' apps detected: ' + Object.keys(apps).join(', ') + ' on ' + url, 'core');
}
if ( Object.keys(apps).length ) {
wappalyzer.log(Object.keys(apps).length + ' apps detected: ' + Object.keys(apps).join(', ') + ' on ' + url, 'core');
this.driver.displayApps(this.detected[url], context);
}
wappalyzer.driver.displayApps(detected[url], context);
}
/**
* Cache detected ads
*/
cacheDetectedAds(ad) {
this.adCache.push(ad);
}
/**
* Cache detected ads
*/
wappalyzer.cacheDetectedAds = ad => {
adCache.push(ad);
}
/**
*
*/
robotsTxtAllows(url) {
return new Promise((resolve, reject) => {
var parsed = this.parseUrl(url);
this.driver.getRobotsTxt(parsed.host, parsed.protocol === 'https:')
.then(robotsTxt => {
robotsTxt.forEach(disallow => {
if ( parsed.pathname.indexOf(disallow) === 0 ) {
reject();
}
});
/**
*
*/
wappalyzer.robotsTxtAllows = url => {
return new Promise((resolve, reject) => {
var parsed = wappalyzer.parseUrl(url);
wappalyzer.driver.getRobotsTxt(parsed.host, parsed.protocol === 'https:')
.then(robotsTxt => {
robotsTxt.forEach(disallow => {
if ( parsed.pathname.indexOf(disallow) === 0 ) {
reject();
}
resolve();
});
});
};
resolve();
});
});
};
/**
* Parse a URL
*/
wappalyzer.parseUrl = url => {
var a = wappalyzer.driver.document.createElement('a');
/**
* Parse a URL
*/
parseUrl(url) {
var a = this.driver.document.createElement('a');
a.href = url;
a.href = url;
a.canonical = a.protocol + '//' + a.host + a.pathname;
a.canonical = a.protocol + '//' + a.host + a.pathname;
return a;
}
return a;
}
/**
*
*/
wappalyzer.parseRobotsTxt = robotsTxt => {
var userAgent;
var disallow = [];
/**
*
*/
parseRobotsTxt(robotsTxt) {
var userAgent;
var disallow = [];
robotsTxt.split('\n').forEach(line => {
var matches = /^User-agent:\s*(.+)$/i.exec(line);
robotsTxt.split('\n').forEach(line => {
var matches = /^User-agent:\s*(.+)$/i.exec(line);
if ( matches ) {
userAgent = matches[1].toLowerCase();
} else {
if ( userAgent === '*' || userAgent === 'wappalyzer' ) {
matches = /^Disallow:\s*(.+)$/i.exec(line);
if ( matches ) {
userAgent = matches[1].toLowerCase();
} else {
if ( userAgent === '*' || userAgent === 'wappalyzer' ) {
matches = /^Disallow:\s*(.+)$/i.exec(line);
if ( matches ) {
disallow.push(matches[1]);
if ( matches ) {
disallow.push(matches[1]);
}
}
}
}
});
return disallow;
}
/**
*
*/
wappalyzer.ping = () => {
if ( Object.keys(hostnameCache).length >= 50 || adCache.length >= 50 ) {
wappalyzer.driver.ping(hostnameCache, adCache);
});
hostnameCache = {};
adCache = [];
return disallow;
}
}
/**
* Enclose string in array
*/
function asArray(value) {
return typeof value === 'string' ? [ value ] : value;
}
/**
* Parse apps.json patterns
*/
function parsePatterns(patterns) {
var parsed = {};
/**
*
*/
ping() {
if ( Object.keys(this.hostnameCache).length >= 50 || this.adCache.length >= 50 ) {
this.driver.ping(this.hostnameCache, this.adCache);
// Convert string to object containing array containing string
if ( typeof patterns === 'string' || patterns instanceof Array ) {
patterns = {
main: asArray(patterns)
};
this.hostnameCache = {};
this.adCache = [];
}
}
for ( var key in patterns ) {
parsed[key] = [];
asArray(patterns[key]).forEach(pattern => {
var attrs = {};
pattern.split('\\;').forEach((attr, i) => {
if ( i ) {
// Key value pairs
attr = attr.split(':');
if ( attr.length > 1 ) {
attrs[attr.shift()] = attr.join(':');
}
} else {
attrs.string = attr;
/**
* Enclose string in array
*/
asArray(value) {
return typeof value === 'string' ? [ value ] : value;
}
try {
attrs.regex = new RegExp(attr.replace('/', '\/'), 'i'); // Escape slashes in regular expression
} catch (e) {
attrs.regex = new RegExp();
/**
* Parse apps.json patterns
*/
parsePatterns(patterns) {
var parsed = {};
// Convert string to object containing array containing string
if ( typeof patterns === 'string' || patterns instanceof Array ) {
patterns = {
main: this.asArray(patterns)
};
}
wappalyzer.log(e + ': ' + attr, 'error', 'core');
}
}
});
for ( var key in patterns ) {
parsed[key] = [];
parsed[key].push(attrs);
});
}
this.asArray(patterns[key]).forEach(pattern => {
var attrs = {};
// Convert back to array if the original pattern list was an array (or string)
if ( 'main' in parsed ) {
parsed = parsed.main;
}
pattern.split('\\;').forEach((attr, i) => {
if ( i ) {
// Key value pairs
attr = attr.split(':');
return parsed;
}
if ( attr.length > 1 ) {
attrs[attr.shift()] = attr.join(':');
}
} else {
attrs.string = attr;
function resolveExcludes(apps) {
var excludes = [];
try {
attrs.regex = new RegExp(attr.replace('/', '\/'), 'i'); // Escape slashes in regular expression
} catch (e) {
attrs.regex = new RegExp();
// Exclude app in detected apps only
Object.keys(apps).forEach(appName => {
var app = apps[appName];
this.log(e + ': ' + attr, 'error', 'core');
}
}
});
if ( app.props.excludes ) {
asArray(app.props.excludes).forEach(excluded => {
excludes.push(excluded);
parsed[key].push(attrs);
});
}
})
// Remove excluded applications
Object.keys(apps).forEach(appName => {
if ( excludes.indexOf(appName) !== -1 ) {
delete apps[appName];
// Convert back to array if the original pattern list was an array (or string)
if ( 'main' in parsed ) {
parsed = parsed.main;
}
})
}
function resolveImplies(apps, url) {
var checkImplies = true;
return parsed;
}
// Implied applications
// Run several passes as implied apps may imply other apps
while ( checkImplies ) {
checkImplies = false;
resolveExcludes(apps) {
var excludes = [];
// Exclude app in detected apps only
Object.keys(apps).forEach(appName => {
var app = apps[appName];
if ( app && app.implies ) {
asArray(app.props.implies).forEach(implied => {
implied = parsePatterns(implied)[0];
if ( !wappalyzer.apps[implied.string] ) {
wappalyzer.log('Implied application ' + implied.string + ' does not exist', 'core', 'warn');
return;
}
if ( !( implied.string in apps ) ) {
apps[implied.string] = detected[url] && detected[url][implied.string] ? detected[url][implied.string] : new Application(implied.string, true);
checkImplies = true;
}
// Apply app confidence to implied app
Object.keys(app.confidence).forEach(id => {
apps[implied.string].confidence[id + ' implied by ' + appName] = app.confidence[id] * ( implied.confidence ? implied.confidence / 100 : 1 );
});
if ( app.props.excludes ) {
this.asArray(app.props.excludes).forEach(excluded => {
excludes.push(excluded);
});
}
});
})
// Remove excluded applications
Object.keys(apps).forEach(appName => {
if ( excludes.indexOf(appName) !== -1 ) {
delete apps[appName];
}
})
}
}
/**
* Cache detected applications
*/
function cacheDetectedApps(apps, url) {
if (!wappalyzer.driver.ping instanceof Function) return;
resolveImplies(apps, url) {
var checkImplies = true;
Object.keys(apps).forEach(appName => {
var app = apps[appName];
// Implied applications
// Run several passes as implied apps may imply other apps
while ( checkImplies ) {
checkImplies = false;
// Per URL
detected[url][appName] = app;
Object.keys(apps).forEach(appName => {
var app = apps[appName];
Object.keys(app.confidence).forEach(id => {
detected[url][appName].confidence[id] = app.confidence[id];
});
})
if ( app && app.implies ) {
this.asArray(app.props.implies).forEach(implied => {
implied = this.parsePatterns(implied)[0];
wappalyzer.ping();
}
if ( !this.apps[implied.string] ) {
this.log('Implied application ' + implied.string + ' does not exist', 'core', 'warn');
/**
* Track detected applications
*/
function trackDetectedApps(apps, url, hostname, html) {
if (!wappalyzer.driver.ping instanceof Function) return;
Object.keys(apps).forEach(appName => {
var app = apps[appName];
if ( detected[url][appName].getConfidence() >= 100 ) {
if ( validation.hostname.test(hostname) && !validation.hostnameBlacklist.test(url) ) {
wappalyzer.robotsTxtAllows(url)
.then(() => {
if ( !( hostname in hostnameCache ) ) {
hostnameCache[hostname] = {
applications: {},
meta: {}
};
return;
}
if ( !( appName in hostnameCache[hostname].applications ) ) {
hostnameCache[hostname].applications[appName] = {
hits: 0
};
if ( !( implied.string in apps ) ) {
apps[implied.string] = this.detected[url] && this.detected[url][implied.string] ? this.detected[url][implied.string] : new Application(implied.string, true);
checkImplies = true;
}
hostnameCache[hostname].applications[appName].hits ++;
// Apply app confidence to implied app
Object.keys(app.confidence).forEach(id => {
apps[implied.string].confidence[id + ' implied by ' + appName] = app.confidence[id] * ( implied.confidence ? implied.confidence / 100 : 1 );
});
});
}
});
}
}
if ( apps[appName].version ) {
hostnameCache[hostname].applications[appName].version = app.version;
}
})
.catch(() => console.log('Disallowed in robots.txt: ' + url))
}
/**
* Cache detected applications
*/
cacheDetectedApps(apps, url) {
if ( !( this.driver.ping instanceof Function ) ) {
return;
}
});
// Additional information
if ( hostname in hostnameCache ) {
var match = html.match(/<html[^>]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i);
Object.keys(apps).forEach(appName => {
var app = apps[appName];
if ( match && match.length ) {
hostnameCache[hostname].meta['language'] = match[1];
}
// Per URL
this.detected[url][appName] = app;
Object.keys(app.confidence).forEach(id => {
this.detected[url][appName].confidence[id] = app.confidence[id];
});
})
this.ping();
}
wappalyzer.ping();
}
/**
* Track detected applications
*/
trackDetectedApps(apps, url, hostname, html) {
if ( !( this.driver.ping instanceof Function ) ) {
return;
}
/**
* Analyze URL
*/
function analyzeUrl(app, url) {
var patterns = parsePatterns(app.props.url);
Object.keys(apps).forEach(appName => {
var app = apps[appName];
if ( patterns.length ) {
patterns.forEach(pattern => {
if ( pattern.regex.test(url) ) {
addDetected(app, pattern, 'url', url);
if ( this.detected[url][appName].getConfidence() >= 100 ) {
if ( validation.hostname.test(hostname) && !validation.hostnameBlacklist.test(url) ) {
this.robotsTxtAllows(url)
.then(() => {
if ( !( hostname in this.hostnameCache ) ) {
this.hostnameCache[hostname] = {
applications: {},
meta: {}
};
}
if ( !( appName in this.hostnameCache[hostname].applications ) ) {
this.hostnameCache[hostname].applications[appName] = {
hits: 0
};
}
this.hostnameCache[hostname].applications[appName].hits ++;
if ( apps[appName].version ) {
this.hostnameCache[hostname].applications[appName].version = app.version;
}
})
.catch(() => console.log('Disallowed in robots.txt: ' + url))
}
}
});
}
}
/**
* Analyze HTML
*/
function analyzeHtml(app, html) {
var patterns = parsePatterns(app.props.html);
// Additional information
if ( hostname in this.hostnameCache ) {
var match = html.match(/<html[^>]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i);
if ( patterns.length ) {
patterns.forEach(pattern => {
if ( pattern.regex.test(html) ) {
addDetected(app, pattern, 'html', html);
if ( match && match.length ) {
this.hostnameCache[hostname].meta['language'] = match[1];
}
});
}
this.ping();
}
}
/**
* Analyze script tag
*/
function analyzeScript(app, html) {
var regex = new RegExp('<script[^>]+src=("|\')([^"\']+)', 'ig');
var patterns = parsePatterns(app.props.script);
/**
* Analyze URL
*/
analyzeUrl(app, url) {
var patterns = this.parsePatterns(app.props.url);
if ( patterns.length ) {
patterns.forEach(pattern => {
var match;
if ( patterns.length ) {
patterns.forEach(pattern => {
if ( pattern.regex.test(url) ) {
this.addDetected(app, pattern, 'url', url);
}
});
}
}
/**
* Analyze HTML
*/
analyzeHtml(app, html) {
var patterns = this.parsePatterns(app.props.html);
while ( ( match = regex.exec(html) ) ) {
if ( pattern.regex.test(match[2]) ) {
addDetected(app, pattern, 'script', match[2]);
if ( patterns.length ) {
patterns.forEach(pattern => {
if ( pattern.regex.test(html) ) {
this.addDetected(app, pattern, 'html', html);
}
}
});
});
}
}
}
/**
* Analyze meta tag
*/
function analyzeMeta(app, html) {
var regex = /<meta[^>]+>/ig;
var patterns = parsePatterns(app.props.meta);
var content;
var match;
while ( patterns && ( match = regex.exec(html) ) ) {
for ( var meta in patterns ) {
if ( new RegExp('(name|property)=["\']' + meta + '["\']', 'i').test(match) ) {
content = match.toString().match(/content=("|')([^"']+)("|')/i);
patterns[meta].forEach(pattern => {
if ( content && content.length === 4 && pattern.regex.test(content[2]) ) {
addDetected(app, pattern, 'meta', content[2], meta);
/**
* Analyze script tag
*/
analyzeScript(app, html) {
var regex = new RegExp('<script[^>]+src=("|\')([^"\']+)', 'ig');
var patterns = this.parsePatterns(app.props.script);
if ( patterns.length ) {
patterns.forEach(pattern => {
var match;
while ( ( match = regex.exec(html) ) ) {
if ( pattern.regex.test(match[2]) ) {
this.addDetected(app, pattern, 'script', match[2]);
}
});
}
});
}
}
/**
* Analyze meta tag
*/
analyzeMeta(app, html) {
var regex = /<meta[^>]+>/ig;
var patterns = this.parsePatterns(app.props.meta);
var content;
var match;
while ( patterns && ( match = regex.exec(html) ) ) {
for ( var meta in patterns ) {
if ( new RegExp('(name|property)=["\']' + meta + '["\']', 'i').test(match) ) {
content = match.toString().match(/content=("|')([^"']+)("|')/i);
patterns[meta].forEach(pattern => {
if ( content && content.length === 4 && pattern.regex.test(content[2]) ) {
this.addDetected(app, pattern, 'meta', content[2], meta);
}
});
}
}
}
}
}
/**
* analyze response headers
*/
function analyzeHeaders(app, headers) {
var patterns = parsePatterns(app.props.headers);
/**
* analyze response headers
*/
analyzeHeaders(app, headers) {
var patterns = this.parsePatterns(app.props.headers);
if ( headers ) {
Object.keys(patterns).forEach(header => {
patterns[header].forEach(pattern => {
header = header.toLowerCase();
if ( headers ) {
Object.keys(patterns).forEach(header => {
patterns[header].forEach(pattern => {
header = header.toLowerCase();
if ( header in headers && pattern.regex.test(headers[header]) ) {
addDetected(app, pattern, 'headers', headers[header], header);
}
if ( header in headers && pattern.regex.test(headers[header]) ) {
this.addDetected(app, pattern, 'headers', headers[header], header);
}
});
});
});
}
}
}
/**
* Analyze environment variables
*/
function analyzeEnv(app, envs) {
var patterns = parsePatterns(app.props.env);
if ( patterns.length ) {
patterns.forEach(pattern => {
Object.keys(envs).forEach(env => {
if ( pattern.regex.test(envs[env]) ) {
addDetected(app, pattern, 'env', envs[env]);
}
})
});
/**
* Analyze environment variables
*/
analyzeEnv(app, envs) {
var patterns = this.parsePatterns(app.props.env);
if ( patterns.length ) {
patterns.forEach(pattern => {
Object.keys(envs).forEach(env => {
if ( pattern.regex.test(envs[env]) ) {
this.addDetected(app, pattern, 'env', envs[env]);
}
})
});
}
}
}
/**
* Analyze robots.txt
*/
function analyzeRobotsTxt(app, robotsTxt) {
var patterns = parsePatterns(app.props.robotsTxt);
/**
* Analyze robots.txt
*/
analyzeRobotsTxt(app, robotsTxt) {
var patterns = this.parsePatterns(app.props.robotsTxt);
if ( patterns.length ) {
patterns.forEach(pattern => {
if ( pattern.regex.test(robotsTxt) ) {
addDetected(app, pattern, 'robotsTxt', robotsTxt);
}
});
if ( patterns.length ) {
patterns.forEach(pattern => {
if ( pattern.regex.test(robotsTxt) ) {
this.addDetected(app, pattern, 'robotsTxt', robotsTxt);
}
});
}
}
}
/**
* Mark application as detected, set confidence and version
*/
function addDetected(app, pattern, type, value, key) {
app.detected = true;
/**
* Mark application as detected, set confidence and version
*/
addDetected(app, pattern, type, value, key) {
app.detected = true;
// Set confidence level
app.confidence[type + ' ' + ( key ? key + ' ' : '' ) + pattern.regex] = pattern.confidence || 100;
// Set confidence level
app.confidence[type + ' ' + ( key ? key + ' ' : '' ) + pattern.regex] = pattern.confidence || 100;
// Detect version number
if ( pattern.version ) {
var versions = [];
var version = pattern.version;
var matches = pattern.regex.exec(value);
// Detect version number
if ( pattern.version ) {
var versions = [];
var version = pattern.version;
var matches = pattern.regex.exec(value);
if ( matches ) {
matches.forEach((match, i) => {
// Parse ternary operator
var ternary = new RegExp('\\\\' + i + '\\?([^:]+):(.*)$').exec(version);
if ( matches ) {
matches.forEach((match, i) => {
// Parse ternary operator
var ternary = new RegExp('\\\\' + i + '\\?([^:]+):(.*)$').exec(version);
if ( ternary && ternary.length === 3 ) {
version = version.replace(ternary[0], match ? ternary[1] : ternary[2]);
}
if ( ternary && ternary.length === 3 ) {
version = version.replace(ternary[0], match ? ternary[1] : ternary[2]);
}
// Replace back references
version = version.replace(new RegExp('\\\\' + i, 'g'), match || '');
});
// Replace back references
version = version.replace(new RegExp('\\\\' + i, 'g'), match || '');
});
if ( version && versions.indexOf(version) === -1 ) {
versions.push(version);
}
if ( version && versions.indexOf(version) === -1 ) {
versions.push(version);
}
if ( versions.length ) {
// Use the longest detected version number
app.version = versions.reduce((a, b) => a.length > b.length ? a : b);
if ( versions.length ) {
// Use the longest detected version number
app.version = versions.reduce((a, b) => a.length > b.length ? a : b);
}
}
}
}
@ -558,5 +564,5 @@ class Application {
}
if ( typeof module === 'object' ) {
module.exports = wappalyzer;
module.exports = Wappalyzer;
}