You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
3.3 KiB
128 lines
3.3 KiB
'use strict'
|
|
/* eslint-env browser */
|
|
/* globals chrome */
|
|
|
|
const Content = {
|
|
/**
|
|
* Initialize content detection.
|
|
*/
|
|
async init() {
|
|
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
|
|
Content.port = chrome.runtime.connect({ name: 'content.js' })
|
|
|
|
Content.port.onMessage.addListener(({ func, args }) => {
|
|
const onFunc = `on${func.charAt(0).toUpperCase() + func.slice(1)}`
|
|
|
|
if (Content[onFunc]) {
|
|
Content[onFunc](args)
|
|
}
|
|
})
|
|
|
|
try {
|
|
// HTML
|
|
let html = new XMLSerializer().serializeToString(document)
|
|
|
|
const chunks = []
|
|
const maxCols = 2000
|
|
const maxRows = 3000
|
|
const rows = html.length / maxCols
|
|
|
|
for (let i = 0; i < rows; i += 1) {
|
|
if (i < maxRows / 2 || i > rows - maxRows / 2) {
|
|
chunks.push(html.slice(i * maxCols, (i + 1) * maxCols))
|
|
}
|
|
}
|
|
|
|
html = chunks.join('\n')
|
|
|
|
const language =
|
|
document.documentElement.getAttribute('lang') ||
|
|
document.documentElement.getAttribute('xml:lang') ||
|
|
(await new Promise((resolve) =>
|
|
chrome.i18n.detectLanguage(html, ({ languages }) =>
|
|
resolve(
|
|
languages
|
|
.filter(({ percentage }) => percentage >= 75)
|
|
.map(({ language: lang }) => lang)[0]
|
|
)
|
|
)
|
|
))
|
|
|
|
// Script tags
|
|
const scripts = Array.from(document.scripts)
|
|
.filter(({ src }) => src)
|
|
.map(({ src }) => src)
|
|
.filter((script) => script.indexOf('data:text/javascript;') !== 0)
|
|
|
|
// Meta tags
|
|
const meta = Array.from(document.querySelectorAll('meta')).reduce(
|
|
(metas, meta) => {
|
|
const key = meta.getAttribute('name') || meta.getAttribute('property')
|
|
|
|
if (key) {
|
|
metas[key.toLowerCase()] = [meta.getAttribute('content')]
|
|
}
|
|
|
|
return metas
|
|
},
|
|
{}
|
|
)
|
|
|
|
Content.port.postMessage({
|
|
func: 'onContentLoad',
|
|
args: [location.href, { html, scripts, meta }, language]
|
|
})
|
|
|
|
Content.port.postMessage({ func: 'getTechnologies' })
|
|
} catch (error) {
|
|
Content.port.postMessage({ func: 'error', args: [error, 'content.js'] })
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Callback for fetching technologies.
|
|
* @param {Object} technologies
|
|
*/
|
|
onGetTechnologies(technologies) {
|
|
const script = document.createElement('script')
|
|
|
|
script.onload = () => {
|
|
const onMessage = ({ data }) => {
|
|
if (!data.wappalyzer || !data.wappalyzer.js) {
|
|
return
|
|
}
|
|
|
|
window.removeEventListener('message', onMessage)
|
|
|
|
Content.port.postMessage({
|
|
func: 'analyzeJs',
|
|
args: [location.href, data.wappalyzer.js]
|
|
})
|
|
|
|
script.remove()
|
|
}
|
|
|
|
window.addEventListener('message', onMessage)
|
|
|
|
window.postMessage({
|
|
wappalyzer: {
|
|
technologies: technologies
|
|
.filter(({ js }) => Object.keys(js).length)
|
|
.map(({ name, js }) => ({ name, chains: Object.keys(js) }))
|
|
}
|
|
})
|
|
}
|
|
|
|
script.setAttribute('src', chrome.extension.getURL('js/inject.js'))
|
|
|
|
document.body.appendChild(script)
|
|
}
|
|
}
|
|
|
|
if (/complete|interactive|loaded/.test(document.readyState)) {
|
|
Content.init()
|
|
} else {
|
|
document.addEventListener('DOMContentLoaded', Content.init)
|
|
}
|