Skip to content

Instantly share code, notes, and snippets.

@Gozala
Forked from ZER0/gist:5209412
Last active December 16, 2015 06:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Gozala/5391531 to your computer and use it in GitHub Desktop.
Save Gozala/5391531 to your computer and use it in GitHub Desktop.
Direct page to add-on communication
// Page mode should be able to communicate with page scripts
// without having to set up content script based proxy.
let { PageMod } = require("sdk/page-mod");
let mod = PageMod({
includes: ["*.good.com"],
contentScriptFile: "./content-script.js",
onAttach: function(worker) {
worker.addEventListener("message", function(event) {
// If `event.origin` is a document that is being tracked by page-mod,
// then reply:
if (event.origin === "good.com") // page script
event.source.postMessage(event.data + " addon!", "good.com");
// If `event.origin` is a `worker.origin` (maybe we can think of
// something better) then event is from content script attached to
// a page:
else if (event.origin === worker.origin)
event.source.postMessage("content script, hello!", worker.origin);
});
}
})

Consider following example where:

A - addon

B - evil.com

  • C - good.com

Related material

Notes

  • Instead of extending window.postMessage we could dispatch "add-on" event on the document that would provide an addon event.source that page could use to communicate. This way communication with add-on could not be initiated by client side, which has pros and cons. Problem is that page could miss event.
// Content scripts could listen for events coming either from
// page scripts or add-on host, by setting event listener on
// a window.
window.addEventListener("message", function onMessage(event) {
if (event.origin === "add-on:A") {
// Message from addon:A
} else if (event.origin === document.URL) {
// Message from page script
} else if (event.origin === self.origin) {
// Message from content-script itself.
} else {
// Unknown message, possibly from malicius evil.com
}
});
// 1. Content script can send messages to itself.
//
// Note that event handlers set by page scripts won't be invoked, since
// `self.origin !== document.URL`, only target able to receive this message
// will be a content script itself.
window.postMessage("hello", self.origin);
// 2. Content script can send messages to an add-on host.
//
// Content script also could post messages to the add-on host, but again
// page scripts won't be invoked, since `"add-on:A" !== documentURL`. Also
// Also above `onMessage` handler wan't be invoked either since
// `"add-on:host" !== self.origin`.
window.postMessage("hello add-on", "add-on:A");
// 3. Content script can send messages to pages scripts
//
// This will invoke handler registered by a page script
// since because host is `document.URL`. Note that add-on
// host and content scripts won't recieve this message
// since they have diff targetOrigin.
window.postMessage("hello page", document.URL);
// Assuming a page-mod is attached, evil.com may attempt to hijack a add-on to
// good.com communication channel, to receive message from add-on:
window.addEventListener("message", function(event) {
// Messages form the add-on won't be received here, since they page-mod
// is attached to "good.com"
// Even if page-mod doesn't verify `event.origin`, and uses "*" as
// `targetOrigin` argument for `postMessage`, then `evil.com` will
// be able to receive a message, still it won't be able to pretend
// being anything but `evil.com` as `event.origin` will reveal it.
});
// Following won't work because of: SOP - Same Origin Policy
// iframe contains "good.com"
iframe.contentWindow.addEventListener("message", function(event) {
// ...
});
// Important: a page (good.com or evil.com or whatever) can't initiate message
// pipe with content-script
// evil.com
// Evil outer frame could attempt pretending to be an add-on, but `event.origin`
// will reveal it to be an `evil.com`.
// It's important for `good.com` to verify the sender and destination.
iframe.contentWindow.postMessage("I'm a add-on", "good.com");
window.addEventListener("message", function onMessage(event) {
// Message events from add-ons will have origin that
// is different from ones that documents could have.
if (event.origin === "add-on:A") {
// Only reply to `event.source` if `event.origin` is an `add-on:A`, in
// which case `good.com` knows is guaranteed to be communicating with
// an add-on.
event.source.postMessage(event.data + " addon!", event.origin);
}
});
// According to the w3c spec following message won't be even dispatched, since
// `origin !== document.URL`. Although maybe we can interfere ansd use this trick
// to enable communication with add-on's directry.
//
// Note that `handler` from `window.addEventListener("message", handler)` won't
// be invoked, since `"add-on:host" !== document.URL`, only add-on side could
// recieve this messages.
window.postMessage("page ready", "add-on:host");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment