workbox icon indicating copy to clipboard operation
workbox copied to clipboard

Recipe for adding COEP/COOP headers

Open jeffposnick opened this issue 4 years ago • 4 comments
trafficstars

Low-priority, but it might be useful to have this documented for Workbox users. CC: @malchata

C.f. https://stackoverflow.com/questions/69468591/using-service-worker-to-enable-coop-coep-headers-security-concerns

This would look something like:

import {registerRoute} from "workbox-routing";
import {NetworkOnly} from "workbox-strategies";
import * as navigationPreload from "workbox-navigation-preload";

navigationPreload.enable();

const headersPlugin = {
  handlerWillRespond: async ({response}) => {
    const headers = new Headers(response.headers);
    headers.set("Cross-Origin-Embedder-Policy", "require-corp");
    headers.set("Cross-Origin-Opener-Policy", "same-origin");

    return new Response(response.body, {
      headers,
      status: response.status,
      statusText: response.statusText,
    });
  },
};

// Swap in NetworkOnly, StaleWhileRevalidate, etc. as needed.
const strategy = new NetworkOnly({
  plugins: [headersPlugin],
});

registerRoute(
  ({request}) => ["document", "iframe", "worker"].includes(request.destination),
  strategy
);

jeffposnick avatar Oct 19 '21 16:10 jeffposnick

Is it possible to set up the interception via the generateSW option ? I'm trying to use https://github.com/antfu/vite-plugin-pwa to generate the service worker which provides a workbox configuration option, but having an issue figuring out how to configure the plugin via the GenerateSWOptions object.

leopsidom avatar Feb 10 '22 03:02 leopsidom

I personally like using injectManifest mode for this sort of customization (here's an example with vite-plugin-pwa), but if you wanted to do something similar using generateSW, you can with the following Vite config:

const headersPlugin = {
  handlerWillRespond: async ({response}) => {
    const headers = new Headers(response.headers);
    headers.set("Cross-Origin-Embedder-Policy", "require-corp");
    headers.set("Cross-Origin-Opener-Policy", "same-origin");

    return new Response(response.body, {
      headers,
      status: response.status,
      statusText: response.statusText,
    });
  },
};

export default defineConfig({
  plugins: [
    VitePWA({
      workbox: {
        runtimeCaching: [
          {
            urlPattern: ({request}) =>
              ['document', 'iframe', 'worker'].includes(request.destination),
            handler: 'NetworkOnly',
            options: {
              plugins: [headersPlugin],
            },
          },
        ],
      },
    }),

    // Other config goes here.

jeffposnick avatar Feb 10 '22 15:02 jeffposnick

Nice, this seems to work. Thanks for the suggestion. But I'm having one issue with my web worker script, i.e the script that gets loaded via new Worker('./webworker.js'). From my network tab it appears that the request is served by service worker. However, the response headers do not seem to be modified. It seems the request is not going through the plugin either, as when I add a log in urlPattern like below:

urlPattern: ({request}) => {
  console.log(request)
  return ['document', 'iframe', 'worker'].includes(request.destination)
}

I don't see .../webworker.js in the log entry. Do you know how worker script is treated differently in service worker ?

leopsidom avatar Feb 11 '22 05:02 leopsidom

I think I figured it out. webworker.js was precached and serving it with a different header like Cross-Origin-Embedder-Policy did not trigger an update. After manually deleting the precache and reinstalling the service worker, it now worked..

leopsidom avatar Feb 12 '22 22:02 leopsidom