Created
May 28, 2021 11:27
-
-
Save ddarwisheh/35576074a1450b018303d568c5f7b1a7 to your computer and use it in GitHub Desktop.
chrome extension and context
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//_________________script js______________ | |
async function test(){ | |
return new Promise((res,rej)=>{ | |
setTimeout(function(){ | |
res('test async function') | |
},3000) | |
}) | |
} | |
//_________________content js______________ | |
runInPageContext({ | |
func: async function diaa () { | |
let testData = await test() | |
return new Promise((resolve, reject) => { | |
resolve(testData) | |
}) | |
}, | |
call: 'diaa', | |
args: [] | |
}) | |
.then(data => { | |
console.log( data ) | |
}) | |
.catch(err => { | |
console.log({ err }) | |
}) | |
//_________________context js______________ | |
function uuidv4 () { | |
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { | |
var r = (Math.random() * 16) | 0, | |
v = c == 'x' ? r : (r & 0x3) | 0x8 | |
return v.toString(16) | |
}) | |
} | |
/** | |
* Runs a function in the page context by serializing it to a string and injecting it to the page | |
* @param {(function|Object)} func - a function to serialize and run in the page context, or an arguments object | |
* @param {function} func.func - a function to serialize and run in the page context | |
* @param {Array} [func.args] - arguments array to be passed to `func` | |
* @param {Document} [func.doc] - alternative `document` to inject the serialized function | |
* @param {number} [func.timeout] - optional timeout (milliseconds) | |
* @param {...any} [args] - arguments array to be passed to `func` | |
* @returns {Promise} a promise that will be resolved with the return value of the serialized function | |
*/ | |
function injectElemnt (element) { | |
try { | |
;(document.head || document.body || document.documentElement).appendChild( | |
element | |
) | |
} catch (err) { | |
console.log(err) | |
} | |
} | |
async function runInPageContext (func, ...args) { | |
const params = Object(func) | |
const { doc = document, timeout, call } = params | |
if (typeof func !== 'function') { | |
func = params.func | |
args = params.args | |
} | |
// test that we are running with the allow-scripts permission | |
try { | |
window.sessionStorage | |
} catch (ignore) { | |
return null | |
} | |
let id1 = uuidv4() | |
let id2 = uuidv4() | |
// returned value container | |
const resultMessageId = parseInt( | |
'' + Math.floor(Math.random() * 100 + 1) + new Date().getTime() | |
) | |
let scriptElm2 = doc.createElement('script') | |
scriptElm2.id = id1 | |
scriptElm2.setAttribute('type', 'application/javascript') | |
const code2 = `${func}` | |
scriptElm2.textContent = code2 | |
injectElemnt(scriptElm2) | |
// console.log(scriptElm2) | |
// prepare script container | |
let scriptElm = doc.createElement('script') | |
scriptElm.setAttribute('type', 'application/javascript') | |
// const code = ` | |
// ( | |
// async function () { | |
// const response = { | |
// id: ${resultMessageId} | |
// }; | |
// try { | |
// response.result = JSON.stringify(await (${func})(...${JSON.stringify( | |
// args || [] | |
// )})); // run script | |
// } catch(err) { | |
// response.error = JSON.stringify(err); | |
// console.log(err) | |
// } | |
// window.postMessage(response, '*'); | |
// } | |
// )(); | |
// ` | |
const code = ` | |
( | |
async function () { | |
const response = { | |
id: ${resultMessageId} | |
}; | |
try { | |
response.result = JSON.stringify(await window['${call}'](...${JSON.stringify( | |
args || [] | |
)})); // run script | |
} catch(err) { | |
response.error = JSON.stringify(err); | |
console.log(err) | |
} | |
window.postMessage(response, '*'); | |
try { | |
if(document.getElementById('${id1}')){ | |
document.getElementById('${id1}').outerHTML = '' | |
window['${call}'] = undefined | |
} | |
} catch(err) { | |
console.log(err) | |
} | |
} | |
)(); | |
` | |
// inject the script | |
scriptElm.id = id2 | |
scriptElm.textContent = code | |
// run the script | |
// doc.documentElement.appendChild(scriptElm) | |
// console.log(scriptElm) | |
injectElemnt(scriptElm) | |
// clean up script element | |
scriptElm.remove() | |
// create a "flat" promise | |
let resolve, reject | |
const promise = new Promise((res, rej) => { | |
resolve = res | |
reject = rej | |
}) | |
// reject on timeout | |
if (timeout !== undefined) { | |
const timerId = setTimeout(() => { | |
onResult({ | |
data: { | |
id: resultMessageId, | |
error: 'Script timeout' | |
} | |
}) | |
}, timeout) | |
// clear the timeout handler | |
promise.finally(() => (timerId !== null ? clearTimeout(timerId) : null)) | |
} | |
// resolve on result | |
function onResult (event) { | |
const data = Object(event.data) | |
if (data.id === resultMessageId) { | |
window.removeEventListener('message', onResult) | |
if (data.error !== undefined) { | |
return reject(JSON.parse(data.error)) | |
} | |
return resolve( | |
data.result !== undefined ? JSON.parse(data.result) : undefined | |
) | |
} | |
} | |
window.addEventListener('message', onResult) | |
return promise | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment