Use runtime.sendMessage instead of port.postMessage for Safari compatibility

main
Elbert Alias 5 years ago
parent eceaac4fd6
commit 0302eba2f4

@ -58,6 +58,7 @@ try {
}
})
// Validate regular expression
try {
// eslint-disable-next-line no-new
new RegExp(regex)
@ -65,6 +66,12 @@ try {
throw new Error(`${error.message} (${id})`)
}
//
if (/\.[+*]/.test(regex)) {
console.log(regex)
}
// Count capture groups
const groups = new RegExp(`${regex}|`).exec('').length - 1
if (groups > maxGroups) {

@ -20,6 +20,7 @@
"validate": "yarn run lint && jsonlint -qV ./schema.json ./src/apps.json && node ./bin/validate.js",
"convert": "cd ./src/drivers/webextension/images/icons ; cp *.svg converted ; cd converted ; convert-svg-to-png *.svg --width 32 --height 32 ; rm *.svg",
"prettify": "jsonlint -si --trim-trailing-commas --enforce-double-quotes ./src/apps.json",
"build": "yarn run link && yarn run validate && yarn run prettify && yarn run convert && node ./bin/build.js"
"build": "yarn run link && yarn run validate && yarn run prettify && yarn run convert && node ./bin/build.js",
"build:safari": "xcrun safari-web-extension-converter --swift --project-location build --bundle-identifier com.wappalyzer.webextension --force src/drivers/webextension"
}
}

@ -9,17 +9,6 @@ const Content = {
async init() {
await new Promise((resolve) => setTimeout(resolve, 1000))
// Enable messaging to and from driver.js
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)
@ -43,13 +32,15 @@ const Content = {
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]
)
)
chrome.i18n.detectLanguage
? chrome.i18n.detectLanguage(html, ({ languages }) =>
resolve(
languages
.filter(({ percentage }) => percentage >= 75)
.map(({ language: lang }) => lang)[0]
)
)
: resolve()
))
// Script tags
@ -72,22 +63,41 @@ const Content = {
{}
)
Content.port.postMessage({
func: 'onContentLoad',
args: [location.href, { html, scripts, meta }, language]
})
Content.driver('onContentLoad', [
location.href,
{ html, scripts, meta },
language
])
Content.port.postMessage({ func: 'getTechnologies' })
Content.onGetTechnologies(await Content.driver('getTechnologies'))
} catch (error) {
Content.port.postMessage({ func: 'error', args: [error, 'content.js'] })
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 {Object} technologies
* @param {Array} technologies
*/
onGetTechnologies(technologies) {
onGetTechnologies(technologies = []) {
console.log({ technologies })
// Inject a script tag into the page to access methods of the window object
const script = document.createElement('script')
@ -99,7 +109,8 @@ const Content = {
window.removeEventListener('message', onMessage)
Content.port.postMessage({
chrome.runtime.sendMessage({
source: 'content.js',
func: 'analyzeJs',
args: [location.href, data.wappalyzer.js]
})

@ -63,7 +63,7 @@ const Driver = {
chrome.tabs.onRemoved.addListener((id) => (Driver.cache.tabs[id] = null))
// Enable messaging between scripts
chrome.runtime.onConnect.addListener(Driver.onRuntimeConnect)
chrome.runtime.onMessage.addListener(Driver.onMessage)
const { version } = chrome.runtime.getManifest()
const previous = await getOption('version')
@ -153,29 +153,28 @@ const Driver = {
/**
* Enable scripts to call Driver functions through messaging
* @param {Object} port
* @param {Object} message
* @param {Object} sender
* @param {Function} callback
*/
onRuntimeConnect(port) {
Driver.log(`Connected to ${port.name}`)
onMessage({ source, func, args }, sender, callback) {
if (!func) {
return
}
port.onMessage.addListener(async ({ func, args }) => {
if (!func) {
return
}
Driver.log({ source, func, args })
Driver.log({ port: port.name, func, args })
if (!Driver[func]) {
Driver.error(new Error(`Method does not exist: Driver.${func}`))
if (!Driver[func]) {
Driver.error(new Error(`Method does not exist: Driver.${func}`))
return
}
return
}
Promise.resolve(Driver[func].call(Driver[func], ...(args || [])))
.then(callback)
.catch(Driver.error)
port.postMessage({
func,
args: await Driver[func].call(port.sender, ...(args || []))
})
})
return !!callback
},
/**
@ -362,6 +361,10 @@ const Driver = {
* @param {Object} technologies
*/
async setIcon(url, technologies) {
if (!chrome.pageAction.show) {
return
}
const dynamicIcon = await getOption('dynamicIcon', true)
let icon = 'default.svg'
@ -380,16 +383,19 @@ const Driver = {
await Promise.all(
tabs.map(async ({ id: tabId }) => {
await promisify(chrome.pageAction, 'setIcon', {
tabId,
path: chrome.extension.getURL(
`../images/icons/${
/\.svg$/i.test(icon)
? `converted/${icon.replace(/\.svg$/, '.png')}`
: icon
}`
)
})
await Promise.race([
promisify(chrome.pageAction, 'setIcon', {
tabId,
path: chrome.extension.getURL(
`../images/icons/${
/\.svg$/i.test(icon)
? `converted/${icon.replace(/\.svg$/, '.png')}`
: icon
}`
)
}),
new Promise((resolve) => setTimeout(resolve, 500))
])
chrome.pageAction.show(tabId)
})
@ -519,7 +525,7 @@ const Driver = {
]
if (
!/((local|dev(elopment)?|stag(e|ing)?|test(ing)?|demo(shop)?|admin|google|cache)\.|\/admin|\.local)/.test(
!/((local|dev(elopment)?|stag(e|ing)?|test(ing)?|demo(shop)?|admin|google|cache)\.|\/admin|\.local|127\.)/.test(
hostname
) &&
hits >= 3

@ -2,11 +2,17 @@
/* eslint-env browser */
/* globals chrome, Utils */
const { agent, open, i18n, getOption, setOption, promisify } = Utils
const {
agent,
open,
i18n,
getOption,
setOption,
promisify,
sendMessage
} = Utils
const Popup = {
port: chrome.runtime.connect({ name: 'popup.js' }),
/**
* Initialise popup
*/
@ -34,7 +40,7 @@ const Popup = {
agent === 'chrome' || (await getOption('termsAccepted', false))
if (termsAccepted) {
Popup.driver('getDetections')
Popup.onGetDetections(await Popup.driver('getDetections'))
} else {
document.querySelector('.terms').style.display = 'flex'
document.querySelector('.detections').style.display = 'none'
@ -47,7 +53,7 @@ const Popup = {
document.querySelector('.detections').style.display = 'block'
document.querySelector('.empty').style.display = 'block'
Popup.driver('getDetections')
chrome.runtime.sendMessage('getDetections', Popup.onGetDetections)
})
// Apply internationalization
@ -71,13 +77,8 @@ const Popup = {
.addEventListener('click', () => chrome.runtime.openOptionsPage())
},
/**
* Call a function on driver.js through messaging
* @param {function} func
* @param {...any} args
*/
driver(func, ...args) {
Popup.port.postMessage({ func, args })
driver(func, args) {
return sendMessage('popup.js', func, args)
},
/**
@ -85,7 +86,7 @@ const Popup = {
* @param {String} message
*/
log(message) {
Popup.driver('log', message, 'popup.js')
Popup.driver('log', message)
},
/**
@ -113,7 +114,7 @@ const Popup = {
* Callback for getDetection listener
* @param {Array} detections
*/
async onGetDetections(detections) {
async onGetDetections(detections = []) {
const pinnedCategory = await getOption('pinnedCategory')
if (detections.length) {
@ -216,15 +217,6 @@ const Popup = {
}
}
// Add listener for popup PostMessage API
Popup.port.onMessage.addListener(({ func, args }) => {
const onFunc = `on${func.charAt(0).toUpperCase() + func.slice(1)}`
if (Popup[onFunc]) {
Popup[onFunc](args)
}
})
if (/complete|interactive|loaded/.test(document.readyState)) {
Popup.init()
} else {

@ -75,5 +75,22 @@ const Utils = {
Array.from(document.querySelectorAll('[data-i18n]')).forEach(
(node) => (node.innerHTML = chrome.i18n.getMessage(node.dataset.i18n))
)
},
sendMessage(source, func, args) {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage(
{
source,
func,
args: args ? (Array.isArray(args) ? args : [args]) : []
},
(response) => {
chrome.runtime.lastError
? reject(new Error(chrome.runtime.lastError.message))
: resolve(response)
}
)
})
}
}