

Gmail just broke every Chrome extension. Here’s how we fixed ours - bradavogel
https://mixmax.com/blog/gmail-just-broke-every-chrome-extension

======
AgentME
I work at Streak, where we make a Chrome extension for Gmail. The Gmail team
notified some extension developers ahead of time, and then slowly rolled out
Content-Security-Policy-Report-Only headers, so we had some time to look into
this. The interactions between extensions and CSP aren't well documented so it
required a bit of testing.

The content_security_policy property in the manifest is only for the extension
background, pop-up, and iframe pages. It does not apply to content scripts or
to pages that the extension acts on.

Only one extension can modify a request's headers at a time, so relying on
modifying Gmail's CSP headers will cause the extension to break if the user
has another extension modifying CSP headers (a few extensions like
Tampermonkey modify all request CSP headers!). There is a better solution.
Extension content scripts are allowed to bypass the page CSP rules in general,
though there's a few cases you noticed that are currently bugged (cross-origin
script tags and frames). Though your extension script does not get the ability
to bypass CSP rules if it's injected into the page, because then to Chrome
it's indistinguishable from Gmail's scripts.

Instead of having your extension content script add a script tag to the page
with a remote URL, just do an AJAX request to load the script and then eval
the contents. This will cause the downloaded script to be run as an extension
content script instead of a page script, and the page's CSP rules in general
won't affect its execution. It also means that you don't have to share your
javascript context with Gmail or other badly-behaving extensions!

To work around iframes being blocked by the page's CSP rules: it turns out
that iframes loaded from chrome-extension:// URIs are never blocked by Chrome,
so whenever you want your extension to inject an iframe with a remote URL into
the page, instead inject an iframe with a URL to an html file inside your
extension (and then that iframe will be obeying the extension's
content_security_policy instead of Gmail's, and you can have that contain a
full-sized iframe to a remote URL).

Some of the above is discussed on this Chrome bug:
[https://code.google.com/p/chromium/issues/detail?id=391128](https://code.google.com/p/chromium/issues/detail?id=391128)

~~~
bradavogel
Thanks for the thoughtful writeup and great work on Streak. We're big fans.
You're also fortunate you were notified by the Gmail team!

On the content_security_policy property in the manifest file, thanks for
pointing that out. The documentation is a bit ambiguous: "In general, CSP
works as a black/whitelisting mechanism for resources loaded or executed by
your extensions." I'll can revise our post.

I'd rather not eval the script contents since we lose the ability to get stack
traces.

~~~
AgentME
>I'd rather not eval the script contents since we lose the ability to get
stack traces.

Chrome supports a special "//# sourceURL=..." comment that lets you name
eval'd code, and allows it to remember breakpoints in the code. (And it plays
nicely with source maps still!) However, there is another issue where Chrome
doesn't actually activate remembered breakpoints until after the eval() call
returns, so the trick is to wrap the code you're going to eval() with
"(function(){"..."})" and then call it after it's returned by eval(). (That
does require that the script doesn't rely on its top level variables
automatically being globals attached to window, since it will now be running
inside a function.) Here's an example:
[https://gist.github.com/AgentME/7369c93de844f8e785b0](https://gist.github.com/AgentME/7369c93de844f8e785b0)

~~~
bradavogel
Awesome, thanks!

------
bisho
Every? Only the ones that inject script tags pointing to external files!

The content_security_policy in the manifest is for the extension, it's not
added to all the pages where the extension is active, obviously.

Also mangling the CSP by intercepting the requests to gmail is scary at best.
Can't they just fetch the js from the extension and inject it rather than
injecting a js with url?

Or go back to use a js bundle in the extension, which is the way it should
work, because it's predictable. By fetching a script from somewhere you are
adding an extra dependency on gmail that is probably far less reliable that
gmail itself.

------
jannotti
"every Chrome extension" That's some serious hyperbole you've got there. You
should have it checked out.

------
Someone1234
Shame about the bugs, but broadly speaking I am happy to see more sites using
CSP. Wonderful feature, and the report-only mode is a great design.

I won't pretend to know if the best way to modify Gmail is to inject
additional script tags into the page, I would hope it isn't, but it wouldn't
surprise me if it was.

------
breakingcups
I wonder if the push to proxy images in emails was triggered by wanting to
enable CSP on Gmail.

