Code for https://chrome.google.com/webstore/detail/ohcfioimjbmanibdlkhbcndkbdibpkpg
Last active
March 4, 2024 05:31
-
-
Save sirdarckcat/15cf8f924389e9535de16c2e6d952075 to your computer and use it in GitHub Desktop.
Isolated Scripts
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
// Copyright (c) 2017 The Chromium Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style license that can be | |
// found in the LICENSE file. | |
var secrets = {}; | |
// 1. If response header "Isolated-Script" is "true" and type is "script" | |
// 1.1. Cancel request, and inject response as content script | |
chrome.webRequest.onHeadersReceived.addListener( | |
function(info) { | |
var scriptUrl = new URL(info.url); | |
if ((info.responseHeaders||[]).find( | |
pair=>pair.name.match(/^Isolated-Script$/i) && pair.value=="true") | |
) { | |
fetch(scriptUrl.href, {redirect: "error", credentials: "include"}) | |
.then(response=> | |
response.status < 300 | |
&& response.headers.get('content-type').match(/^(text|application)\/javascript(;.*)?$/) | |
? response.text() | |
: 'console.error("bad script response")') | |
.then(code=>chrome.tabs.executeScript(info.tabId, { | |
code: wrapCode( | |
code, | |
secrets[scriptUrl.origin] = String(secrets[scriptUrl.origin] || Math.random())), | |
frameId: info.frameId | |
})); | |
chrome.tabs.executeScript(info.tabId, { | |
file: "secrethtml.js", | |
frameId: info.frameId | |
}); | |
return {redirectUrl: 'data:text/javascript,console.log("loading script as isolate");'}; | |
} | |
}, | |
// filters | |
{ | |
urls: ["*://*/*"], | |
types: ["script"] | |
}, | |
// extraInfoSpec | |
["blocking", "responseHeaders"]); | |
// 1.2. Replace fetch and XMLHttpRequest.send to add "Isolated-Script-Secret: SECRET" to every request made. | |
function wrapCode(code, secret) { | |
var wrapper = function(self, secret, code){ | |
console.log('running isolate script'); | |
self.fetch = new Proxy(self.fetch, { | |
apply: function(fetch, window, args) { | |
args[1] = args[1] || {}; | |
args[1].headers = args[1].headers || {}; | |
args[1].headers["Isolated-Script-Secret"] = secret; | |
return fetch.apply(window, args); | |
}}); | |
self.XMLHttpRequest.prototype.send = new Proxy(self.XMLHttpRequest.prototype.send, { | |
apply: function(send, xhr, args) { | |
xhr.addRequestHeader("Isolated-Script-Secret", secret); | |
return xhr.send.apply(xhr, args); | |
} | |
}); | |
code(); | |
}; | |
var code = "function(){" + code + "}"; | |
return "(" + wrapper + ")(self," + JSON.stringify(secret) + "," + code + ")"; | |
} | |
// 2. If request header "Isolated-Script-Secret" exists | |
// 2.1 Remove from every request, but remember it's value. | |
// 3. If request header "Cookie" contains cookie prefixed "__isolatedScript-" and request header "Isolated-Script-Secret" didn't contain secret. | |
// 3.1. Remove cookie from request. | |
chrome.webRequest.onBeforeSendHeaders.addListener( | |
function(info){ | |
var scriptUrl = new URL(info.url); | |
var requestHeaders = []; | |
var claimedSecret, cookieIndex, dirtyCookies, cleanCookies, cookies; | |
(info.requestHeaders||[]).forEach(function(header, index){ | |
if (header.name.match(/^Isolated-Script-Secret$/i)) { | |
claimedSecret = header.value; | |
} else | |
if (header.name.match(/^Cookie$/i)) { | |
cookieIndex = index; | |
dirtyCookies = header.value.split(';'); | |
cleanCookies = dirtyCookies.filter(function(cookie) { | |
return !cookie.match(/^\s*__isolatedScript-/); | |
}); | |
} else { | |
requestHeaders.push(header); | |
} | |
}); | |
if (dirtyCookies) { | |
if (claimedSecret && claimedSecret == secrets[scriptUrl.origin]) { | |
cookies = dirtyCookies.join(';'); | |
} else { | |
cookies = cleanCookies.join(';'); | |
} | |
requestHeaders.push({name: "Cookie", value: cookies}); | |
} | |
return {requestHeaders: requestHeaders}; | |
}, | |
// filters | |
{ | |
urls: ["*://*/*"] | |
}, | |
// extraInfoSpec | |
["blocking", "requestHeaders"]); |
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
{ | |
"name": "Isolate Scripts Demo", | |
"version": "0.1.1", | |
"description": "Demo for Isolate Scripts", | |
"permissions": [ | |
"webRequest", | |
"webRequestBlocking", | |
"https://isolate-scripts-demo.appspot.com/*" | |
], | |
"background": { | |
"scripts": ["background.js"] | |
}, | |
"manifest_version": 2 | |
} |
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
// Copyright (c) 2017 The Chromium Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style license that can be | |
// found in the LICENSE file. | |
var bootstrap = function(self) { | |
self.onmessage = function(m) { | |
document.open(); | |
document.write(m.data.html); | |
document.close(); | |
var eventPort = m.ports[0]; | |
for(var x in document.body) { | |
if (x.match(/^on/)) { | |
document.body[x] = function(event) { | |
var clone = {}; | |
for (var n in event) { | |
try { | |
var serialized = JSON.stringify(event[n]); | |
if (serialized == "{}" || serialized == "[]" || serialized == "null") { | |
continue; | |
} | |
clone[n] = JSON.parse(serialized); | |
} catch (e) {} | |
}; | |
eventPort.postMessage(clone); | |
}; | |
} | |
} | |
document.documentElement.style.cssText = "padding: 0; margin: 0; position: fixed; top: 0; left: 0; right: 0; bottom: 0; height: 100%: width: 100%;"; | |
document.body.style.cssText = m.data.style; | |
}; | |
} | |
Object.defineProperty(Element.prototype, 'innerHTML', { | |
set: function(html){ | |
if (html) { | |
var element = this; | |
var style = window.getComputedStyle(this, null).cssText; | |
var shadow = this.attachShadow({mode: 'closed'}); | |
var iframe = document.createElement('iframe'); | |
iframe.srcdoc = "<script>(" + bootstrap + ")(self)</script>"; | |
iframe.sandbox = "allow-forms allow-scripts"; | |
iframe.style.cssText = "height: 100%; width: 100%; padding: 0; margin: 0; border: 0;"; | |
var mc = new MessageChannel(); | |
mc.port1.onmessage = function(e) { | |
// Fake the event | |
var fakeEvent; | |
if (!fakeEvent && e.data.type.match(/^mouse|click/)) { | |
try { | |
fakeEvent = new MouseEvent(e.data.type, e.data); | |
} catch(e) {} | |
} | |
if (!fakeEvent) { | |
try { | |
fakeEvent = new UIEvent(e.data.type, e.data); | |
} catch(e) {} | |
} | |
if (!fakeEvent) { | |
try { | |
fakeEvent = new Event(e.data.type, e.data); | |
} catch(e) {} | |
} | |
if (!fakeEvent) { | |
try { | |
fakeEvent = new CustomEvent(e.data.type, e.data); | |
} catch(e) {} | |
} | |
if (fakeEvent) { | |
element.dispatchEvent(fakeEvent); | |
} | |
}; | |
iframe.onload = function() { | |
iframe.onload = null; | |
iframe.contentWindow.postMessage({ | |
html: html, | |
style: style | |
}, '*', [mc.port2]); | |
}; | |
shadow.appendChild(iframe); | |
} | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment