diff --git a/package-lock.json b/package-lock.json
index e1bac56a..f906e6b9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,11 +5,10 @@
"requires": true,
"packages": {
"": {
- "name": "squoosh",
"version": "2.0.0",
"license": "apache-2.0",
"dependencies": {
- "cheerio": "^1.0.0-rc.10",
+ "strict-csp": "^1.0.2",
"wasm-feature-detect": "^1.2.11"
},
"devDependencies": {
@@ -288,6 +287,14 @@
"node": ">=6"
}
},
+ "node_modules/@types/cheerio": {
+ "version": "0.22.30",
+ "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.30.tgz",
+ "integrity": "sha512-t7ZVArWZlq3dFa9Yt33qFBQIK4CQd1Q3UJp0V+UhP6vgLWLM6Qug7vZuRSGXg45zXeB1Fm5X2vmBkEX58LV2Tw==",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
@@ -331,8 +338,7 @@
"node_modules/@types/node": {
"version": "16.11.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.1.tgz",
- "integrity": "sha512-PYGcJHL9mwl1Ek3PLiYgyEKtwTMmkMw4vbiyz/ps3pfdRYLVv+SN7qHVAImrjdAXxgluDEw6Ph4lyv+m9UpRmA==",
- "dev": true
+ "integrity": "sha512-PYGcJHL9mwl1Ek3PLiYgyEKtwTMmkMw4vbiyz/ps3pfdRYLVv+SN7qHVAImrjdAXxgluDEw6Ph4lyv+m9UpRmA=="
},
"node_modules/@types/parse-json": {
"version": "4.0.0",
@@ -8185,6 +8191,15 @@
"integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
"dev": true
},
+ "node_modules/strict-csp": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/strict-csp/-/strict-csp-1.0.2.tgz",
+ "integrity": "sha512-YLnlJIGZQYRPRo39d/wNmF1CVkaikwCsIcLBWvVBWYAxQGFjigolOE2oPeqPMFt19NPM+Vts/z5nT15nRcKNUg==",
+ "dependencies": {
+ "@types/cheerio": "^0.22.23",
+ "cheerio": "^1.0.0-rc.5"
+ }
+ },
"node_modules/string-argv": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
@@ -9105,6 +9120,14 @@
}
}
},
+ "@types/cheerio": {
+ "version": "0.22.30",
+ "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.30.tgz",
+ "integrity": "sha512-t7ZVArWZlq3dFa9Yt33qFBQIK4CQd1Q3UJp0V+UhP6vgLWLM6Qug7vZuRSGXg45zXeB1Fm5X2vmBkEX58LV2Tw==",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@types/color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
@@ -9148,8 +9171,7 @@
"@types/node": {
"version": "16.11.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.1.tgz",
- "integrity": "sha512-PYGcJHL9mwl1Ek3PLiYgyEKtwTMmkMw4vbiyz/ps3pfdRYLVv+SN7qHVAImrjdAXxgluDEw6Ph4lyv+m9UpRmA==",
- "dev": true
+ "integrity": "sha512-PYGcJHL9mwl1Ek3PLiYgyEKtwTMmkMw4vbiyz/ps3pfdRYLVv+SN7qHVAImrjdAXxgluDEw6Ph4lyv+m9UpRmA=="
},
"@types/parse-json": {
"version": "4.0.0",
@@ -15656,6 +15678,15 @@
"integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
"dev": true
},
+ "strict-csp": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/strict-csp/-/strict-csp-1.0.2.tgz",
+ "integrity": "sha512-YLnlJIGZQYRPRo39d/wNmF1CVkaikwCsIcLBWvVBWYAxQGFjigolOE2oPeqPMFt19NPM+Vts/z5nT15nRcKNUg==",
+ "requires": {
+ "@types/cheerio": "^0.22.23",
+ "cheerio": "^1.0.0-rc.5"
+ }
+ },
"string-argv": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
diff --git a/package.json b/package.json
index e02c8157..b7a1e425 100644
--- a/package.json
+++ b/package.json
@@ -54,7 +54,7 @@
"*.rs": "rustfmt"
},
"dependencies": {
- "cheerio": "^1.0.0-rc.10",
+ "strict-csp": "^1.0.2",
"wasm-feature-detect": "^1.2.11"
}
}
diff --git a/src/static-build/lib-csp.ts b/src/static-build/lib-csp.ts
deleted file mode 100644
index 685c476d..00000000
--- a/src/static-build/lib-csp.ts
+++ /dev/null
@@ -1,192 +0,0 @@
-/**
- * @license
- * Copyright 2021 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import * as crypto from 'crypto';
-import * as cheerio from 'cheerio';
-
-/** Module for enabling a hash-based strict Content Security Policy. */
-export class StrictCsp {
- private static readonly HASH_FUNCTION = 'sha256';
- private static readonly INLINE_SCRIPT_SELECTOR = 'script:not([src])';
- private static readonly SOURCED_SCRIPT_SELECTOR = 'script[src]';
- private $: any;
-
- constructor(html: string) {
- this.$ = cheerio.load(html, {
- decodeEntities: false,
- xmlMode: false,
- });
- }
-
- serializeDom(): string {
- return this.$.html();
- }
-
- /**
- * Returns a strict Content Security Policy for mitigating XSS.
- * For more details read csp.withgoogle.com.
- * If you modify this CSP, make sure it has not become trivially bypassable by
- * checking the policy using csp-evaluator.withgoogle.com.
- *
- * @param hashes A list of sha-256 hashes of trusted inline scripts.
- * @param enableTrustedTypes If Trusted Types should be enabled for scripts.
- * @param enableBrowserFallbacks If fallbacks for older browsers should be
- * added. This is will not weaken the policy as modern browsers will ignore
- * the fallbacks.
- */
- static getStrictCsp(
- hashes?: string[],
- enableTrustedTypes?: boolean,
- enableBrowserFallbacks?: boolean,
- ): string {
- hashes = hashes || [];
- let strictCspTemplate = {
- // 'strict-dynamic' allows hashed scripts to create new scripts.
- 'script-src': [`'strict-dynamic'`, ...hashes],
- // Restricts `object-src` to disable dangerous plugins like Flash.
- 'object-src': [`'none'`],
- // Restricts `base-uri` to block the injection of `` tags. This
- // prevents attackers from changing the locations of scripts loaded from
- // relative URLs.
- 'base-uri': [`'self'`],
- };
-
- // Adds fallbacks for browsers not compatible to CSP3 and CSP2.
- // These fallbacks are ignored by modern browsers in presence of hashes,
- // and 'strict-dynamic'.
- if (enableBrowserFallbacks) {
- // Fallback for Safari. All modern browsers supporting strict-dynamic will
- // ignore the 'https:' fallback.
- strictCspTemplate['script-src'].push('https:');
- // 'unsafe-inline' is only ignored in presence of a hash or nonce.
- if (hashes.length > 0) {
- strictCspTemplate['script-src'].push(`'unsafe-inline'`);
- }
- }
-
- // If enabled, dangerous DOM sinks will only accept typed objects instead of
- // strings.
- if (enableTrustedTypes) {
- strictCspTemplate = {
- ...strictCspTemplate,
- ...{ 'require-trusted-types-for': [`'script'`] },
- };
- }
-
- return Object.entries(strictCspTemplate)
- .map(([directive, values]) => {
- return `${directive} ${values.join(' ')};`;
- })
- .join('');
- }
-
- /**
- * Enables a CSP via a meta tag at the beginning of the document.
- * Warning: It's recommended to set CSP as HTTP response header instead of
- * using a meta tag. Injections before the meta tag will not be covered by CSP
- * and meta tags don't support CSP in report-only mode.
- *
- * @param csp A Content Security Policy string.
- */
- addMetaTag(csp: string): void {
- let metaTag = this.$('meta[http-equiv="Content-Security-Policy"]');
- if (!metaTag.length) {
- metaTag = cheerio.load('')(
- 'meta',
- );
- metaTag.prependTo(this.$('head'));
- }
- metaTag.attr('content', csp);
- }
-
- /**
- * Replaces all sourced scripts with a single inline script that can be hashed
- */
- refactorSourcedScriptsForHashBasedCsp(): void {
- const srcList = this.$(StrictCsp.SOURCED_SCRIPT_SELECTOR)
- .map((i: any, script: any) => {
- const src = this.$(script).attr('src');
- this.$(script).remove();
- return src;
- })
- .filter((src: any) => src !== null)
- .get();
-
- const loaderScript = StrictCsp.createLoaderScript(srcList);
- if (!loaderScript) {
- return;
- }
-
- // const hash = StrictCsp.hashInlineScript(loaderScript);
- // const comment = cheerio.load(``).root();
- // comment.appendTo(this.$('body'));
- const newScript = cheerio.load('