Skip to content

Commit

Permalink
fix: Automatically convert MV3 content_security_policy to MV2 (#1168)
Browse files Browse the repository at this point in the history
Co-authored-by: windmillcode0 <[email protected]>
Co-authored-by: windmillcode0 <[email protected]>
  • Loading branch information
3 people authored Nov 27, 2024
1 parent aab4244 commit 241c907
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 23 deletions.
35 changes: 35 additions & 0 deletions packages/wxt/src/core/utils/__tests__/manifest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1581,6 +1581,41 @@ describe('Manifest Utils', () => {
permissions: ['tabs', 'scripting'],
});
});

it('should convert MV3 CSP object to MV2 CSP string with localhost for MV2', async () => {
const entrypoints: Entrypoint[] = [];
const buildOutput = fakeBuildOutput();
const inputCsp =
"script-src 'self' 'wasm-unsafe-eval'; object-src 'self';";
const expectedCsp =
"script-src 'self' 'wasm-unsafe-eval' http://localhost:3000; object-src 'self';";

// Setup WXT for Firefox and serve command
setFakeWxt({
config: {
browser: 'firefox',
command: 'serve',
manifestVersion: 2,
manifest: {
content_security_policy: {
extension_pages: inputCsp,
},
},
},
server: fakeWxtDevServer({
port: 3000,
hostname: 'localhost',
origin: 'http://localhost:3000',
}),
});

const { manifest: actual } = await generateManifest(
entrypoints,
buildOutput,
);

expect(actual.content_security_policy).toEqual(expectedCsp);
});
});
});

Expand Down
58 changes: 35 additions & 23 deletions packages/wxt/src/core/utils/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,12 @@ export async function generateManifest(
if (wxt.config.manifestVersion === 2) {
convertWebAccessibleResourcesToMv2(manifest);
convertActionToMv2(manifest);
convertCspToMv2(manifest);
moveHostPermissionsToPermissions(manifest);
}

if (wxt.config.manifestVersion === 3) {
validateMv3WebAccessbileResources(manifest);
validateMv3WebAccessibleResources(manifest);
}

stripKeys(manifest);
Expand All @@ -143,7 +144,7 @@ export async function generateManifest(
}

/**
* Removes suffixes from the version, like X.Y.Z-alpha1 (which brosers don't allow), so it's a
* Removes suffixes from the version, like X.Y.Z-alpha1 (which browsers don't allow), so it's a
* simple version number, like X or X.Y or X.Y.Z, which browsers allow.
*/
function simplifyVersion(versionName: string): string {
Expand Down Expand Up @@ -467,34 +468,28 @@ function addDevModeCsp(manifest: Manifest.WebExtensionManifest): void {
}

const extensionPagesCsp = new ContentSecurityPolicy(
manifest.manifest_version === 3
? // @ts-expect-error: extension_pages is not typed
(manifest.content_security_policy?.extension_pages ??
"script-src 'self' 'wasm-unsafe-eval'; object-src 'self';") // default extension_pages CSP for MV3
: (manifest.content_security_policy ??
"script-src 'self'; object-src 'self';"), // default CSP for MV2
// @ts-expect-error: extension_pages exists, we convert MV2 CSPs to this earlier in the process
manifest.content_security_policy?.extension_pages ??
(manifest.manifest_version === 3
? DEFAULT_MV3_EXTENSION_PAGES_CSP
: DEFAULT_MV2_CSP),
);
const sandboxCsp = new ContentSecurityPolicy(
// @ts-expect-error: sandbox is not typed
manifest.content_security_policy?.sandbox ??
"sandbox allow-scripts allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';", // default sandbox CSP for MV3
manifest.content_security_policy?.sandbox ?? DEFAULT_MV3_SANDBOX_CSP,
);

if (wxt.server) {
if (wxt.config.command === 'serve') {
extensionPagesCsp.add('script-src', allowedCsp);
sandboxCsp.add('script-src', allowedCsp);
}

if (manifest.manifest_version === 3) {
manifest.content_security_policy ??= {};
// @ts-expect-error: extension_pages is not typed
manifest.content_security_policy.extension_pages =
extensionPagesCsp.toString();
// @ts-expect-error: sandbox is not typed
manifest.content_security_policy.sandbox = sandboxCsp.toString();
} else {
manifest.content_security_policy = extensionPagesCsp.toString();
}
manifest.content_security_policy ??= {};
// @ts-expect-error: extension_pages is not typed
manifest.content_security_policy.extension_pages =
extensionPagesCsp.toString();
// @ts-expect-error: sandbox is not typed
manifest.content_security_policy.sandbox = sandboxCsp.toString();
}

function addDevModePermissions(manifest: Manifest.WebExtensionManifest) {
Expand Down Expand Up @@ -613,7 +608,7 @@ export function stripPathFromMatchPattern(pattern: string) {
/**
* Converts all MV3 web accessible resources to their MV2 forms. MV3 web accessible resources are
* generated in this file, and may be defined by the user in their manifest. In both cases, when
* targetting MV2, automatically convert their definitions down to the basic MV2 array.
* targeting MV2, automatically convert their definitions down to the basic MV2 array.
*/
export function convertWebAccessibleResourcesToMv2(
manifest: Manifest.WebExtensionManifest,
Expand Down Expand Up @@ -652,10 +647,21 @@ function convertActionToMv2(manifest: Manifest.WebExtensionManifest): void {
manifest.browser_action = manifest.action;
}

function convertCspToMv2(manifest: Manifest.WebExtensionManifest): void {
if (
typeof manifest.content_security_policy === 'string' ||
manifest.content_security_policy?.extension_pages == null
)
return;

manifest.content_security_policy =
manifest.content_security_policy.extension_pages;
}

/**
* Make sure all resources are in MV3 format. If not, add a wanring
*/
export function validateMv3WebAccessbileResources(
export function validateMv3WebAccessibleResources(
manifest: Manifest.WebExtensionManifest,
): void {
if (manifest.web_accessible_resources == null) return;
Expand Down Expand Up @@ -718,3 +724,9 @@ const mv3OnlyKeys = [
'side_panel',
];
const firefoxMv3OnlyKeys = ['host_permissions'];

const DEFAULT_MV3_EXTENSION_PAGES_CSP =
"script-src 'self' 'wasm-unsafe-eval'; object-src 'self';";
const DEFAULT_MV3_SANDBOX_CSP =
"sandbox allow-scripts allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';";
const DEFAULT_MV2_CSP = "script-src 'self'; object-src 'self';";
4 changes: 4 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 241c907

Please sign in to comment.