Add short DOM notation

main
Elbert Alias 4 years ago
parent 5270da9536
commit 35090b3606

@ -66,6 +66,7 @@ Patterns (regular expressions) are kept in [`src/technologies.json`](https://git
},
"dom": {
"#example-id": {
"exists": "",
"attributes": {
"class": "example-class"
},
@ -277,7 +278,7 @@ Plus any of:
</tr>
<tr>
<td><code>dom</code></td>
<td>Object</td>
<td>String | Array | Object</td>
<td>
Uses a
<a

@ -87,12 +87,25 @@
}
},
"dom": {
"type": "object",
"additionalProperties": false,
"patternProperties": {
"^.+$": {
}
}
"oneOf": [
{
"type": "array",
"items": {
"$ref": "#/definitions/non-empty-non-blank-string"
}
},
{
"$ref": "#/definitions/non-empty-non-blank-string"
},
{
"type": "object",
"additionalProperties": false,
"patternProperties": {
"^.+$": {
}
}
}
]
},
"dns": {
"type": "object",

@ -73,22 +73,30 @@ function analyzeJs(js) {
function analyzeDom(dom) {
return Array.prototype.concat.apply(
[],
dom.map(({ name, selector, text, property, attribute, value }) => {
dom.map(({ name, selector, exists, text, property, attribute, value }) => {
const technology = Wappalyzer.technologies.find(
({ name: _name }) => name === _name
)
if (text) {
return analyzeManyToMany(technology, 'dom.text', { [selector]: [text] })
if (typeof exists !== 'undefined') {
return analyzeManyToMany(technology, 'dom.exists', {
[selector]: [''],
})
}
if (property) {
if (typeof text !== 'undefined') {
return analyzeManyToMany(technology, 'dom.text', {
[selector]: [text],
})
}
if (typeof property !== 'undefined') {
return analyzeManyToMany(technology, `dom.properties.${property}`, {
[selector]: [value],
})
}
if (attribute) {
if (typeof attribute !== 'undefined') {
return analyzeManyToMany(technology, `dom.attributes.${attribute}`, {
[selector]: [value],
})
@ -424,7 +432,7 @@ class Site {
await sleep(1000)
// page.on('console', (message) => this.log(message.text()))
page.on('console', (message) => this.log(message.text())) // TODO
// Links
const links = await this.promiseTimeout(
@ -560,68 +568,84 @@ class Site {
: !!value
Object.keys(dom).forEach((selector) => {
const nodes = document.querySelectorAll(selector)
let nodes = []
try {
nodes = document.querySelectorAll(selector)
} catch (error) {
// Continue
}
if (!nodes.length) {
return
}
dom[selector].forEach(({ text, properties, attributes }) => {
nodes.forEach((node) => {
if (text) {
const value = node.textContent.trim()
if (value) {
dom[selector].forEach(
({ exists, text, properties, attributes }) => {
nodes.forEach((node) => {
if (exists) {
technologies.push({
name,
selector,
text: value,
exists: '',
})
}
}
if (properties) {
Object.keys(properties).forEach((property) => {
if (
Object.prototype.hasOwnProperty.call(node, property)
) {
const value = node[property]
if (text) {
const value = node.textContent.trim()
if (value) {
technologies.push({
name,
selector,
text: value,
})
}
}
if (properties) {
Object.keys(properties).forEach((property) => {
if (
Object.prototype.hasOwnProperty.call(node, property)
) {
const value = node[property]
if (typeof value !== 'undefined') {
technologies.push({
name,
selector,
property,
value: toScalar(value),
})
}
}
})
}
if (attributes) {
Object.keys(attributes).forEach((attribute) => {
if (node.hasAttribute(attribute)) {
const value = node.getAttribute(attribute)
if (typeof value !== 'undefined') {
technologies.push({
name,
selector,
property,
attribute,
value: toScalar(value),
})
}
}
})
}
if (attributes) {
Object.keys(attributes).forEach((attribute) => {
if (node.hasAttribute(attribute)) {
const value = node.getAttribute(attribute)
technologies.push({
name,
selector,
attribute,
value: toScalar(value),
})
}
})
}
})
})
})
}
})
}
)
})
return technologies
}, [])
},
Wappalyzer.technologies
.filter(({ dom }) => dom)
.filter(({ dom }) => dom && dom.constructor === Object)
.map(({ name, dom }) => ({ name, dom }))
)
).catch(() => [])

@ -0,0 +1 @@
<svg viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg"><g fill="#e10098"><path d="m57.468 302.66-14.376-8.3 160.15-277.38 14.376 8.3z"/><path d="m39.8 272.2h320.3v16.6h-320.3z"/><path d="m206.348 374.026-160.21-92.5 8.3-14.376 160.21 92.5zm139.174-241.079-160.21-92.5 8.3-14.376 160.21 92.5z"/><path d="m54.482 132.883-8.3-14.375 160.21-92.5 8.3 14.376z"/><path d="m342.568 302.663-160.15-277.38 14.376-8.3 160.15 277.38zm-290.068-195.163h16.6v185h-16.6zm278.4 0h16.6v185h-16.6z"/><path d="m203.522 367-7.25-12.558 139.34-80.45 7.25 12.557z"/><path d="m369.5 297.9c-9.6 16.7-31 22.4-47.7 12.8s-22.4-31-12.8-47.7 31-22.4 47.7-12.8c16.8 9.7 22.5 31 12.8 47.7m-278.6-160.9c-9.6 16.7-31 22.4-47.7 12.8s-22.4-31-12.8-47.7 31-22.4 47.7-12.8c16.7 9.7 22.4 31 12.8 47.7m-60.4 160.9c-9.6-16.7-3.9-38 12.8-47.7 16.7-9.6 38-3.9 47.7 12.8 9.6 16.7 3.9 38-12.8 47.7-16.8 9.6-38.1 3.9-47.7-12.8m278.6-160.9c-9.6-16.7-3.9-38 12.8-47.7 16.7-9.6 38-3.9 47.7 12.8 9.6 16.7 3.9 38-12.8 47.7-16.7 9.6-38.1 3.9-47.7-12.8m-109.1 258.8c-19.3 0-34.9-15.6-34.9-34.9s15.6-34.9 34.9-34.9 34.9 15.6 34.9 34.9c0 19.2-15.6 34.9-34.9 34.9m0-321.8c-19.3 0-34.9-15.6-34.9-34.9s15.6-34.9 34.9-34.9 34.9 15.6 34.9 34.9-15.6 34.9-34.9 34.9"/></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -115,7 +115,11 @@ const Content = {
},
(response) => {
chrome.runtime.lastError
? reject(new Error(chrome.runtime.lastError.message))
? reject(
new Error(
`${chrome.runtime.lastError}: Driver.${func}(${args})`
)
)
: resolve(response)
}
)
@ -164,7 +168,7 @@ const Content = {
// DOM
const dom = technologies
.filter(({ dom }) => dom)
.filter(({ dom }) => dom && dom.constructor === Object)
.map(({ name, dom }) => ({ name, dom }))
.reduce((technologies, { name, dom }) => {
const toScalar = (value) =>
@ -173,14 +177,29 @@ const Content = {
: !!value
Object.keys(dom).forEach((selector) => {
const nodes = document.querySelectorAll(selector)
let nodes = []
try {
nodes = document.querySelectorAll(selector)
} catch (error) {
// eslint-disable-next-line no-console
console.error(error)
}
if (!nodes.length) {
return
}
dom[selector].forEach(({ text, properties, attributes }) => {
dom[selector].forEach(({ exists, text, properties, attributes }) => {
nodes.forEach((node) => {
if (exists) {
technologies.push({
name,
selector,
exists: '',
})
}
if (text) {
const value = node.textContent.trim()

@ -186,35 +186,50 @@ const Driver = {
url,
Array.prototype.concat.apply(
[],
dom.map(({ name, selector, text, property, attribute, value }) => {
const technology = Wappalyzer.technologies.find(
({ name: _name }) => name === _name
)
dom.map(
(
{ name, selector, exists, text, property, attribute, value },
index
) => {
const technology = Wappalyzer.technologies.find(
({ name: _name }) => name === _name
)
if (text) {
return analyzeManyToMany(technology, 'dom.text', {
[selector]: [text],
})
}
if (typeof exists !== 'undefined') {
return analyzeManyToMany(technology, 'dom.exists', {
[selector]: [''],
})
}
if (property) {
return analyzeManyToMany(technology, `dom.properties.${property}`, {
[selector]: [value],
})
}
if (typeof text !== 'undefined') {
return analyzeManyToMany(technology, 'dom.text', {
[selector]: [text],
})
}
if (attribute) {
return analyzeManyToMany(
technology,
`dom.attributes.${attribute}`,
{
[selector]: [value],
}
)
}
if (typeof property !== 'undefined') {
return analyzeManyToMany(
technology,
`dom.properties.${property}`,
{
[selector]: [value],
}
)
}
return []
})
if (typeof attribute !== 'undefined') {
return analyzeManyToMany(
technology,
`dom.attributes.${attribute}`,
{
[selector]: [value],
}
)
}
return []
}
)
)
)
},
@ -263,8 +278,6 @@ const Driver = {
* @param {Object} request
*/
async onWebRequestComplete(request) {
console.log('xxx', request.responseHeaders)
if (request.responseHeaders) {
if (await Driver.isDisabledDomain(request.url)) {
return

@ -320,18 +320,7 @@
36
],
"description": "33Across is a technology company focused on solving the challenge of consumer attention for automated advertising.",
"dom": {
"iframe[src*='.33across.com]": {
"attributes": {
"src": ""
}
},
"link[href*='.33across.com']": {
"attributes": {
"href": ""
}
}
},
"dom": "iframe[src*='.33across.com'], link[href*='.33across.com']",
"icon": "33Across.png",
"saas": true,
"website": "https://www.33across.com",
@ -401,13 +390,7 @@
71
],
"description": " A8.net is an affiliate marketing network.",
"dom": {
"img[src*='.a8.net']": {
"attributes": {
"src": "\\.a8\\.net"
}
}
},
"dom": "img[src*='.a8.net']",
"icon": "A8.net.png",
"js": {
"A8salesCookieRepository": "",
@ -535,13 +518,7 @@
6
],
"description": "ATSHOP is an all-in-one ecommerce platform.",
"dom": {
"link[href*='cdn.atshop.io']": {
"attributes": {
"href": ""
}
}
},
"dom": "link[href*='cdn.atshop.io']",
"icon": "ATSHOP.png",
"pricing": [
"low",
@ -618,13 +595,7 @@
71
],
"description": "AccessTrade is an affiliate marketing platform based on the CPA model developed by Interspace Co.",
"dom": {
"img[src*='.accesstrade.net'],img[data-src*='.accesstrade.net']": {
"attributes": {
"src": ""
}
}
},
"dom": "img[src*='.accesstrade.net'],img[data-src*='.accesstrade.net']",
"icon": "AccessTrade.png",
"website": "https://www.accesstrade.ne.jp"
},
@ -664,14 +635,7 @@
10
],
"description": "Ackee is a self-hosted, Node.js based analytics tool with a focus on privacy.",
"dom": {
"[data-ackee-domain-id]": {
"attributes": {
"data-ackee-domain-id": "",
"data-ackee-server": ""
}
}
},
"dom": "[data-ackee-domain-id], [data-ackee-server]",
"icon": "Ackee.png",
"js": {
"ackeeTracker": ""
@ -1166,13 +1130,7 @@
36
],
"description": "Affiliate B is an advertising system that allows site operators (HP, blogs, e-mail newsletters, etc.) to place advertiser advertisements on their own sites.",
"dom": {
"img[src*='www.afi-b.com']": {
"attributes": {
"src": "www\\.afi-b\\.com"
}
}
},
"dom": "img[src*='www.afi-b.com']",
"icon": "Affiliate B.svg",
"scripts": "t\\.afi-b\\.com",
"website": "https://affiliate-b.com"
@ -1182,13 +1140,7 @@
71
],
"description": "Affiliate Future is a provider of advertisers with marketing solution through its affiliate network and tools.",
"dom": {
"img[src*='banners.affiliatefuture.com']": {
"attributes": {
"src": "banners\\.affiliatefuture\\.com"
}
}
},
"dom": "img[src*='banners.affiliatefuture.com']",
"icon": "Affiliate Future.png",
"scripts": "tags\\.affiliatefuture\\.com",
"website": "http://affiliatefuture.com"
@ -1569,7 +1521,7 @@
},
"a[href*='amzn.to']": {
"attributes": {
"href": "^https?://amzn.to"
"href": ""
}
}
},
@ -1640,11 +1592,7 @@
41
],
"description": "Amazon Pay is an online payments processing service that is owned by Amazon. It lets you use the payment methods associated with your Amazon account to make payments for goods and services.",
"dom": {
"img[src*='amazonpay']": {
"text": ""
}
},
"dom": "img[src*='amazonpay']",
"icon": "Amazon Pay.svg",
"js": {
"AmazonPayments": "",
@ -1915,18 +1863,7 @@
36
],
"description": "AnyClip is a video engagement platform that uses an AI-driven content analysis engine to analyze and categorize video content in real-time to create personalized video feeds.",
"dom": {
"img[src*='.anyclip.com']": {
"attributes": {
"src": ""
}
},
"video[poster*='.anyclip.com']": {
"attributes": {
"poster": ""
}
}
},
"dom": "img[src*='.anyclip.com'], video[poster*='.anyclip.com']",
"icon": "AnyClip.svg",
"js": {
"anyclip": ""
@ -2076,18 +2013,7 @@
36
],
"description": "AppNexus is a cloud-based software platform that enables and optimizes programmatic online advertising.",
"dom": {
"iframe[src*='.adnxs.com']": {
"attributes": {
"src": ""
}
},
"img[src*='.adnxs.com']": {
"attributes": {
"src": ""
}
}
},
"dom": "iframe[src*='.adnxs.com'], img[src*='.adnxs.com']",
"icon": "AppNexus.svg",
"js": {
"appnexus": "",
@ -2134,9 +2060,7 @@
"description": "Apple Sign-in is based on OAuth 2.0 and OpenID Connect, and provides a privacy-friendly way for users to sign in to websites and apps.",
"dom": {
"a[href*='appleid.apple.com/auth/authorize']": {
"attributes": {
"href": ""
}
"exists": ""
},
"button": {
"text": "(Sign (in|up)|Log in|Continue) with Apple"
@ -2227,13 +2151,7 @@
31
],
"description": "Arc is a peer-to-peer CDN that pays site owners for using it. Instead of expensive servers in distant datacenters, Arc's network is comprised of browsers.",
"dom": {
"#arc-widget": {
"attributes": {
"id": ""
}
}
},
"dom": "#arc-widget",
"icon": "Arc.svg",
"js": {
"arc.p2pClient": "",
@ -2348,18 +2266,7 @@
53
],
"description": "Astute Solutions is a customer engagement software.",
"dom": {
"iframe[src*='.iperceptions.com]": {
"attributes": {
"src": ""
}
},
"link[href*='.iperceptions.com']": {
"attributes": {
"href": ""
}
}
},
"dom": "iframe[src*='.iperceptions.com'], link[href*='.iperceptions.com']",
"icon": "Astute Solutions.svg",
"pricing": [
"poa"
@ -2373,13 +2280,7 @@
29
],
"description": "Athena Search is a customizable autocomplete, feature-rich dashboard, smart predictions, real-time reports search engine developed from scratch by Syncit Groups.",
"dom": {
"link[href*='athena/autocomplete/css/autocomplete.css']": {
"attributes": {
"href": ""
}
}
},
"dom": "link[href*='athena/autocomplete/css/autocomplete.css']",
"icon": "Athena Search.svg",
"pricing": [
"payg"
@ -2443,11 +2344,7 @@
13
],
"cpe": "cpe:/a:atlassian:jira",
"dom": {
"#jira": {
"text": ""
}
},
"dom": "#jira",
"icon": "Atlassian Jira.svg",
"implies": "Java",
"js": {
@ -2609,13 +2506,7 @@
75
],
"description": "AWeber is an email marketing service.",
"dom": {
"form[action*='aweber.com']": {
"attributes": {
"action": "www\\.aweber\\.com"
}
}
},
"dom": "form[action*='aweber.com']",
"icon": "Aweber.svg",
"js": {
"awt_analytics": ""
@ -2896,14 +2787,7 @@
6
],
"description": "BigCommerce is a hosted ecommerce platform that allows business owners to set up an online store and sell their products online.",
"dom": {
"img[data-src*='.bigcommerce.com'],img[src*='.bigcommerce.com']": {
"attributes": {
"data-src": "",
"src": ""
}
}
},
"dom": "img[data-src*='.bigcommerce.com'], img[src*='.bigcommerce.com']",
"html": "<link href=[^>]+cdn\\d+\\.bigcommerce\\.com/",
"icon": "BigCommerce.svg",
"pricing": [
@ -3103,13 +2987,7 @@
77
],
"description": "Blue is a ecommerce data marketing, lead generation, real time bidding and recommendation solutions.",
"dom": {
"iframe[src*='.getblue.io']": {
"attributes": {
"src": ""
}
}
},
"dom": "iframe[src*='.getblue.io']",
"icon": "Blue.svg",
"js": {
"blueProductId": "",
@ -3232,11 +3110,7 @@
41
],
"description": "Bolt powers a checkout experience designed to convert shoppers.",
"dom": {
"bolt-checkout-button": {
"text": ""
}
},
"dom": "bolt-checkout-button",
"icon": "Bolt.svg",
"js": {
"BoltCheckout": "",
@ -3389,11 +3263,7 @@
67
],
"description": "Borlabs Cookie is a GDPR cookie consent plugin for WordPress.",
"dom": {
"#BorlabsCookieBox": {
"text": ""
}
},
"dom": "#BorlabsCookieBox",
"icon": "Borlabs Cookie.svg",
"implies": "WordPress",
"js": {
@ -3500,11 +3370,7 @@
41
],
"description": "Bread is a buy now, pay later platform for ecommerce websites.",
"dom": {
"#bread-mini-cart-btn": {
"text": ""
}
},
"dom": "#bread-mini-cart-btn",
"icon": "Bread.svg",
"js": {
"BreadCalc": "",
@ -3681,11 +3547,7 @@
1
],
"description": "Builder.io is a headless CMS with a powerful drag-and-drop visual editor that lets you build and optimize digital experiences with speed and flexibility. ",
"dom": {
"[data-builder-content-id], img[src*='cdn.builder.io']": {
"text": ""
}
},
"dom": "[data-builder-content-id], img[src*='cdn.builder.io']",
"icon": "Builder.svg",
"pricing": [
"low",
@ -3700,13 +3562,7 @@
"cats": [
19
],
"dom": {
"iframe[src*='buildertrend.net'], script[src*='buildertrend.net']": {
"attributes": {
"src": ""
}
}
},
"dom": "iframe[src*='buildertrend.net'], script[src*='buildertrend.net']",
"icon": "Buildertrend.svg",
"pricing": [
"mid",
@ -4002,11 +3858,7 @@
6
],
"description": "Websites that have a shopping cart or checkout page, either using a known ecommerce platform or a custom solution.",
"dom": {
"a[href*='/cart'], a[href*='/basket'], a[href*='/trolley'], a[href*='/bag'], a[href*='/shoppingbag'], a[href*='/checkout'], [aria-controls='cart']": {
"text": ""
}
},
"dom": "a[href*='/cart'], a[href*='/basket'], a[href*='/trolley'], a[href*='/bag'], a[href*='/shoppingbag'], a[href*='/checkout'], [aria-controls='cart']",
"icon": "Cart-generic.svg",
"website": "https://www.wappalyzer.com/technologies/ecommerce/cart-functionality"
},
@ -4428,14 +4280,7 @@
"cats": [
71
],
"dom": {
"a[href*='pay.clickbank.net?cbfid']": {
"text": ""
},
"img[width='1'][src*='hop.clickbank.net?affiliate']": {
"text": ""
}
},
"dom": "a[href*='pay.clickbank.net?cbfid'], img[width='1'][src*='hop.clickbank.net?affiliate']",
"icon": "Clickbank.svg",
"js": {
"cbtb": ""
@ -4540,13 +4385,7 @@
35
],
"description": "ClustrMaps widget is a visitor tracker, designed for general web and blog use.",
"dom": {
"img[src*='clustrmaps.com']": {
"attributes": {
"src": ""
}
}
},
"dom": "img[src*='clustrmaps.com']",
"icon": "ClustrMaps.svg",
"scripts": "clustrmaps\\.com",
"website": "https://clustrmaps.com/"
@ -4555,18 +4394,7 @@
"cats": [
19
],
"dom": {
"a[href*='co-construct.com/skins']": {
"attributes": {
"href": ""
}
},
"iframe[src*='co-construct.com']": {
"attributes": {
"src": ""
}
}
},
"dom": "a[href*='co-construct.com/skins'], iframe[src*='co-construct.com']",
"icon": "CoConstruct.png",
"pricing": [
"mid",
@ -4658,13 +4486,7 @@
41
],
"description": "Coinbase Commerce is a platform that enables merchants to accept cryptocurrency payments.",
"dom": {
"a[href^='https://commerce.coinbase.com/checkout/']": {
"attributes": {
"href": "^https://commerce\\.coinbase\\.com/checkout/[a-z0-9-]+$"
}
}
},
"dom": "a[href^='https://commerce.coinbase.com/checkout/']",
"icon": "Coinbase.svg",
"website": "https://commerce.coinbase.com/"
},
@ -4904,18 +4726,7 @@
75
],
"description": "ConvertKit is an email marketing tool built for content creators.",
"dom": {
"form[action*='.convertkit.com']": {
"attributes": {
"action": ""
}
},
"link[href*='.convertkit.com']": {
"attributes": {
"href": ""
}
}
},
"dom": "form[action*='.convertkit.com'], link[href*='.convertkit.com']",
"icon": "ConvertKit.svg",
"pricing": [
"low",
@ -4949,11 +4760,7 @@
"cats": [
67
],
"dom": {
"#cookie-law-info-bar": {
"text": ""
}
},
"dom": "#cookie-law-info-bar",
"icon": "cookieyes.svg",
"scripts": "app\\.cookieyes\\.com/client_data/",
"website": "https://www.cookieyes.com/"
@ -5448,13 +5255,7 @@
32
],
"description": "Dealer Spike is a digital marketing and advertising company focused that helps dealers grow their business.",
"dom": {
"meta[name='author'][content*='Dealer Spike']": {
"attributes": {
"content": ""
}
}
},
"dom": "meta[name='author'][content*='Dealer Spike']",
"icon": "Dealer Spike.svg",
"pricing": [
"poa"
@ -5613,13 +5414,7 @@
36
],
"description": "District M is a programmatic advertising exchange.",
"dom": {
"iframe[src*='.districtm.io']": {
"attributes": {
"src": ""
}
}
},
"dom": "iframe[src*='.districtm.io']",
"icon": "District M.svg",
"saas": true,
"website": "https://districtm.net",
@ -5909,18 +5704,7 @@
],
"cpe": "cpe:/a:commerceguys:commerce",
"description": "Drupal Commerce is open-source ecommerce software that augments the content management system Drupal.",
"dom": {
"aside#cart-offcanvas": {
"attributes": {
"id": ""
}
},
"form.commerce-order-item-add-to-cart-form,form.commerce-add-to-cart": {
"attributes": {
"class": ""
}
}
},
"dom": "aside#cart-offcanvas, form.commerce-order-item-add-to-cart-form,form.commerce-add-to-cart",
"html": "<[^>]+(?:id=\"block[_-]commerce[_-]cart[_-]cart|class=\"commerce[_-]product[_-]field)",
"icon": "Drupal Commerce.png",
"implies": "Drupal",
@ -6318,11 +6102,7 @@
47
],
"description": "Emotion is a library designed for writing CSS styles with JavaScript.",
"dom": {
"style[data-emotion], style[data-emotion-css]": {
"text": ""
}
},
"dom": "style[data-emotion], style[data-emotion-css]",
"icon": "Emotion.png",
"website": "http://emotion.sh"
},
@ -6680,13 +6460,7 @@
],
"description": "Pinterest Conversion Tag allows you to track actions people take on your website after viewing your Promoted Pin.",
"icon": "Pinterest.svg",
"dom": {
"img[src*='ct.pinterest.com/v3/?tid']": {
"attributes": {
"src": ""
}
}
},
"dom": "img[src*='ct.pinterest.com/v3/?tid']",
"js": {
"pintrk": ""
},
@ -6697,13 +6471,7 @@
10
],
"description": "Facebook pixel is an analytics tool that allows you to measure the effectiveness of your advertising.",
"dom": {
"img[src*='facebook.com/tr']": {
"attributes": {
"src": ""
}
}
},
"dom": "img[src*='facebook.com/tr']",
"icon": "Facebook.svg",
"js": {
"_fbq": ""
@ -6881,13 +6649,7 @@
71
],
"description": "FinanceAds is a performance marketing agency that has grown affiliate network for the financial sector.",
"dom": {
"link[href*='js.financeads.net'], link[href*='js.financeads.com'], a[href*='www.financeads.net/tc.php']": {
"attributes": {
"href": ""
}
}
},
"dom": "link[href*='js.financeads.net'], link[href*='js.financeads.com'], a[href*='www.financeads.net/tc.php']",
"icon": "Financeads.png",
"pricing": [
"payg"
@ -6942,13 +6704,7 @@
32
],
"description": "Firepush is an omnichannel marketing app that helps Shopify stores to drive sales with automated web push, email and SMS campaigns.",
"dom": {
"link[href*='cdn.firepush.net']": {
"attributes": {
"href": ""
}
}
},
"dom": "link[href*='cdn.firepush.net']",
"icon": "Firepush.svg",
"pricing": [
"low",
@ -8098,14 +7854,7 @@
41
],
"description": "Google Pay is a digital wallet platform and online payment system developed by Google to power in-app and tap-to-pay purchases on mobile devices, enabling users to make payments with Android phones, tablets or watches.",
"dom": {
"[aria-labelledby='pi-google_pay']": {
"text": ""
},
"ul[data-shopify-buttoncontainer] li": {
"text": "GooglePay"
}
},
"dom": "[aria-labelledby='pi-google_pay'], ul[data-shopify-buttoncontainer] li",
"icon": "Google.svg",
"scripts": [
"pay\\.google\\.com/([a-z/]+)/pay\\.js"
@ -8370,13 +8119,7 @@
72
],
"description": "Guestonline is a restaurant table booking widget.",
"dom": {
"iframe[src*='guestonline']": {
"attributes": {
"src": "ib\\.guestonline\\.\\w+"
}
}
},
"dom": "iframe[src*='ib.guestonline.']",
"icon": "Guestonline.svg",
"pricing": [
"low",
@ -8391,18 +8134,7 @@
36
],
"description": "GumGum is a technology and media company specializing in contextual intelligence.",
"dom": {
"iframe[src*='gumgum.com']": {
"attributes": {
"src": ""
}
},
"img[src*='gumgum.com']": {
"attributes": {
"src": ""
}
}
},
"dom": "iframe[src*='gumgum.com'], img[src*='gumgum.com']",
"icon": "GumGum.png",
"pricing": [
"low",
@ -8604,11 +8336,7 @@
18
],
"description": "Helix Ultimate a free template framework for Joomla.",
"dom": {
"header#sp-header, body.helix-ultimate": {
"text": ""
}
},
"dom": "header#sp-header, body.helix-ultimate",
"icon": "HelixUltimate.svg",
"implies": "Joomla",
"oss": true,
@ -9430,14 +9158,8 @@
"cats": [
71
],
"description": "JANet is an affiliate marketing network.",
"dom": {
"img[src*='.j-a-net.jp'],img[data-src*='.j-a-net.jp']": {
"attributes": {
"src": ""
}
}
},
"description": "JANet is an affiliate marketing network.",
"dom": "img[src*='.j-a-net.jp'],img[data-src*='.j-a-net.jp']",
"icon": "JANet.png",
"website": "https://j-a-net.jp"
},
@ -9536,13 +9258,7 @@
14
],
"description": "JW Player is a online video player with video engagement analytics, custom video player skins, and live video streaming capability.",
"dom": {
"div[data-video-provider*=jwplayer]": {
"attributes": {
"data-video-provider": ""
}
}
},
"dom": "div[data-video-provider*=jwplayer]",
"icon": "JW Player.svg",
"js": {
"jwDefaults": "",
@ -9904,13 +9620,7 @@
"kameleoonVisitorCode": ""
},
"description": "Kameleoon is a personalisation technology platform for real-time omnichannel optimisation and conversion.",
"dom": {
"link[href*='.kameleoon.eu/kameleoon.js']": {
"attributes": {
"href": ""
}
}
},
"dom": "link[href*='.kameleoon.eu/kameleoon.js']",
"icon": "Kameleoon.svg",
"js": {
"Kameleoon.Gatherer.SCRIPT_VERSION": "(.+)\\;version:\\1",
@ -9975,13 +9685,7 @@
53
],
"description": "Keap offers an email marketing and sales platform for small businesses, including products to manage customers, customer relationship management, marketing, and ecommerce.",
"dom": {
"form[action*='property.infusionsoft.com']": {
"attributes": {
"action": ""
}
}
},
"dom": "form[action*='property.infusionsoft.com']",
"icon": "Keap.svg",
"pricing": [
"low",
@ -10336,13 +10040,7 @@
6
],
"description": "Kooomo is a SaaS ecommerce platform with a focus on localisation and internationalisation.",
"dom": {
"img[src*='.kooomo-cloud.com']": {
"attributes": {
"src": ""
}
}
},
"dom": "img[src*='.kooomo-cloud.com']",
"icon": "Kooomo.svg",
"implies": [
"PHP",
@ -10408,13 +10106,7 @@
36
],
"description": "LKQD is a video advertising platform that enables publishers to serve video ads across multiple devices and formats.",
"dom": {
"iframe[src*='.lkqd.net']": {
"attributes": {
"src": ""
}
}
},
"dom": "iframe[src*='.lkqd.net']",
"icon": "LKQD.svg",
"js": {
"lkqdCall": "",
@ -10655,13 +10347,7 @@
"cats": [
10
],
"dom": {
"noscript > img[src*='dc.ads.linkedin.com']": {
"attributes": {
"src": ""
}
}
},
"dom": "noscript > img[src*='dc.ads.linkedin.com']",
"icon": "Linkedin.svg",
"js": {
"_linkedin_data_partner_id": ""
@ -10853,13 +10539,7 @@
67
],
"description": "LiveRamp PCM is a preference and consent management platform that enables comply with the ePrivacy Directive, GDPR, CCPA, and other data protection and privacy laws and regulations.",
"dom": {
"iframe[src*='gdpr-consent-tool\\.privacymanager\\.io']": {
"attributes": {
"src": ""
}
}
},
"dom": "iframe[src*='gdpr-consent-tool\\.privacymanager\\.io']",
"icon": "LiveRamp.svg",
"js": {
"wpJsonpLiverampGdprCmp": ""
@ -11365,13 +11045,7 @@
35
],
"description": "Mapbox GL JS is a JavaScript library that uses WebGL to render interactive maps from vector tiles and Mapbox styles.",
"dom": {
"link[href*='mapbox-gl.css']": {
"attributes": {
"href": ""
}
}
},
"dom": "link[href*='mapbox-gl.css']",
"icon": "Mapbogljs.png",
"js": {
"mapboxgl.version": "^(.+)$\\;version:\\1\\;confidence:0"
@ -11689,13 +11363,7 @@
72
],
"description": "Meeting Scheduler is a schedule appointments widget.",
"dom": {
"a[href*='bookmenow.info/book']": {
"attributes": {
"href": ""
}
}
},
"dom": "a[href*='bookmenow.info/book']",
"icon": "Meeting Scheduler.png",
"scripts": "bookmenow\\.info/(?:runtime|main).+\\.js",
"website": "https://bookmenow.info"
@ -12587,11 +12255,7 @@
6
],
"description": "NEO is an ecommerce software that manages multiple online stores.",
"dom": {
"#svr[value^=\"NEOWEBV\"]": {
"text": ""
}
},
"dom": "#svr[value^=\"NEOWEBV\"]",
"headers": {
"powered": "jet-neo"
},
@ -12603,16 +12267,7 @@
"cats": [
66
],
"dom": {
".nsw-container, .nsw-header, .nsw-icon": {
"text": ""
},
"link[href*='nsw-design-system']": {
"attributes": {
"href": ""
}
}
},
"dom": ".nsw-container, .nsw-header, .nsw-icon, link[href*='nsw-design-system']",
"icon": "NSW Design System.svg",
"js": {
"NSW.initSite": ""
@ -13081,13 +12736,7 @@
"ometria": ""
},
"description": "Ometria is a customer insight and marketing automation platform.",
"dom": {
"form[action*='api.ometria.com']": {
"attributes": {
"action": "api\\.ometria\\.com"
}
}
},
"dom": "form[action*='api.ometria.com']",
"icon": "Ometria.svg",
"js": {
"AddOmetriaBasket": "",
@ -13122,13 +12771,7 @@
74
],
"description": "Omniconvert is an award-winning conversion rate optimisation (CRO) software that can be used for A/B testing, online surveys, traffic segmentation.",
"dom": {
"link[href*='app.omniconvert.com']": {
"attributes": {
"href": ""
}
}
},
"dom": "link[href*='app.omniconvert.com']",
"icon": "Omniconvert.png",
"js": {
"_omni": ""
@ -13446,13 +13089,7 @@
35
],
"description": "OpenStreetMap is a free, editable map of the whole world that is being built by volunteers largely from scratch and released with an open-content license.",
"dom": {
"iframe[src*='openstreetmap.org'],iframe[data-lazy-src*='openstreetmap.org']": {
"attributes": {
"src": ""
}
}
},
"dom": "iframe[src*='openstreetmap.org'],iframe[data-lazy-src*='openstreetmap.org']",
"icon": "OpenStreetMap.svg",
"oss": true,
"website": "https://www.openstreetmap.org"
@ -13483,18 +13120,7 @@
],
"cpe": "cpe:/a:openx:openx",
"description": "OpenX is a programmatic advertising technology company.",
"dom": {
"iframe[src*='.openx.net']": {
"attributes": {
"src": ""
}
},
"img[src*='.openx.net']": {
"attributes": {
"src": ""
}
}
},
"dom": "iframe[src*='.openx.net'], img[src*='.openx.net']",
"icon": "OpenX.png",
"js": {
"openx.name": "openx"
@ -13993,13 +13619,7 @@
41
],
"description": "PayBright is a Canadian fintech company that offers short-term interest-free installment loans for online shopping to consumers at checkout.",
"dom": {
"link[href*='app.paybright.com']": {
"attributes": {
"href": ""
}
}
},
"dom": "link[href*='app.paybright.com']",
"icon": "PayBright.png",
"js": {
"_paybright_config": ""
@ -14032,18 +13652,8 @@
"button": {
"text": "PayPal"
},
"iframe[src*='paypal.com']": {
"attributes": {
"src": ""
}
},
"img[src*='paypal.com'], img[src*='paypalobjects.com']": {
"text": ""
},
"link": {
"attributes": {
"href": "paypal-express-checkout"
}
"iframe[src*='paypal.com'], img[src*='paypal.com'], img[src*='paypalobjects.com'], link[href*='paypal-express-checkout']": {
"exists": ""
}
},
"html": "<input[^>]+_s-xclick",
@ -14325,13 +13935,7 @@
5
],
"description": "Picreel is a conversion optimisation software.",
"dom": {
"iframe[src*='app.picreel.com']": {
"attributes": {
"src": ""
}
}
},
"dom": "iframe[src*='app.picreel.com']",
"icon": "Picreel.svg",
"js": {
"picreel": ""
@ -14353,6 +13957,7 @@
"headers": {
"X-Powered-By": "^pimcore$"
},
"dom": ".pimcore_area_content",
"icon": "pimcore.svg",
"implies": "PHP",
"website": "http://pimcore.org"

@ -1,24 +1,24 @@
'use strict'
function toArray(value) {
return Array.isArray(value) ? value : [value]
}
const Wappalyzer = {
technologies: [],
categories: [],
slugify(string) {
return string
slugify: (string) =>
string
.toLowerCase()
.replace(/[^a-z0-9-]/g, '-')
.replace(/--+/g, '-')
.replace(/(?:^-|-$)/g, '')
},
.replace(/(?:^-|-$)/g, ''),
getTechnology(name) {
return Wappalyzer.technologies.find(({ name: _name }) => name === _name)
},
getTechnology: (name) =>
Wappalyzer.technologies.find(({ name: _name }) => name === _name),
getCategory(id) {
return Wappalyzer.categories.find(({ id: _id }) => id === _id)
},
getCategory: (id) => Wappalyzer.categories.find(({ id: _id }) => id === _id),
/**
* Resolve promises for implied technology.
@ -270,7 +270,19 @@ const Wappalyzer = {
headers: transform(headers),
dns: transform(dns),
cookies: transform(cookies),
dom: transform(dom, true),
dom: transform(
typeof dom === 'string' || Array.isArray(dom)
? toArray(dom).reduce(
(dom, selector) => ({
...dom,
[selector]: { exists: '' },
}),
{}
)
: dom,
false,
false
),
html: transform(html),
css: transform(css),
certIssuer: transform(certIssuer),
@ -319,13 +331,11 @@ const Wappalyzer = {
* @param {string|array} patterns
* @param {boolean} caseSensitive
*/
transformPatterns(patterns, caseSensitive = false) {
transformPatterns(patterns, caseSensitive = false, isRegex = true) {
if (!patterns) {
return []
}
const toArray = (value) => (Array.isArray(value) ? value : [value])
if (typeof patterns === 'string' || Array.isArray(patterns)) {
patterns = { main: patterns }
}
@ -333,7 +343,7 @@ const Wappalyzer = {
const parsed = Object.keys(patterns).reduce((parsed, key) => {
parsed[caseSensitive ? key : key.toLowerCase()] = toArray(
patterns[key]
).map((pattern) => Wappalyzer.parsePattern(pattern))
).map((pattern) => Wappalyzer.parsePattern(pattern, isRegex))
return parsed
}, {})
@ -345,7 +355,7 @@ const Wappalyzer = {
* Extract information from regex pattern.
* @param {string|object} pattern
*/
parsePattern(pattern) {
parsePattern(pattern, isRegex = true) {
if (typeof pattern === 'object') {
return Object.keys(pattern).reduce(
(parsed, key) => ({
@ -369,7 +379,10 @@ const Wappalyzer = {
attrs.value = attr
// Escape slashes in regular expression
attrs.regex = new RegExp(attr.replace(/\//g, '\\/'), 'i')
attrs.regex = new RegExp(
isRegex ? attr.replace(/\//g, '\\/') : '',
'i'
)
}
return attrs