w3c / webextensions

Charter and administrivia for the WebExtensions Community Group (WECG)
Other
591 stars 54 forks source link

Use cases that are not well served by service workers #72

Open dotproto opened 3 years ago

dotproto commented 3 years ago

Near the end of the 2021-08-19 meeting we briefly discussed (but didn't capture) the idea of collecting background page use cases and design patterns that are not well served by service workers. My hope is that by collecting these use cases in a well known location, community members and browser vendors we will be able to more concretely discuss the challenges posed by this new background context and explore potential solutions.

Please use this issue to link to use use cases that are impossible to accomplish with or not well supported by service workers. If you'd like to report a new use case, please create a new issue and reference this one.

Use cases

Specific ways that background pages are used that cannot be accomplished with a service worker.

Other discussions

scholtzm commented 2 years ago

It's January 20th, 2022 and according to Manifest v2 Support Timeline[1], we can no longer submit public Mv2 extensions. Yet, there are many use cases which are not supported by the sheer nature of ephemeral service workers.

For example (among other broken APIs), our extension uses WebSockets to receive live updates from our servers. How can we implement this functionality with current Mv3 standard? The fact that extensions are being made less powerful than a standard web page is beyond my comprehension.

[1] https://developer.chrome.com/docs/extensions/mv3/mv2-sunset/

capaj commented 2 years ago

@microsoft @mozilla I would very much like to hear what your official stand point is towards manifest V3 vs manifest V2. Which one do you prefer? Which one you will support going forward? Because V3 seems like something @google has cooked up to kill ad blockers and raise their ad revenue.

@MicrosoftEdge are you going to kill manifest V2 as well? Are you going to drive more people towards browsers like @brave or @kiwibrowser on android?

markon1 commented 2 years ago

it's impossible to integrate google analytics with MV3, since it won't allow this in manifest.json: "content_security_policy": { "extension_pages": "script-src 'self' https://www.google-analytics.com https://www.googletagmanager.com https://js.refiner.io; object-src 'self'" }

kzar commented 2 years ago

I'm looking at porting StayFocusd from Manifest v2 to v3...

Could it work like this?

  1. webNavigation.onCommitted listener in background serviceWorker notes the time a distracting website is opened in storage (if there is not already a time noted for that website).
  2. chrome.alarms listener fires every one minute and checks if any distracting websites are due to be blocked.
  3. When a website is due to be blocked, a dynamic declarativeNetRequest rule is added to block that website.
  4. When the chrome.alarms listener notices a day has passed, all declarativeNetRequest rules and logged times for distracting websites are cleared.
tophf commented 2 years ago

Edit: self-hidden due to being off-topic.

@kzar, it probably could, at the cost of reducing the precision to 1 minute (not a problem here I guess) and [quite possibly] restarting the background script hundreds of times a day, thus wasting battery and other resources [astronomically] more than the equivalent MV2 extension with a persistent background script, so the author's extension is yet another fine example of a bad fit for a service worker as it is defined now. We have to admit that persistence is not bad per se for some cases where the lack thereof is much worse for overall performance and resource consumption, and start specifying how the service worker's lifetime should be dynamically prolonged based on heuristics, measurements, histograms, statistics to achieve a realistically better outcome. There's an evidence that Chromium team has at least one developer who seems to understand this.

kzar commented 2 years ago

...restarting the background script hundreds of times a day, thus wasting battery and other resources...

Yea, good point about it being inefficient to fire the alarm every minute. I think the chrome.alarms API also lets you pick a specific time for the alarm to fire. So I guess it could work something like this:

  1. webNavigation.onCommitted listener creates an alarm when a distracting website is navigated to (if there isn't an alarm or declarativeNetRequest rule already created for the site).
  2. When the alarm fires, a dynamic declarativeNetRequest rule is added to block that website.
  3. A periodic alarm also fires every X hours or once a day and clears any other alarms or dynamic declarativeNetRequest rules.

(FWIW I'm not defending the switch from background page to ServiceWorker, just trying to help.)

alanhkarp commented 2 years ago

I have a password manager that holds the user's master password in the memory of the background page in Manifest 2. Of course, that approach won't work with Manifest 3.

My solution was to create a tab that runs what was the background script. Every time the service worker starts, it looks for this tab and creates it if it doesn't exist. Any state I put in the script that runs in the tab persists as long as the tab is open.

I was concerned about the effect on the user experience, but so far it appears to be minimal. My biggest problem is figuring out what to show in the tab that makes its presence seem natural.

The other issue is security. I understood access to the background page, but I'm less certain about the code running in the tab. Is there a risk to the user's master password because it's held in the memory of a script running on a web page? A search didn't turn up anything, which both comforts and worries me.

tophf commented 2 years ago

@alanhkarp, chrome.storage.session should help you, it's yet undocumented, but the API is the same as chrome.storage.local with an overall limit of 1MB for the entire storage.

alanhkarp commented 2 years ago

Thanks for the pointer, @tophf, but I don't need session storage. I have a running process. Once I set the variable, I can get the value as long as the tab is open.

tophf commented 2 years ago

@alanhkarp, I was commenting on the first sentence in your comment:

I have a password manager that holds the user's master password in the memory of the background page in Manifest 2. Of course, that approach won't work with Manifest 3.

chrome.storage.session is an API created specifically for this use case.

alanhkarp commented 2 years ago

Oops, @topf, my bad. My code will be far simpler if I can use session storage for the master password.

I had the wrong mental model of session storage. I thought it was connected to the session when the popup or service worker were open and would be lost after they closed.

I just ran some experiments, and that is not the case. I found an article that says "session" refers to the time a web page is open. For an extension, that appears to be while the browser is open and the extension is enabled.

I have all kinds of questions. Is session storage for extensions documented anywhere?

One problem with session storage is that it is not recommended for sensitive data, such as passwords. Is that true for extensions? I'm not using any third-party scripts, just the ones included in my extension.

cuylerstuwe commented 2 years ago

chrome.storage.session is not the same as window.sessionStorage.

The former was poorly-named and unfortunately that poor name seems to have stuck now. It would have been better to call it e.g., chrome.storage.ephemeral, chrome.storage.volatile, etc.

On Tue, Mar 8, 2022 at 4:55 PM Alan Karp @.***> wrote:

Oops, @Topf https://github.com/Topf, my bad. My code will be far simpler if I can use session storage for the master password.

I had the wrong mental model of session storage. I thought it was connected to the session when the popup or service worker were open and would be lost after they closed.

I just ran some experiments, and that is not the case. I found an article that says "session" refers to the time a web page is open. For an extension, that appears to be while the browser is open and the extension is enabled.

I have all kinds of questions. Is session storage for extensions documented anywhere?

One problem with session storage is that it is not recommended for sensitive data, such as passwords. Is that true for extensions? I'm not using any third-party scripts, just the ones included in my extension.

— Reply to this email directly, view it on GitHub https://github.com/w3c/webextensions/issues/72#issuecomment-1062441850, or unsubscribe https://github.com/notifications/unsubscribe-auth/AE4MEMD2YGSFF4YAKQVXLXDU67ZIJANCNFSM5DJTXWDQ . You are receiving this because you were mentioned.Message ID: @.***>

alanhkarp commented 2 years ago

Thanks for the clarification, @cuylerstuwe. No matter what you call it, you still have to understand its lifetime. I haven't found anything about that for the session storage of an extension. For what it's worth, I ran my experiments with chrome.storage.session, but I should probably also see how window.sessionStorage works.

tophf commented 2 years ago

chrome.storage.session is an API created specifically for storing sensitive data in-memory without writing it anywhere, which is why it's almost just as safe as a variable inside a persistent background script, assuming the web page didn't find an exploit to break through the world isolation barrier. There's some info in https://crbug.com/1185226. When chrome.storage.setAccessLevel is implemented we will be able to hide the values from being directly accessible in content scripts so that a malicious web page would have to also break through the inter-process barrier, which is incomparably harder if even possible.

scholtzm commented 2 years ago

One catch, storage.session API is asynchronous which makes it impractical as a storage for data that was previously stored in memory in persistent background page. You might find yourself a) rewriting large parts of your code or b) hacking around it by greedily fetching all of the data[1] before you reach critical part of your code. This also means you won't be able to use importScripts in your SW.

[1] As suggested officially here: https://docs.google.com/document/d/1N34xDVIeIM2A6egjoKUQqjqcuQ2s2W8_v_H8ciFWBu4/edit

tophf commented 2 years ago

you won't be able to use importScripts in your SW.

You can use importScripts asynchronously but you need to call it additionally in the install event handler, example. This is necessary for the web SW because all dependencies must be ensured to be locally cached. It makes no sense for extensions, which are already local, which is yet another reason why SW was a poor choice made by Chromium people who aren't JS developers.

scholtzm commented 2 years ago

example

Doesn't the example load (and execute) some-complex-script.js twice? Once in oninstall and once in the async handler.

tophf commented 2 years ago

Yes, it does and the reason is explained in my comment above. Note that the install event is triggered just once when the extension is installed/updated.

alanhkarp commented 2 years ago

chrome.storage.session will work for my extension, but there are some things I only learned by experiment. For example, it appears that the popup and service worker have separate session storage, but the popup and tabs the extension creates have the same storage. I also tried window.sessionStorage, which works fine in the popup, but window is undefined in the service worker.

Is this stuff written up anywhere?

tophf commented 2 years ago

@alanhkarp, chrome.storage.session is the same throughout the entire extension, sessionStorage is an unrelated thing.

zombie commented 2 years ago

Please keep this issue as a summary/list of use cases. If you need to discuss something in more detail, a separate issue is probably a better place.

alanhkarp commented 2 years ago

You are right, @tophf. I had a bug in my experiment.

I agree, @zombie.

alanhkarp commented 2 years ago

Don't worry, @zombie, this post explains problems when using Manifest 3 for my extension :)

I have been playing around with both session storage and an additional tab to hold the user's master password. They both work fine -- most of the time. The tests I did are a pain, because I have to wait until the service worker goes idle. Of course, I can't use the browser while I'm waiting because page loads keep the service worker active :(

The first case uses session storage with the bulk of the code running in the service worker. Say that the user loads a page with a password field, but doesn't do anything with it for long enough for the service worker to go idle. Clicking on the password field tells the content script to send a message to the service worker. The message wakes up the service worker, but the response doesn't come back until the service worker goes idle again, after which I get a "message port closed" error. I get the same behavior if I load an unrelated page to wake up the service worker.

The second case uses a tab created by the extension to hold the user's master password and to run the bulk of the code. That works fine unless the user closes the tab while the service worker is idle. Now the password manager appears to be hung until the service worker wakes up. In my current implementation, the service worker doesn't receive any messages, so a page load is the only way to wake it up.

hunterharris1 commented 2 years ago

@alanhkarp FWIW, to make your testing easier, this page exists where you can stop/start service workers - chrome://serviceworker-internals/

alanhkarp commented 2 years ago

Thanks, @hunterharris1. I was running out of things to do while waiting for the service worker to go inactive.

alanhkarp commented 2 years ago

After some changes, the service worker reliably wakes up when it should. I don't know why it wasn't happening before, but my extension now works with service workers. Thanks for all your help, both related to the actual topic of this thread and not.

discobeta commented 2 years ago

FYI one can kill the service worker manually (for testing) by using chrome://serviceworker-internals/

scholtzm commented 2 years ago

Are there any plans to introduce clipboard access in service worker?

nodeticswww commented 2 years ago

One of the most important features of a persistent background page is to enable pre-fetching and pre-processing of lots of data that is then quickly accessible by the WebExtension UI (in-memory meta data lookup tables). So basically data caching is really important for performance.

One example of that is an RSS reader (Feedbro).

In Feedbro, the background page is also responsible for playing audio clips, parsing HTML/XML pages (requires an efficient XML/HTML parser provided by DOMParser), showing desktop notifications, calling external services (like IFTTT) and holding various data structures in memory. Background page also needs timed events and concurrent scanning of several different URLs (feed sources).

With MV3 it seems impossible to implement Feedbro in any reasonable way. Another victim will be our PageProbe extension which relies on much of the same MV2 features.

wolfspelz commented 2 years ago

One of the most important features of a persistent background page is to enable pre-fetching and pre-processing of lots of data that is then quickly accessible by the WebExtension UI (in-memory meta data lookup tables). So basically data caching is really important for performance.

I totally agree. This change intends to lower resource usage in order to support weak (mobile) devices better. Ironically it turns out to make things worse. Caching background pages will have to reload their data using even more resources or apps abandon cashing as optimization strategy entirely, also harming performance. Kindof defeats the original purpose.

aeharding commented 2 years ago

Anyone know the latest status on MV3? Is Google still ignoring developers?

leoshusar commented 2 years ago

My use case is keeping the state of opened tabs, I am using events like tabs.(onCreated|onUpdated|onRemoved). I had to wrap all my event handlers in a preloader that retrieves data from storage, executes the handler and then saves the data again, like this:

let initialized = false;

const initialize = async () => {
  if (!initialized) {
    const data = await chrome.storage.local.get(['tabInfo', 'controlsHidden']);
    Object.assign(tabInfo, data.tabInfo);
    Object.assign(controlsHidden, data.controlsHidden);

    initialized = true;
  }
}

const initializer = initialize();

const handleEvent = async (func, ...args) => {
  await initializer;

  try {
    await func(...args);
  } finally {
    await chrome.storage.local.set({ tabInfo, controlsHidden });
  }
}

chrome.tabs.onCreated.addListener((...args) => handleEvent(handleTabCreated, ...args));
chrome.tabs.onUpdated.addListener((...args) => handleEvent(handleTabUpdated, ...args));
chrome.tabs.onRemoved.addListener((...args) => handleEvent(handleTabRemoved, ...args));

If the reason for short lived workers was so it can save some CPU cycles, my workaround is the exact opposite, because I don't think calling storage.get on almost every event and storage.set on every event has the same performance as simply keeping the data in variables.

bobthebuilder1997 commented 2 years ago

Service workers do not provide access to geolocation api. This is frustrating especially when using them in background scripts.

leo60228 commented 2 years ago

Anyone know the latest status on MV3? Is Google still ignoring developers?

@aeharding Limited Event Pages (#134) and Offscreen Documents (#170) are two proposals to help with the limitations of service workers. The former has implementations in Safari and Firefox. The latter is backed by Chrome but to my knowledge not yet implemented in any browser. The 2022-03-03 meeting notes have some relevant discussion too.

iamnottheway commented 2 years ago

Is there any update on persistent service workers? Or is there any API that lets you listen to when service workers stop?

aeharding commented 2 years ago

@leo60228 Offscreen documents don't support chrome.tabCapture api, so it doesn't work for me. I feel like mv3 completely ignores chrome.tabCapture.

tdriley commented 1 year ago

setTimeout and setInterval (though frowned on) have many unavoidable use cases and cannot be relied upon in an extension Service Worker because they're cleared when it suspends. The chrome.alarms API doesn't really offer an alternative given this restriction documented on the create method at https://developer.chrome.com/docs/extensions/reference/alarms/#method-create:

Chrome limits alarms to at most once every 1 minute but may delay them an arbitrary amount more. That is, setting delayInMinutes or periodInMinutes to less than 1 will not be honored and will cause a warning. when can be set to less than 1 minute after "now" without warning but won't actually cause the alarm to fire for at least 1 minute. To help you debug your app or extension, when you've loaded it unpacked, there's no limit to how often the alarm can fire.

bershanskiy commented 1 year ago

setTimeout and setInterval (though frowned on) have many unavoidable use cases and cannot be relied upon in an extension Service Worker because they're cleared when it suspends.

In my experience, extensions can combine setTimeout/setinterval with alarms to achieve almost any desired outcome. Specifically, use setTimeout/setinterval for short intervals less than 5 minutes (arbitrary lifetime limit at some point enforced by Chromium) and set regular alarms for events more than a minute apart. Some use cases for short setTimeout/setinterval do not even require persisting beyond service worker lifetime: in-memory cache with regular timed clenups, time limits for lengthy operations initiated by service worker itself, etc. Could you please describe your specific use case and perhaps I can describe how to do it with setTimeout/setinterval and alarms?

bershanskiy commented 1 year ago

Another use case not served by service workers is language change detection: language and languages live under navigator so are accessible from service workers, but oddly enough languagechange event is delivered to window. So extension backgrounds can detect the current language but can not react to changes (without regular pulling, of course).

tophf commented 1 year ago

extensions can combine setTimeout/setinterval with alarms to achieve almost any desired outcome

@bershanskiy, this won't work in Chrome where 1) the SW lives for just 30 seconds since the moment it was started, 2) its lifetime is not prolonged by new chrome events, which is a nasty regression compared to MV2 event pages, 3) chrome.alarms is throttled to 1 wake-up per minute. The only way it can work is if we use a nativeMessaging host to keep the SW alive or constantly re-open ports from other tabs, which is not guaranteed to be open and requires broad host permissions.

carlosjeurissen commented 1 year ago

Another use case not served by service workers is language change detection: language and languages live under navigator so are accessible from service workers, but oddly enough languagechange event is delivered to window. So extension backgrounds can detect the current language but can not react to changes (without regular pulling, of course).

In serviceWorkers you can listen for languagechange using:

self.addEventListener('languagechange', console.log);

or simply:

addEventListener('languagechange', console.log);

This has been tested in Mozilla Firefox, Google Chrome and Opera with success.

DavidJCobb commented 1 year ago

Service workers will lead to inconsiderate and wasteful bandwidth usage. Consider, for example, an extension that allows a user to manage or search through personal content or collections stored on a website (e.g. "favorites," "followers," "lists," etc.) in ways that a site does not normally offer -- perhaps a site with relatively minimal APIs, as opposed to the Internet's major corporate-funded platforms; in essence, a site that you have to scrape in order to extend.

The polite way to implement something like this would be to cache data in-memory whenever possible (possibly clearing that cache after enough time spent idle or off-site) to minimize how many redundant requests have to go over the network during a single browsing session. However, you can't cache anything using service workers. The 1MB storage in chrome.storage.session is tiny; it'd be pathetically small even if we could store space-efficient binary data e.g. DataView, which, of course, we can't. The other storage areas are inappropriate for caching during a single browsing session, and may have privacy implications (e.g. for incognito browsing) as well. (There would also be logistical difficulties in taking what's supposed to be a session-specific cache and placing it in persistent storage. At minimum, you'd have to go to the trouble of wiping your jury-rigged cache onStartup and rejecting/deferring all queries until that's complete. With how patchy WebExtensions APIs have been in my experience, I have zero confidence that trying this wouldn't lead to some huge unexpected obstacle.)

That leaves the impolite way: repeatedly bombard the website with requests for the same information you just asked for three minutes ago. Cache nothing; precompute nothing; optimize nothing; write rampantly wasteful code, because it's the only thing you're allowed to write.

The performance cost for the network requests can be larger than one might expect. I've been privately developing and testing some WebExtensions and working on getting them release-ready, and some of the sites I've been making add-ons for have anti-botting/anti-DDoS measures. Slamming them with tons of rapid-fire redundant requests is a great way to get rate-limited and receive a slew of 503s. If you need to scrape, say, a few dozen pages to gather up and preload metadata about a user's saved content, you might have to throttle those requests to ensure reliability. That's fine when it's information that you can query just once or twice, store in a background page, and then reuse throughout the rest of a browsing session (perhaps manually updating the in-memory copy without extra network requests if the user makes changes through the website). With service workers, however, you can't usefully cache anything, so that throttling ends up adding a substantial delay to a WebExtension's reactivity, because now the user has to wait on it every time the service worker wakes up.

radiolondra commented 1 year ago

It seems to me (tested) that calling the function below when any service worker starts, keeps the service worker up forever (that is, it doesn't go to sleep anymore). Question: Is this (another) Chrome bug or I found a way to keep a service worker alive forever?

-------------------------------------------->>> Code Description The function (StayAlive), inside the service worker, connects to a named port and tries to send a message through it to a nonexistent listener (so it will generate errors) when the service worker starts.

While doing this, SW is active and running (ok, it has something to do, that is, it has to send a message through a port, but this is my doubt about a possible Chrome bug, because the connect() is started by the service worker itself, not by some external tab/app/extension/whatever... ok, lets go on with the code description).

Because noone is listening, it generates a (catched and logged) error (in "onDisconnect" port event) and terminates.

But after 25 secs it does the same iter from start, keeping SW active forever.

Note: To perform reliable tests remember to not open any DevTools page. Use chrome://serviceworker-internals instead and find the log (Scope) of your test extension ID.

This is the code:

// In ServiceWorker.js
// -------------------
// Forcing service worker to stay alive by sending a "ping" to a port where noone is listening
// Essentially it prevents SW to fall asleep after the first 30 secs of work.

const INTERNAL_STAYALIVE_PORT = "Whatever_Port_Name_You_Want"
var alivePort = null;
...
// Call the function at SW start
StayAlive();
...

async function StayAlive() {
    var lastCall = Date.now();
    var wakeup = setInterval( () => {

        const now = Date.now();
        const age = now - lastCall;

        console.log(`(DEBUG StayAlive) ----------------------- time elapsed: ${age}`)
        if (alivePort == null) {
            alivePort = chrome.runtime.connect({name:INTERNAL_STAYALIVE_PORT})

            alivePort.onDisconnect.addListener( (p) => {
                if (chrome.runtime.lastError){
                    console.log(`(DEBUG StayAlive) Disconnected due to an error: ${chrome.runtime.lastError.message}`);
                } else {
                    console.log(`(DEBUG StayAlive): port disconnected`);
                }

                alivePort = null;
            });
        }

        if (alivePort) {

            alivePort.postMessage({content: "ping"});

            if (chrome.runtime.lastError) {                              
                console.log(`(DEBUG StayAlive): postMessage error: ${chrome.runtime.lastError.message}`)                
            } else {                               
                console.log(`(DEBUG StayAlive): "ping" sent through ${alivePort.name} port`)
            }

        }         
        //lastCall = Date.now();

    }, 25000);
}
cacosandon commented 1 year ago

If you came here looking for recording video/audio solution for MV3, you can use this example: https://github.com/wireworks-app/chrome-screen-recording

Pauan commented 11 months ago

I have created an extension which helps the user to manage tabs more easily.

It displays the user's tabs in a vertical list, it allows for organizing tabs with labels, it allows for searching through tabs, it allows for bulk operations on many tabs, etc.

It's designed for users who have a lot of tabs (hundreds, or potentially even thousands of tabs).

Because it needs to process a lot of tabs, and it needs to process those tabs quickly, it keeps the tab data alive in RAM with a persistent background page.

When a new tab event happens (because a tab was closed, or opened, or moved, etc.) it can very quickly process the event, because all of the tab data is kept in RAM.

This is a very natural and efficient design, and it mimics what the browser itself does (the browser has its own C++ representation of the tabs which is always kept available in RAM).

However, this is incompatible with service workers, because service workers can never be persistent.

Re-processing potentially thousands of tabs on every tab event is unacceptable for performance, it will slow down the browser and lead to a bad user experience.

Pauan commented 11 months ago

I have created a Chrome extension which automatically bets on the saltybet.com website (automatic betting bots are allowed by the SaltyBet rules).

In order to make the bets, it needs to look at past historical data. There is a LOT of historical data (258 MB of data).

This data is loaded and processed inside of a persistent background page. This processing takes about 39 seconds.

This is acceptable because the data only needs to be loaded one time, and then it can be reused over and over again for each match.

However, this is incompatible with service workers, because service workers cannot be persistent.

Re-loading the data over and over again is completely 100% unacceptable for performance.

Any use case that requires loading or processing large amounts of data is incompatible with service workers.

For example, if somebody wanted to create a folding@home extension for Chrome, it would not work because it needs to store and process large amounts of data.

Pauan commented 11 months ago

Cryptocurrency wallets are incompatible with service workers.

Cryptocurrency requires a lot of expensive computations (to generate keys, download the blockchain, etc.). This computation can potentially take several seconds, or even minutes.

Because the computation is so expensive, cryptocurrency extensions must cache the computation so that it only needs to be done one time.

However, because service workers cannot be persistent, that means it cannot cache the computation.

Here is an example:

https://chrome.google.com/webstore/detail/leo-wallet/nebnhfamliijlghikdgcigoebonmoibm

Because of the lack of persistent background pages, that extension opens a new tab and then does all of its computation inside of that tab.

So the user must keep that tab open at all times in order to use the extension.

This is obviously a completely unacceptable user experience.

Persistent background pages do not have that problem, because it can simply cache the computation inside of the (invisible) background page.

With persistent background pages, the extension could use a browser action popup for its UI.

But because service workers are not persistent, the extension cannot use a browser action popup, it must use a browser tab, which is an inferior user experience.

Any extension that requires in-memory caching of expensive computations is incompatible with service workers.

As time goes on, more extensions will start to abuse tabs as a substitute for persistent background pages, requiring the user to keep the tab open at all times in order for the extension to function.

alanhkarp commented 11 months ago

Can you use session storage? That's what I'm using for a very small amount of data.

I'm doing it with my fingers crossed because I haven't found a definitive statement that what's in session storage never appears on disk.


Alan Karp

On Fri, Oct 13, 2023 at 8:01 PM Pauan @.***> wrote:

Cryptocurrency wallets are incompatible with service workers.

Cryptocurrency requires a lot of expensive computations (to generate keys, download the blockchain, etc.). This computation can potentially take several seconds, or even minutes.

Because the computation is so expensive, cryptocurrency extensions must cache the computation so that it only needs to be done one time.

However, because service workers cannot be persistent, that means it cannot cache the computation.

Here is an example:

https://chrome.google.com/webstore/detail/leo-wallet/nebnhfamliijlghikdgcigoebonmoibm

Because of the lack of persistent background pages, that extension opens a new tab and then does all of its computation inside of that tab.

So the user must keep that tab open at all times in order to use the extension.

This is obviously a completely unacceptable user experience.

Persistent background pages do not have that problem, because it can simply cache the computation inside of the (invisible) background page.

With persistent background pages, the extension could use a browser action popup for its UI.

But because service workers are not persistent, the extension cannot use a browser action popup, it must use a browser tab, which is an inferior user experience.

Any extension that requires caching of expensive computations is incompatible with service workers.

— Reply to this email directly, view it on GitHub https://github.com/w3c/webextensions/issues/72#issuecomment-1762516009, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACFAT44KNPBDQZ7OIQ435HLX7H57HANCNFSM5DJTXWDQ . You are receiving this because you were mentioned.Message ID: @.***>

Pauan commented 11 months ago

Can you use session storage? That's what I'm using for a very small amount of data.

No, cryptocurrency wallets take security VERY seriously, it is unacceptable to have even the tiniest chance of private secrets leaked. Very large amounts of money are involved.

Anything private must be kept exclusively in memory, which means the extension must use in-memory caching with persistent background pages (or abuse tabs as a substitute for persistent background pages).

Even if sessionStorage was guaranteed to be in-memory only, it can only store a small amount of data, so it cannot support every use case.

Also, sometimes the cryptocurrency calculations take longer than 5 minutes, which means Chrome will kill the service worker, which obviously breaks everything. Caching cannot solve that problem.

So any extension that needs to run a very expensive computation (which takes longer than 5 minutes) is incompatible with service workers.

tophf commented 11 months ago

Note that session storage leaks into the content script context in Chrome, which can be hacked by a web page via a side channel attack as they share the same physical process.