|
|
@ -8,9 +8,6 @@ const { agent, open, i18n, getOption, setOption, promisify, sendMessage } =
|
|
|
|
const baseUrl = 'https://www.wappalyzer.com'
|
|
|
|
const baseUrl = 'https://www.wappalyzer.com'
|
|
|
|
const utm = '?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer'
|
|
|
|
const utm = '?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer'
|
|
|
|
|
|
|
|
|
|
|
|
let csv = ''
|
|
|
|
|
|
|
|
let csvFilename = ''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const footers = [
|
|
|
|
const footers = [
|
|
|
|
{
|
|
|
|
{
|
|
|
|
heading: 'Generate sales leads',
|
|
|
|
heading: 'Generate sales leads',
|
|
|
@ -107,6 +104,71 @@ function setDisabledDomain(enabled) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getCsv() {
|
|
|
|
|
|
|
|
let hostname = ''
|
|
|
|
|
|
|
|
let www = false
|
|
|
|
|
|
|
|
let https = false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
let protocol = ''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;({ hostname, protocol } = new URL(Popup.cache.url))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
www = hostname.startsWith('www')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
https = protocol === 'https:'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hostname = hostname.replace(/^www\./, '')
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
|
|
// Continue
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const columns = [
|
|
|
|
|
|
|
|
'URL',
|
|
|
|
|
|
|
|
...Popup.cache.categories.map(({ id }) =>
|
|
|
|
|
|
|
|
chrome.i18n.getMessage(`categoryName${id}`)
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
...attributeKeys.map((key) =>
|
|
|
|
|
|
|
|
chrome.i18n.getMessage(
|
|
|
|
|
|
|
|
`attribute${
|
|
|
|
|
|
|
|
key.charAt(0).toUpperCase() + key.slice(1).replace('.', '_')
|
|
|
|
|
|
|
|
}`
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const csv = [`"${columns.join('","')}"`]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const filename = `wappalyzer${
|
|
|
|
|
|
|
|
hostname ? `_${hostname.replace('.', '-')}` : ''
|
|
|
|
|
|
|
|
}.csv`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const row = [`http${https ? 's' : ''}://${www ? 'www.' : ''}${hostname}`]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
row.push(
|
|
|
|
|
|
|
|
...Popup.cache.categories.reduce((categories, { id }) => {
|
|
|
|
|
|
|
|
categories.push(
|
|
|
|
|
|
|
|
Popup.cache.detections
|
|
|
|
|
|
|
|
.filter(({ categories }) =>
|
|
|
|
|
|
|
|
categories.some(({ id: _id }) => _id === id)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.map(({ name }) => name)
|
|
|
|
|
|
|
|
.join(' ; ')
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return categories
|
|
|
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
row.push(
|
|
|
|
|
|
|
|
...attributeKeys.map((key) => csvEscape(Popup.cache.attributeValues[key]))
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
csv.push(`"${row.join('","')}"`)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return { csv, filename }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function csvEscape(value = '') {
|
|
|
|
function csvEscape(value = '') {
|
|
|
|
if (Array.isArray(value)) {
|
|
|
|
if (Array.isArray(value)) {
|
|
|
|
value = value
|
|
|
|
value = value
|
|
|
@ -136,6 +198,13 @@ const Popup = {
|
|
|
|
* Initialise popup
|
|
|
|
* Initialise popup
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
async init() {
|
|
|
|
async init() {
|
|
|
|
|
|
|
|
Popup.cache = {
|
|
|
|
|
|
|
|
url: '',
|
|
|
|
|
|
|
|
categories: [],
|
|
|
|
|
|
|
|
detections: [],
|
|
|
|
|
|
|
|
attributeValues: {},
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const el = {
|
|
|
|
const el = {
|
|
|
|
body: document.body,
|
|
|
|
body: document.body,
|
|
|
|
terms: document.querySelector('.terms'),
|
|
|
|
terms: document.querySelector('.terms'),
|
|
|
@ -150,6 +219,7 @@ const Popup = {
|
|
|
|
headerSwitchDisabled: document.querySelector('.header__switch--disabled'),
|
|
|
|
headerSwitchDisabled: document.querySelector('.header__switch--disabled'),
|
|
|
|
plusConfigureApiKey: document.querySelector('.plus-configure__apikey'),
|
|
|
|
plusConfigureApiKey: document.querySelector('.plus-configure__apikey'),
|
|
|
|
plusConfigureSave: document.querySelector('.plus-configure__save'),
|
|
|
|
plusConfigureSave: document.querySelector('.plus-configure__save'),
|
|
|
|
|
|
|
|
plusDownload: document.querySelector('.plus-download'),
|
|
|
|
plusDownloadLink: document.querySelector(
|
|
|
|
plusDownloadLink: document.querySelector(
|
|
|
|
'.plus-download__button .button__link'
|
|
|
|
'.plus-download__button .button__link'
|
|
|
|
),
|
|
|
|
),
|
|
|
@ -246,6 +316,8 @@ const Popup = {
|
|
|
|
;[{ url }] = tabs
|
|
|
|
;[{ url }] = tabs
|
|
|
|
|
|
|
|
|
|
|
|
if (url.startsWith('http')) {
|
|
|
|
if (url.startsWith('http')) {
|
|
|
|
|
|
|
|
Popup.cache.url = url
|
|
|
|
|
|
|
|
|
|
|
|
const { hostname } = new URL(url)
|
|
|
|
const { hostname } = new URL(url)
|
|
|
|
|
|
|
|
|
|
|
|
setDisabledDomain(disabledDomains.includes(hostname))
|
|
|
|
setDisabledDomain(disabledDomains.includes(hostname))
|
|
|
@ -322,6 +394,7 @@ const Popup = {
|
|
|
|
el.tabItems[index].classList.remove('tab-item--hidden')
|
|
|
|
el.tabItems[index].classList.remove('tab-item--hidden')
|
|
|
|
|
|
|
|
|
|
|
|
el.credits.classList.add('credits--hidden')
|
|
|
|
el.credits.classList.add('credits--hidden')
|
|
|
|
|
|
|
|
el.plusDownload.classList.remove('plus-download--hidden')
|
|
|
|
el.footer.classList.remove('footer--hidden')
|
|
|
|
el.footer.classList.remove('footer--hidden')
|
|
|
|
|
|
|
|
|
|
|
|
if (tab.classList.contains('tab--plus')) {
|
|
|
|
if (tab.classList.contains('tab--plus')) {
|
|
|
@ -331,7 +404,7 @@ const Popup = {
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Download
|
|
|
|
// Download
|
|
|
|
el.plusDownloadLink.addEventListener('click', (event) => Popup.downloadCsv)
|
|
|
|
el.plusDownloadLink.addEventListener('click', Popup.downloadCsv)
|
|
|
|
|
|
|
|
|
|
|
|
// Footer
|
|
|
|
// Footer
|
|
|
|
const item =
|
|
|
|
const item =
|
|
|
@ -381,6 +454,8 @@ const Popup = {
|
|
|
|
|
|
|
|
|
|
|
|
// Apply internationalization
|
|
|
|
// Apply internationalization
|
|
|
|
i18n()
|
|
|
|
i18n()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Popup.cache.categories = await Popup.driver('getCategories')
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
driver(func, args) {
|
|
|
|
driver(func, args) {
|
|
|
@ -423,9 +498,12 @@ const Popup = {
|
|
|
|
* @param {Array} detections
|
|
|
|
* @param {Array} detections
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
async onGetDetections(detections = []) {
|
|
|
|
async onGetDetections(detections = []) {
|
|
|
|
|
|
|
|
Popup.cache.detections = detections
|
|
|
|
|
|
|
|
|
|
|
|
const el = {
|
|
|
|
const el = {
|
|
|
|
empty: document.querySelector('.empty'),
|
|
|
|
empty: document.querySelector('.empty'),
|
|
|
|
detections: document.querySelector('.detections'),
|
|
|
|
detections: document.querySelector('.detections'),
|
|
|
|
|
|
|
|
plusDownload: document.querySelector('.plus-download'),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
detections = (detections || [])
|
|
|
|
detections = (detections || [])
|
|
|
@ -435,12 +513,14 @@ const Popup = {
|
|
|
|
if (!detections || !detections.length) {
|
|
|
|
if (!detections || !detections.length) {
|
|
|
|
el.empty.classList.remove('empty--hidden')
|
|
|
|
el.empty.classList.remove('empty--hidden')
|
|
|
|
el.detections.classList.add('detections--hidden')
|
|
|
|
el.detections.classList.add('detections--hidden')
|
|
|
|
|
|
|
|
el.plusDownload.classList.add('plus-download--hidden')
|
|
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
el.empty.classList.add('empty--hidden')
|
|
|
|
el.empty.classList.add('empty--hidden')
|
|
|
|
el.detections.classList.remove('detections--hidden')
|
|
|
|
el.detections.classList.remove('detections--hidden')
|
|
|
|
|
|
|
|
el.plusDownload.classList.remove('plus-download--hidden')
|
|
|
|
|
|
|
|
|
|
|
|
while (el.detections.firstChild) {
|
|
|
|
while (el.detections.firstChild) {
|
|
|
|
el.detections.removeChild(detections.firstChild)
|
|
|
|
el.detections.removeChild(detections.firstChild)
|
|
|
@ -554,9 +634,6 @@ const Popup = {
|
|
|
|
crawl: document.querySelector('.plus-crawl'),
|
|
|
|
crawl: document.querySelector('.plus-crawl'),
|
|
|
|
error: document.querySelector('.plus-error'),
|
|
|
|
error: document.querySelector('.plus-error'),
|
|
|
|
download: document.querySelector('.plus-download'),
|
|
|
|
download: document.querySelector('.plus-download'),
|
|
|
|
downloadLink: document.querySelector(
|
|
|
|
|
|
|
|
'.plus-download__button .button__link'
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
errorMessage: document.querySelector('.plus-error__message'),
|
|
|
|
errorMessage: document.querySelector('.plus-error__message'),
|
|
|
|
configure: document.querySelector('.plus-configure'),
|
|
|
|
configure: document.querySelector('.plus-configure'),
|
|
|
|
credits: document.querySelector('.credits'),
|
|
|
|
credits: document.querySelector('.credits'),
|
|
|
@ -565,6 +642,7 @@ const Popup = {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
el.error.classList.add('plus-error--hidden')
|
|
|
|
el.error.classList.add('plus-error--hidden')
|
|
|
|
|
|
|
|
el.download.classList.add('plus-download--hidden')
|
|
|
|
|
|
|
|
|
|
|
|
if (apiKey) {
|
|
|
|
if (apiKey) {
|
|
|
|
el.loading.classList.remove('loading--hidden')
|
|
|
|
el.loading.classList.remove('loading--hidden')
|
|
|
@ -579,7 +657,6 @@ const Popup = {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
el.panels.classList.add('panels--hidden')
|
|
|
|
el.panels.classList.add('panels--hidden')
|
|
|
|
el.download.classList.add('plus-download--hidden')
|
|
|
|
|
|
|
|
el.empty.classList.add('plus-empty--hidden')
|
|
|
|
el.empty.classList.add('plus-empty--hidden')
|
|
|
|
el.crawl.classList.add('plus-crawl--hidden')
|
|
|
|
el.crawl.classList.add('plus-crawl--hidden')
|
|
|
|
el.error.classList.add('plus-error--hidden')
|
|
|
|
el.error.classList.add('plus-error--hidden')
|
|
|
@ -588,24 +665,6 @@ const Popup = {
|
|
|
|
el.panels.removeChild(el.panels.lastElementChild)
|
|
|
|
el.panels.removeChild(el.panels.lastElementChild)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let hostname = ''
|
|
|
|
|
|
|
|
let www = false
|
|
|
|
|
|
|
|
let https = false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
let protocol = ''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;({ hostname, protocol } = new URL(url))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
www = hostname.startsWith('www')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
https = protocol === 'https:'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hostname = hostname.replace(/^www\./, '')
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
|
|
// Continue
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
const response = await fetch(
|
|
|
|
const response = await fetch(
|
|
|
|
`https://api.wappalyzer.com/v2/plus/${encodeURIComponent(url)}`,
|
|
|
|
`https://api.wappalyzer.com/v2/plus/${encodeURIComponent(url)}`,
|
|
|
@ -635,9 +694,8 @@ const Popup = {
|
|
|
|
10
|
|
|
|
10
|
|
|
|
).toLocaleString()
|
|
|
|
).toLocaleString()
|
|
|
|
|
|
|
|
|
|
|
|
el.credits.classList.remove('credits--hidden')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
el.loading.classList.add('loading--hidden')
|
|
|
|
el.loading.classList.add('loading--hidden')
|
|
|
|
|
|
|
|
el.credits.classList.remove('credits--hidden')
|
|
|
|
|
|
|
|
|
|
|
|
if (crawl) {
|
|
|
|
if (crawl) {
|
|
|
|
document
|
|
|
|
document
|
|
|
@ -649,50 +707,11 @@ const Popup = {
|
|
|
|
|
|
|
|
|
|
|
|
if (!Object.keys(attributes).length) {
|
|
|
|
if (!Object.keys(attributes).length) {
|
|
|
|
el.empty.classList.remove('plus-empty--hidden')
|
|
|
|
el.empty.classList.remove('plus-empty--hidden')
|
|
|
|
|
|
|
|
el.download.classList.remove('plus-download--hidden')
|
|
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const categories = await Popup.driver('getCategories')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const columns = [
|
|
|
|
|
|
|
|
'URL',
|
|
|
|
|
|
|
|
...categories.map(({ id }) =>
|
|
|
|
|
|
|
|
chrome.i18n.getMessage(`categoryName${id}`)
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
...attributeKeys.map((key) =>
|
|
|
|
|
|
|
|
chrome.i18n.getMessage(
|
|
|
|
|
|
|
|
`attribute${
|
|
|
|
|
|
|
|
key.charAt(0).toUpperCase() + key.slice(1).replace('.', '_')
|
|
|
|
|
|
|
|
}`
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
csv = [`"${columns.join('","')}"`]
|
|
|
|
|
|
|
|
csvFilename = `wappalyzer${
|
|
|
|
|
|
|
|
hostname ? `_${hostname.replace('.', '-')}` : ''
|
|
|
|
|
|
|
|
}.csv`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const row = [`http${https ? 's' : ''}://${www ? 'www.' : ''}${hostname}`]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const detections = await Popup.driver('getDetections')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
row.push(
|
|
|
|
|
|
|
|
...categories.reduce((categories, { id }) => {
|
|
|
|
|
|
|
|
categories.push(
|
|
|
|
|
|
|
|
detections
|
|
|
|
|
|
|
|
.filter(({ categories }) =>
|
|
|
|
|
|
|
|
categories.some(({ id: _id }) => _id === id)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.map(({ name }) => name)
|
|
|
|
|
|
|
|
.join(' ; ')
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return categories
|
|
|
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const attributeValues = {}
|
|
|
|
const attributeValues = {}
|
|
|
|
|
|
|
|
|
|
|
|
Object.keys(attributes).forEach((set) => {
|
|
|
|
Object.keys(attributes).forEach((set) => {
|
|
|
@ -800,26 +819,7 @@ const Popup = {
|
|
|
|
el.panels.appendChild(panel)
|
|
|
|
el.panels.appendChild(panel)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
row.push(...attributeKeys.map((key) => csvEscape(attributeValues[key])))
|
|
|
|
Popup.cache.attributeValues = attributeValues
|
|
|
|
|
|
|
|
|
|
|
|
csv.push(`"${row.join('","')}"`)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
el.downloadLink.addEventListener('click', (event) => {
|
|
|
|
|
|
|
|
event.preventDefault()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const file = URL.createObjectURL(
|
|
|
|
|
|
|
|
new Blob([csv.join('\n')], { type: 'text/csv;charset=utf-8' })
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
chrome.downloads.download({
|
|
|
|
|
|
|
|
url: file,
|
|
|
|
|
|
|
|
filename: `wappalyzer${
|
|
|
|
|
|
|
|
hostname ? `_${hostname.replace('.', '-')}` : ''
|
|
|
|
|
|
|
|
}.csv`,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
el.panels.classList.remove('panels--hidden')
|
|
|
|
el.panels.classList.remove('panels--hidden')
|
|
|
|
el.download.classList.remove('plus-download--hidden')
|
|
|
|
el.download.classList.remove('plus-download--hidden')
|
|
|
@ -869,14 +869,20 @@ const Popup = {
|
|
|
|
i18n()
|
|
|
|
i18n()
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
downloadCsv() {
|
|
|
|
downloadCsv(event) {
|
|
|
|
|
|
|
|
console.log('x')
|
|
|
|
|
|
|
|
|
|
|
|
event.preventDefault()
|
|
|
|
event.preventDefault()
|
|
|
|
|
|
|
|
|
|
|
|
chrome.downloads.download({
|
|
|
|
const { csv, filename } = getCsv()
|
|
|
|
url: URL.createObjectURL(
|
|
|
|
|
|
|
|
|
|
|
|
const file = URL.createObjectURL(
|
|
|
|
new Blob([csv.join('\n')], { type: 'text/csv;charset=utf-8' })
|
|
|
|
new Blob([csv.join('\n')], { type: 'text/csv;charset=utf-8' })
|
|
|
|
),
|
|
|
|
)
|
|
|
|
filename: csvFilename,
|
|
|
|
|
|
|
|
|
|
|
|
chrome.downloads.download({
|
|
|
|
|
|
|
|
url: file,
|
|
|
|
|
|
|
|
filename,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
return false
|
|
|
|