fix: Automatically convert MV3 content_security_policy to MV2 (#1168)

Co-authored-by: windmillcode0 <michaelodumosu57@gmail.com>
Co-authored-by: windmillcode0 <shieldmousetower734@gmail.com>
This commit is contained in:
Aaron
2024-11-27 10:14:32 -06:00
committed by GitHub
parent aab4244d84
commit 241c907c65
3 changed files with 74 additions and 23 deletions
@@ -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);
});
});
});
+35 -23
View File
@@ -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);
@@ -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 {
@@ -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) {
@@ -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,
@@ -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;
@@ -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
View File
@@ -3041,10 +3041,12 @@ packages:
glob@6.0.4:
resolution: {integrity: sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==}
deprecated: Glob versions prior to v9 are no longer supported
glob@8.1.0:
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
engines: {node: '>=12'}
deprecated: Glob versions prior to v9 are no longer supported
global-dirs@3.0.1:
resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==}
@@ -3174,6 +3176,7 @@ packages:
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -4283,6 +4286,7 @@ packages:
rimraf@2.4.5:
resolution: {integrity: sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==}
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
rollup-plugin-dts@6.1.1: