The Bottomless Pit of Disappointment: A Chrome Extension Tale
A bit of a “learn from our pain” / rant / sharing our experience-type blogpost, but here goes.
At Leaning Technologies, we make compilers and VMs that target JavaScript and WebAssembly. Our tooling is used both to extend the life of existing applications allowing them to run on modern browsers, but also to port and develop new web applications in languages that are traditionally a prerogative of native applications (such as C/C++ and Java).
As we typically work at the limits of what modern browsers and HTML5 specs allow, we have found (and fixed!) morebrowserbugsthan we’d like, helped improve the performance of more than oneJavaScript engine, and are an active part of the standardization process for WebAssembly.
Generally speaking, we work in a niche where it’s easy to develop PoCs and small toy projects, and very hard to make robust products. Having a majority enterprise clientele, but also because of our nature, we are the sort of people that always try doing things The Right Way™.
CheerpJ, in particular, is our solution to convert and run any Java client application, fully client-side, in the browser. And when we say “any”, we mean: reflection, proxies, dynamically generated classes, full runtime support (AWT, Swing, etc), threads, you-name-it. CheerpJ is the only tool in the market with these capabilities, and is mostly used by enterprise customers with complex porting and migration requirements.
As an offshoot of this technology, we have for several years offered a free-to-use Chrome extension (for non-commercial purposes), called CheerpJ Applet Runner.
This lets users seamlessly access fully deprecated Java Applets on modern versions of Chrome, without a local Java installation, or a plugin. This is achieved, in essence, by converting the Applet bytecode to HTML5 on the fly, and providing a full Java runtime environment in JavaScript and Wasm.
Originally developed to have our tech tested as much as possible in the wild, it has become very widely used by people, from all walks of life, who still need to use Java applets on a daily basis. We have helped over 40,000 students, senior card players, artists, law enforcement officers and even major US federal institutions to access content that is way past its selling date. And with a 4.4/5 rating and wide adoption, I think we have been quite successful at that.
Just to be clear, we don’t buy reviews.
Not the best way to begin your day
In March 2020, as the COVID-19 pandemic began to rage over the planet, I woke up one day to find what any extension developer dreads the most. Two emails, in rapid succession:
Your recently published update was rejected for policy violations;
Upon review, your product was found to violate our policies and it has been removed from the store.
The second email offered us a shimmer of hope: it was possible to reply and appeal to the decision, which we immediately did. We received an automated response that, due to the (at the time) new pandemic and general congestion of the Chrome Web Store, it might have taken a few days to receive an answer.
Almost 18 months later, we are still to receive an answer to our appeal. The extension is still up on the store somehow, with a Rejected update in the Dashboard. Because of this, we have decided not to update the extension, or try again with the same update, being worried that the extension might be taken down altogether.
What this has meant was leaving users with unresolved bugs, and leaving us without the extensive testing that only thousands of end-users can provide to our new releases. Not only that, but there have been several major releases to CheerpJ, the big-sister technology behind this extension, which we have not been able to propagate to the Applet Runner.
After such a long time, we can’t postpone updates any longer, and can’t continue stalling.
This post is about our plan to get out of this quagmire, about the inevitable costs of this situation (both for us and our users), and the massive amount of frustration, pointless limitations and ugly bugs that we have found along the way. Hopefully, this will be useful for other developers of Chrome extensions. At the very least, they might find some comfort from seeing other people having their fair share of pain.
Are we the bad guys?
Chrome Web Store policies change frequently, mostly getting stricter by the day, and for very good reasons.
Extensions are powerful, and can easily have a serious negative impact on user security and privacy. This can happen both directly (i.e. a plain malware/spyware extension), but also indirectly, by compromising the developer account or remote assets of an otherwise legit extension.
There is also the grey area of “extension acquisitions” by shady companies: we very regularly receive inquiries to purchase the CheerpJ Applet Runner extension, most of them not looking exactly kosher.
Anyway, as a form of defense in depth, the Chrome Web Store policies require that the least possible amount of permissions are requested. In this way, even a compromised extension can still do limited damage. This makes complete sense. Extensions developers are incentivized by a “warning” system: when installing an extension a worrying message is shown to the user if the extension requires heavy-handed permissions. Moreover, developers have to justify each and every requested permission when submitting an item to the store.
uBlock Origin: A very popular extension that shows quite a worrying message at install time
CheerpJ Applet Runner gets no warning at install time
For us, the idea of sticking to these guidelines not only made sense — it was a no-brainer. We care hugely about user privacy, and we certainly do not want our users to think that CheerpJ Applet Runner will “read and change all their data on the websites they visit”. To be fully honest, we don’t even want the responsibility that comes with that.
That said, our extension needs to be able to do some tricky stuff just to work as expected. In particular:
Many Java powered websites will try to detect if Java is supported before creating the relevant