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.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

142 lines
3.7 KiB

'use strict'
/* eslint-env browser */
/* globals chrome */
const Content = {
/**
* Initialise content script
*/
async init() {
await new Promise((resolve) => setTimeout(resolve, 1000))
try {
// HTML
let html = new XMLSerializer().serializeToString(document)
// Discard the middle portion of HTML to avoid performance degradation on large pages
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')
// Determine language based on the HTML lang attribute or content
const language =
document.documentElement.getAttribute('lang') ||
document.documentElement.getAttribute('xml:lang') ||
(await new Promise((resolve) =>
chrome.i18n.detectLanguage
? chrome.i18n.detectLanguage(html, ({ languages }) =>
resolve(
languages
.filter(({ percentage }) => percentage >= 75)
.map(({ language: lang }) => lang)[0]
)
)
: resolve()
))
// 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.driver('onContentLoad', [
location.href,
{ html, scripts, meta },
language
])
Content.onGetTechnologies(await Content.driver('getTechnologies'))
} catch (error) {
Content.driver('error', error)
}
},
driver(func, args, callback) {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage(
{
source: 'content.js',
func,
args: args ? (Array.isArray(args) ? args : [args]) : []
},
(response) => {
chrome.runtime.lastError
? reject(new Error(chrome.runtime.lastError.message))
: resolve(response)
}
)
})
},
/**
* Callback for getTechnologies
* @param {Array} technologies
*/
onGetTechnologies(technologies = []) {
// Inject a script tag into the page to access methods of the window object
const script = document.createElement('script')
script.onload = () => {
const onMessage = ({ data }) => {
if (!data.wappalyzer || !data.wappalyzer.js) {
return
}
window.removeEventListener('message', onMessage)
chrome.runtime.sendMessage({
source: 'content.js',
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)
}