summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2023-09-18 16:40:41 -0400
committerGitHub <noreply@github.com>2023-09-18 16:40:41 -0400
commit3de9af4d0bf5a411e4c43ce1ce474665585502b9 (patch)
tree156a55dd21b6e11ae77702e5f6b3748cc87657c8
parentdc1da309274823c15ad8ade0545678f8a9b8e54d (diff)
fix(npm): properly handle legacy shasum of package (#20557)
Closes #20554
-rw-r--r--Cargo.lock5
-rw-r--r--Cargo.toml2
-rw-r--r--cli/Cargo.toml1
-rw-r--r--cli/npm/resolution.rs18
-rw-r--r--cli/npm/tarball.rs112
5 files changed, 107 insertions, 31 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9cb7c2bd7..e122c65a1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1024,6 +1024,7 @@ dependencies = [
"fwdansi",
"glibc_version",
"glob",
+ "hex",
"http",
"hyper 0.14.27",
"import_map",
@@ -1588,9 +1589,9 @@ dependencies = [
[[package]]
name = "deno_npm"
-version = "0.15.0"
+version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b266a37deae9bc36785d44e9cc1c52d504940b89e5fea63b65119bef44b128a3"
+checksum = "7aba69155a585297af4b9ba8d204567bcd51b25af77b5f4c8856b867019093ba"
dependencies = [
"anyhow",
"async-trait",
diff --git a/Cargo.toml b/Cargo.toml
index 22b6aa4e8..966f9a899 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -48,7 +48,7 @@ deno_bench_util = { version = "0.112.0", path = "./bench_util" }
test_util = { path = "./test_util" }
deno_lockfile = "0.17.1"
deno_media_type = { version = "0.1.1", features = ["module_specifier"] }
-deno_npm = "0.15.0"
+deno_npm = "0.15.1"
deno_semver = "0.5.0"
# exts
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index 8c67d7b29..92251e78b 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -85,6 +85,7 @@ fastwebsockets.workspace = true
flate2.workspace = true
fs3.workspace = true
glob = "0.3.1"
+hex.workspace = true
http.workspace = true
hyper.workspace = true
import_map = "=0.15.0"
diff --git a/cli/npm/resolution.rs b/cli/npm/resolution.rs
index 10ff5fd92..5595a71ef 100644
--- a/cli/npm/resolution.rs
+++ b/cli/npm/resolution.rs
@@ -10,6 +10,7 @@ use deno_core::parking_lot::RwLock;
use deno_lockfile::NpmPackageDependencyLockfileInfo;
use deno_lockfile::NpmPackageLockfileInfo;
use deno_npm::registry::NpmPackageInfo;
+use deno_npm::registry::NpmPackageVersionDistInfoIntegrity;
use deno_npm::registry::NpmRegistryApi;
use deno_npm::resolution::NpmPackageVersionResolutionError;
use deno_npm::resolution::NpmPackagesPartitioned;
@@ -391,6 +392,21 @@ fn populate_lockfile_from_snapshot(
fn npm_package_to_lockfile_info(
pkg: &NpmResolutionPackage,
) -> NpmPackageLockfileInfo {
+ fn integrity_for_lockfile(
+ integrity: NpmPackageVersionDistInfoIntegrity,
+ ) -> String {
+ match integrity {
+ NpmPackageVersionDistInfoIntegrity::Integrity {
+ algorithm,
+ base64_hash,
+ } => format!("{}-{}", algorithm, base64_hash),
+ NpmPackageVersionDistInfoIntegrity::UnknownIntegrity(integrity) => {
+ integrity.to_string()
+ }
+ NpmPackageVersionDistInfoIntegrity::LegacySha1Hex(hex) => hex.to_string(),
+ }
+ }
+
let dependencies = pkg
.dependencies
.iter()
@@ -403,7 +419,7 @@ fn npm_package_to_lockfile_info(
NpmPackageLockfileInfo {
display_id: pkg.id.nv.to_string(),
serialized_id: pkg.id.as_serialized(),
- integrity: pkg.dist.integrity().to_string(),
+ integrity: integrity_for_lockfile(pkg.dist.integrity()),
dependencies,
}
}
diff --git a/cli/npm/tarball.rs b/cli/npm/tarball.rs
index f2f8d1ba4..e72b1afc8 100644
--- a/cli/npm/tarball.rs
+++ b/cli/npm/tarball.rs
@@ -8,6 +8,7 @@ use std::path::PathBuf;
use deno_core::anyhow::bail;
use deno_core::error::AnyError;
use deno_npm::registry::NpmPackageVersionDistInfo;
+use deno_npm::registry::NpmPackageVersionDistInfoIntegrity;
use deno_semver::package::PackageNv;
use flate2::read::GzDecoder;
use tar::Archive;
@@ -31,12 +32,15 @@ pub fn verify_and_extract_tarball(
fn verify_tarball_integrity(
package: &PackageNv,
data: &[u8],
- npm_integrity: &str,
+ npm_integrity: &NpmPackageVersionDistInfoIntegrity,
) -> Result<(), AnyError> {
use ring::digest::Context;
- let (algo, expected_checksum) = match npm_integrity.split_once('-') {
- Some((hash_kind, checksum)) => {
- let algo = match hash_kind {
+ let (tarball_checksum, expected_checksum) = match npm_integrity {
+ NpmPackageVersionDistInfoIntegrity::Integrity {
+ algorithm,
+ base64_hash,
+ } => {
+ let algo = match *algorithm {
"sha512" => &ring::digest::SHA512,
"sha1" => &ring::digest::SHA1_FOR_LEGACY_USE_ONLY,
hash_kind => bail!(
@@ -45,19 +49,28 @@ fn verify_tarball_integrity(
hash_kind
),
};
- (algo, checksum.to_lowercase())
+ let mut hash_ctx = Context::new(algo);
+ hash_ctx.update(data);
+ let digest = hash_ctx.finish();
+ let tarball_checksum = base64::encode(digest.as_ref()).to_lowercase();
+ (tarball_checksum, base64_hash.to_lowercase())
+ }
+ NpmPackageVersionDistInfoIntegrity::LegacySha1Hex(hex) => {
+ let mut hash_ctx = Context::new(&ring::digest::SHA1_FOR_LEGACY_USE_ONLY);
+ hash_ctx.update(data);
+ let digest = hash_ctx.finish();
+ let tarball_checksum = hex::encode(digest.as_ref()).to_lowercase();
+ (tarball_checksum, hex.to_lowercase())
+ }
+ NpmPackageVersionDistInfoIntegrity::UnknownIntegrity(integrity) => {
+ bail!(
+ "Not implemented integrity kind for {}: {}",
+ package,
+ integrity
+ )
}
- None => bail!(
- "Not implemented integrity kind for {}: {}",
- package,
- npm_integrity
- ),
};
- let mut hash_ctx = Context::new(algo);
- hash_ctx.update(data);
- let digest = hash_ctx.finish();
- let tarball_checksum = base64::encode(digest.as_ref()).to_lowercase();
if tarball_checksum != expected_checksum {
bail!(
"Tarball checksum did not match what was provided by npm registry for {}.\n\nExpected: {}\nActual: {}",
@@ -147,36 +160,81 @@ mod test {
let actual_checksum =
"z4phnx7vul3xvchq1m2ab9yg5aulvxxcg/spidns6c5h0ne8xyxysp+dgnkhfuwvy7kxvudbeoglodj6+sfapg==";
assert_eq!(
- verify_tarball_integrity(&package, &Vec::new(), "test")
- .unwrap_err()
- .to_string(),
+ verify_tarball_integrity(
+ &package,
+ &Vec::new(),
+ &NpmPackageVersionDistInfoIntegrity::UnknownIntegrity("test")
+ )
+ .unwrap_err()
+ .to_string(),
"Not implemented integrity kind for package@1.0.0: test",
);
assert_eq!(
- verify_tarball_integrity(&package, &Vec::new(), "notimplemented-test")
- .unwrap_err()
- .to_string(),
+ verify_tarball_integrity(
+ &package,
+ &Vec::new(),
+ &NpmPackageVersionDistInfoIntegrity::Integrity {
+ algorithm: "notimplemented",
+ base64_hash: "test"
+ }
+ )
+ .unwrap_err()
+ .to_string(),
"Not implemented hash function for package@1.0.0: notimplemented",
);
assert_eq!(
- verify_tarball_integrity(&package, &Vec::new(), "sha1-test")
- .unwrap_err()
- .to_string(),
+ verify_tarball_integrity(
+ &package,
+ &Vec::new(),
+ &NpmPackageVersionDistInfoIntegrity::Integrity {
+ algorithm: "sha1",
+ base64_hash: "test"
+ }
+ )
+ .unwrap_err()
+ .to_string(),
concat!(
"Tarball checksum did not match what was provided by npm ",
"registry for package@1.0.0.\n\nExpected: test\nActual: 2jmj7l5rsw0yvb/vlwaykk/ybwk=",
),
);
assert_eq!(
- verify_tarball_integrity(&package, &Vec::new(), "sha512-test")
- .unwrap_err()
- .to_string(),
+ verify_tarball_integrity(
+ &package,
+ &Vec::new(),
+ &NpmPackageVersionDistInfoIntegrity::Integrity {
+ algorithm: "sha512",
+ base64_hash: "test"
+ }
+ )
+ .unwrap_err()
+ .to_string(),
format!("Tarball checksum did not match what was provided by npm registry for package@1.0.0.\n\nExpected: test\nActual: {actual_checksum}"),
);
assert!(verify_tarball_integrity(
&package,
&Vec::new(),
- &format!("sha512-{actual_checksum}")
+ &NpmPackageVersionDistInfoIntegrity::Integrity {
+ algorithm: "sha512",
+ base64_hash: actual_checksum,
+ },
+ )
+ .is_ok());
+ let actual_hex = "da39a3ee5e6b4b0d3255bfef95601890afd80709";
+ assert_eq!(
+ verify_tarball_integrity(
+ &package,
+ &Vec::new(),
+ &NpmPackageVersionDistInfoIntegrity::LegacySha1Hex("test"),
+ )
+ .unwrap_err()
+ .to_string(),
+ format!("Tarball checksum did not match what was provided by npm registry for package@1.0.0.\n\nExpected: test\nActual: {actual_hex}"),
+ );
+ assert!(verify_tarball_integrity(
+ &package,
+ &Vec::new(),
+ &NpmPackageVersionDistInfoIntegrity::LegacySha1Hex(actual_hex),
)
.is_ok());
}