Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improve the worker integrity warning #2091

Merged
merged 1 commit into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/browser/setupWorker/glossary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ export type ServiceWorkerIncomingResponse = Pick<
*/
export interface ServiceWorkerIncomingEventsMap {
MOCKING_ENABLED: boolean
INTEGRITY_CHECK_RESPONSE: string
INTEGRITY_CHECK_RESPONSE: {
packageVersion: string
checksum: string
}
KEEPALIVE_RESPONSE: never
REQUEST: ServiceWorkerIncomingRequest
RESPONSE: ServiceWorkerIncomingResponse
Expand Down
28 changes: 9 additions & 19 deletions src/browser/setupWorker/start/createStartHandler.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { until } from '@open-draft/until'
import { devUtils } from '~/core/utils/internal/devUtils'
import { getWorkerInstance } from './utils/getWorkerInstance'
import { enableMocking } from './utils/enableMocking'
import { SetupWorkerInternalContext, StartHandler } from '../glossary'
import { createRequestListener } from './createRequestListener'
import { requestIntegrityCheck } from '../../utils/requestIntegrityCheck'
import { checkWorkerIntegrity } from '../../utils/checkWorkerIntegrity'
import { createResponseListener } from './createResponseListener'
import { validateWorkerScope } from './utils/validateWorkerScope'

Expand Down Expand Up @@ -74,23 +73,14 @@ Please consider using a custom "serviceWorker.url" option to point to the actual
window.clearInterval(context.keepAliveInterval)
})

// Check if the active Service Worker is the latest published one
const integrityCheckResult = await until(() =>
requestIntegrityCheck(context, worker),
)

if (integrityCheckResult.error) {
devUtils.warn(`\
Detected outdated Service Worker: ${integrityCheckResult.error.message}

The mocking is still enabled, but it's highly recommended that you update your Service Worker by running:

$ npx msw init <PUBLIC_DIR>

This is necessary to ensure that the Service Worker is in sync with the library to guarantee its stability.
If this message still persists after updating, please report an issue: https://github.com/open-draft/msw/issues\
`)
}
// Check if the active Service Worker has been generated
// by the currently installed version of MSW.
await checkWorkerIntegrity(context).catch((error) => {
devUtils.error(
'Error while checking the worker script integrity. Please report this on GitHub (https://github.com/mswjs/msw/issues), including the original error below.',
)
console.error(error)
})

context.keepAliveInterval = window.setInterval(
() => context.workerChannel.send('KEEPALIVE_REQUEST'),
Expand Down
34 changes: 34 additions & 0 deletions src/browser/utils/checkWorkerIntegrity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { devUtils } from '~/core/utils/internal/devUtils'
import type { SetupWorkerInternalContext } from '../setupWorker/glossary'

/**
* Check whether the registered Service Worker has been
* generated by the installed version of the library.
* Prints a warning message if the worker scripts mismatch.
*/
export async function checkWorkerIntegrity(
context: SetupWorkerInternalContext,
): Promise<void> {
// Request the integrity checksum from the registered worker.
context.workerChannel.send('INTEGRITY_CHECK_REQUEST')

const { payload } = await context.events.once('INTEGRITY_CHECK_RESPONSE')

// Compare the response from the Service Worker and the
// global variable set during the build.

// The integrity is validated based on the worker script's checksum
// that's derived from its minified content during the build.
// The "SERVICE_WORKER_CHECKSUM" global variable is injected by the build.
if (payload.checksum !== SERVICE_WORKER_CHECKSUM) {
devUtils.warn(
`The currently registered Service Worker has been generated by a different version of MSW (${payload.packageVersion}) and may not be fully compatible with the installed version.

It's recommended you update your worker script by running this command:

\u2022 npx msw init <PUBLIC_DIR>

You can also automate this process and make the worker script update automatically upon the library installations. Read more: https://mswjs.io/docs/cli/init.`,
)
}
}
23 changes: 0 additions & 23 deletions src/browser/utils/requestIntegrityCheck.ts

This file was deleted.

8 changes: 6 additions & 2 deletions src/mockServiceWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
/* tslint:disable */

/**
* Mock Service Worker (<PACKAGE_VERSION>).
* Mock Service Worker.
* @see https://github.com/mswjs/msw
* - Please do NOT modify this file.
* - Please do NOT serve this file on production.
*/

const PACKAGE_VERSION = '<PACKAGE_VERSION>'
const INTEGRITY_CHECKSUM = '<INTEGRITY_CHECKSUM>'
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
const activeClientIds = new Set()
Expand Down Expand Up @@ -48,7 +49,10 @@ self.addEventListener('message', async function (event) {
case 'INTEGRITY_CHECK_REQUEST': {
sendToClient(client, {
type: 'INTEGRITY_CHECK_RESPONSE',
payload: INTEGRITY_CHECKSUM,
payload: {
packageVersion: PACKAGE_VERSION,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Send the MSW version used to generate the worker script in this message to have a better warning.

checksum: INTEGRITY_CHECKSUM,
},
})
break
}
Expand Down
9 changes: 8 additions & 1 deletion test/browser/msw-api/integrity-check.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as fs from 'fs'
import * as path from 'path'
import { test, expect } from '../playwright.extend'
import copyServiceWorker from '../../../config/copyServiceWorker'
import { version } from '../../../package.json'

const { SERVICE_WORKER_SOURCE_PATH } = require('../../../config/constants')

Expand Down Expand Up @@ -67,7 +68,13 @@ test('errors when activating the worker with an outdated integrity', async ({
// Produces a meaningful error in the browser's console.
expect(consoleSpy.get('warning')).toEqual(
expect.arrayContaining([
expect.stringContaining('[MSW] Detected outdated Service Worker'),
`[MSW] The currently registered Service Worker has been generated by a different version of MSW (${version}) and may not be fully compatible with the installed version.

It's recommended you update your worker script by running this command:

\u2022 npx msw init <PUBLIC_DIR>

You can also automate this process and make the worker script update automatically upon the library installations. Read more: https://mswjs.io/docs/cli/init.`,
]),
)
})
Expand Down