mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05:00
fix(npm): properly handle legacy shasum of package (#20557)
Closes #20554
This commit is contained in:
parent
dc1da30927
commit
3de9af4d0b
5 changed files with 107 additions and 31 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
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();
|
||||
(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
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
if tarball_checksum != expected_checksum {
|
||||
bail!(
|
||||
"Tarball checksum did not match what was provided by npm registry for {}.\n\nExpected: {}\nActual: {}",
|
||||
|
@ -147,19 +160,37 @@ mod test {
|
|||
let actual_checksum =
|
||||
"z4phnx7vul3xvchq1m2ab9yg5aulvxxcg/spidns6c5h0ne8xyxysp+dgnkhfuwvy7kxvudbeoglodj6+sfapg==";
|
||||
assert_eq!(
|
||||
verify_tarball_integrity(&package, &Vec::new(), "test")
|
||||
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")
|
||||
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")
|
||||
verify_tarball_integrity(
|
||||
&package,
|
||||
&Vec::new(),
|
||||
&NpmPackageVersionDistInfoIntegrity::Integrity {
|
||||
algorithm: "sha1",
|
||||
base64_hash: "test"
|
||||
}
|
||||
)
|
||||
.unwrap_err()
|
||||
.to_string(),
|
||||
concat!(
|
||||
|
@ -168,7 +199,14 @@ mod test {
|
|||
),
|
||||
);
|
||||
assert_eq!(
|
||||
verify_tarball_integrity(&package, &Vec::new(), "sha512-test")
|
||||
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}"),
|
||||
|
@ -176,7 +214,27 @@ mod test {
|
|||
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());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue