Replace cookie-based hacks with synchronous messaging (currently shimmed) to retrieve fallback and per-tab restriction policies.
This commit is contained in:
parent
c3dcf300a6
commit
fcd7c4aef0
|
@ -287,8 +287,12 @@ var RequestGuard = (() => {
|
||||||
if (policyType) {
|
if (policyType) {
|
||||||
let {url, originUrl, documentUrl} = request;
|
let {url, originUrl, documentUrl} = request;
|
||||||
let isFetch = "fetch" === policyType;
|
let isFetch = "fetch" === policyType;
|
||||||
|
|
||||||
if ((isFetch || "frame" === policyType) &&
|
if ((isFetch || "frame" === policyType) &&
|
||||||
(((isFetch && !originUrl || url === originUrl) && originUrl === documentUrl
|
(((isFetch && (!originUrl ||
|
||||||
|
browser.runtime.onSyncMessage &&
|
||||||
|
url.includes(browser.runtime.onSyncMessage.ENDPOINT_PREFIX)
|
||||||
|
) || url === originUrl) && originUrl === documentUrl
|
||||||
// some extensions make them both undefined,
|
// some extensions make them both undefined,
|
||||||
// see https://github.com/eight04/image-picka/issues/150
|
// see https://github.com/eight04/image-picka/issues/150
|
||||||
) ||
|
) ||
|
||||||
|
|
|
@ -141,24 +141,26 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchChildPolicy({url, contextUrl}, sender) {
|
fetchChildPolicy({url, contextUrl}, sender) {
|
||||||
if (!url) url = sender.url;
|
|
||||||
let {tab} = sender;
|
let {tab} = sender;
|
||||||
let tabUrl = tab.url;
|
let topUrl = tab.url || TabCache.get(tab.id);
|
||||||
if (!contextUrl) contextUrl = tabUrl;
|
|
||||||
|
|
||||||
let policy = !Sites.isInternal(url) && ns.isEnforced(tab.id)
|
let policy = !Sites.isInternal(url) && ns.isEnforced(tab.id)
|
||||||
? ns.policy : null;
|
? ns.policy : null;
|
||||||
|
|
||||||
let permissions = Permissions.ALL;
|
let permissions, unrestricted, cascaded;
|
||||||
if (policy) {
|
if (policy) {
|
||||||
let perms = policy.get(url, contextUrl).perms;
|
let perms = policy.get(url, contextUrl).perms;
|
||||||
if (tabUrl && ns.sync.cascadeRestrictions) {
|
cascaded = ns.sync.cascadeRestrictions;
|
||||||
perms = policy.cascadeRestrictions(perms, tabUrl);
|
if (topUrl && cascaded) {
|
||||||
|
perms = policy.cascadeRestrictions(perms, topUrl);
|
||||||
}
|
}
|
||||||
permissions = perms.dry();
|
permissions = perms.dry();
|
||||||
} // otherwise either internal URL or unrestricted
|
} else {
|
||||||
|
// otherwise either internal URL or unrestricted
|
||||||
return {permissions};
|
permissions = new Permissions(Permissions.ALL);
|
||||||
|
unrestricted = true;
|
||||||
|
cascaded = false;
|
||||||
|
}
|
||||||
|
return {permissions, unrestricted, cascaded};
|
||||||
},
|
},
|
||||||
|
|
||||||
async openStandalonePopup() {
|
async openStandalonePopup() {
|
||||||
|
|
|
@ -58,10 +58,6 @@ var notifyPage = async () => {
|
||||||
debug("Page %s shown, %s", document.URL, document.readyState);
|
debug("Page %s shown, %s", document.URL, document.readyState);
|
||||||
if (document.readyState === "complete") {
|
if (document.readyState === "complete") {
|
||||||
try {
|
try {
|
||||||
if (!("canScript" in ns)) {
|
|
||||||
ns.fetchPolicy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await Messages.send("pageshow", {seen: seen.list, canScript: ns.canScript});
|
await Messages.send("pageshow", {seen: seen.list, canScript: ns.canScript});
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -74,8 +70,6 @@ var notifyPage = async () => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyPage();
|
|
||||||
|
|
||||||
window.addEventListener("pageshow", notifyPage);
|
window.addEventListener("pageshow", notifyPage);
|
||||||
|
|
||||||
ns.on("capabilities", () => {
|
ns.on("capabilities", () => {
|
||||||
|
@ -105,3 +99,6 @@ ns.on("capabilities", () => {
|
||||||
|
|
||||||
notifyPage();
|
notifyPage();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ns.fetchPolicy();
|
||||||
|
notifyPage();
|
||||||
|
|
|
@ -33,78 +33,27 @@
|
||||||
backlog.add(eventName);
|
backlog.add(eventName);
|
||||||
},
|
},
|
||||||
|
|
||||||
async fetchPolicy() {
|
fetchPolicy() {
|
||||||
let policy = await Messages.send("fetchChildPolicy", {url: document.URL});
|
let url = document.URL;
|
||||||
if (!policy) {
|
let policy = browser.runtime.sendSyncMessage(
|
||||||
debug(`No answer to fetchChildPolicy message. This should not be happening.`);
|
{id: "fetchPolicy", url, contextUrl: document.URL});
|
||||||
return false;
|
if (!policy) {
|
||||||
}
|
debug(`No answer to fetchPolicy message. This should not be happening.`);
|
||||||
this.setup(policy.permissions, policy.MARKER, true);
|
return false;
|
||||||
return true;
|
}
|
||||||
|
this.setup(policy);
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
setup(permissions, MARKER, fetched = false) {
|
setup(policy) {
|
||||||
this.config.permissions = permissions;
|
this.policy = policy;
|
||||||
|
|
||||||
// ugly hack: since now we use registerContentScript instead of the
|
if (!policy.permissions || policy.unrestricted) {
|
||||||
// filterRequest dynamic script injection hack, we use a session cookie
|
|
||||||
// to store per-tab information, erasing it as soon as we see it
|
|
||||||
// (before any content can access it)
|
|
||||||
|
|
||||||
let checkUnrestricted = challenge => sha256(`${MARKER}:${challenge}`);
|
|
||||||
|
|
||||||
if ((this.config.MARKER = MARKER) && permissions) {
|
|
||||||
let cookieRx = new RegExp(`(?:^|;\\s*)(${MARKER}(?:_\\d+){2})=([^;]*)`);
|
|
||||||
let match = document.cookie.match(cookieRx);
|
|
||||||
if (match) {
|
|
||||||
let [cookie, cookieName, cookieValue] = match;
|
|
||||||
// delete cookie NOW
|
|
||||||
document.cookie = `${cookieName}=;expires=${new Date(Date.now() - 31536000000).toGMTString()}`;
|
|
||||||
try {
|
|
||||||
this.config.tabInfo = JSON.parse(decodeURIComponent(cookieValue));
|
|
||||||
} catch (e) {
|
|
||||||
error(e);
|
|
||||||
}
|
|
||||||
} else if (UA.isMozilla && window !== window.top) {
|
|
||||||
// The cookie hack won't work for non-HTTP subframes (issue #48),
|
|
||||||
// or the cookie might have been deleted in a race condition,
|
|
||||||
// so here we try to check the parent
|
|
||||||
let checkParent = null;
|
|
||||||
try {
|
|
||||||
checkParent = parent.wrappedJSObject.checkNoScriptUnrestricted;
|
|
||||||
} catch (e) {
|
|
||||||
// may throw a SecurityException for cross-origin wrappedJSObject access
|
|
||||||
}
|
|
||||||
if (typeof checkParent === "function") {
|
|
||||||
try {
|
|
||||||
let challenge = uuid();
|
|
||||||
let unrestricted = checkParent(challenge) === checkUnrestricted(challenge);
|
|
||||||
this.config.tabInfo = {unrestricted, inherited: true};
|
|
||||||
} catch (e) {
|
|
||||||
debug("Exception thrown while checking parent unrestricted tab marker. Something fishy going on...")
|
|
||||||
error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.config.permissions || this.config.tabInfo.unrestricted) {
|
|
||||||
exportFunction(checkUnrestricted, window, {defineAs: "checkNoScriptUnrestricted"});
|
|
||||||
debug("%s is loading unrestricted by user's choice (%o).", document.URL, this.config);
|
|
||||||
this.allows = () => true;
|
this.allows = () => true;
|
||||||
this.capabilities = Object.assign(
|
this.capabilities = Object.assign(
|
||||||
new Set(["script"]), { has() { return true; } });
|
new Set(["script"]), { has() { return true; } });
|
||||||
} else {
|
} else {
|
||||||
if (!fetched) {
|
let perms = policy.permissions;
|
||||||
let hostname = window.location.hostname;
|
|
||||||
if (hostname && hostname.startsWith("[")) {
|
|
||||||
// WebExt match patterns don't seem to support IPV6 (Firefox 63)...
|
|
||||||
debug("Ignoring child policy setup parameters for IPV6 address %s, forcing IPC...", hostname);
|
|
||||||
this.fetchPolicy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let perms = this.config.permissions;
|
|
||||||
this.capabilities = new Set(perms.capabilities);
|
this.capabilities = new Set(perms.capabilities);
|
||||||
new DocumentCSP(document).apply(this.capabilities, this.embeddingDocument);
|
new DocumentCSP(document).apply(this.capabilities, this.embeddingDocument);
|
||||||
}
|
}
|
||||||
|
@ -112,7 +61,8 @@
|
||||||
this.canScript = this.allows("script");
|
this.canScript = this.allows("script");
|
||||||
this.fire("capabilities");
|
this.fire("capabilities");
|
||||||
},
|
},
|
||||||
config: { permissions: null, tabInfo: {}, MARKER: "" },
|
|
||||||
|
policy: null,
|
||||||
|
|
||||||
allows(cap) {
|
allows(cap) {
|
||||||
return this.capabilities && this.capabilities.has(cap);
|
return this.capabilities && this.capabilities.has(cap);
|
||||||
|
|
Loading…
Reference in New Issue