From d1dd66ffe82c3ba78a1a504c6867b85a9da03e70 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Fri, 29 Nov 2024 05:45:41 +0000 Subject: [PATCH] feat: gpg verification for node --- schema/mise.json | 4 +++ settings.toml | 6 +++++ src/plugins/core/node.rs | 51 ++++++++++++++++++++++++++++++++++++--- src/plugins/core/swift.rs | 23 ++++++++---------- 4 files changed, 67 insertions(+), 17 deletions(-) diff --git a/schema/mise.json b/schema/mise.json index 3fe2d1850b..31eaa0bfd3 100644 --- a/schema/mise.json +++ b/schema/mise.json @@ -371,6 +371,10 @@ "description": "Install a specific node flavor like glibc-217 or musl. Use with unofficial node build repo.", "type": "string" }, + "gpg_verify": { + "description": "Use gpg to verify node tool signatures.", + "type": "boolean" + }, "mirror_url": { "description": "Mirror to download node tarballs from.", "type": "string" diff --git a/settings.toml b/settings.toml index ed291b7462..7a079c8cca 100644 --- a/settings.toml +++ b/settings.toml @@ -461,6 +461,12 @@ type = "String" optional = true description = "Install a specific node flavor like glibc-217 or musl. Use with unofficial node build repo." +[node.gpg_verify] +env = "MISE_NODE_GPG_VERIFY" +type = "Bool" +optional = true +description = "Use gpg to verify node tool signatures." + [node.mirror_url] env = "MISE_NODE_MIRROR_URL" type = "Url" diff --git a/src/plugins/core/node.rs b/src/plugins/core/node.rs index 1c12ed46c5..9763333652 100644 --- a/src/plugins/core/node.rs +++ b/src/plugins/core/node.rs @@ -152,7 +152,7 @@ impl NodePlugin { } if *env::MISE_NODE_VERIFY && !tv.checksums.contains_key(&tarball_name) { tv.checksums - .insert(tarball_name, self.get_checksum(local, version)?); + .insert(tarball_name, self.get_checksum(ctx, local, version)?); } self.verify_checksum(ctx, tv, local)?; Ok(()) @@ -180,15 +180,58 @@ impl NodePlugin { self.sh(ctx, opts)?.arg(&opts.make_install_cmd).execute() } - fn get_checksum(&self, tarball: &Path, version: &str) -> Result { + fn get_checksum(&self, ctx: &InstallContext, tarball: &Path, version: &str) -> Result { let tarball_name = tarball.file_name().unwrap().to_string_lossy().to_string(); - // TODO: verify gpg signature - let shasums = HTTP.get_text(self.shasums_url(version)?)?; + let shasums_file = tarball.parent().unwrap().join("SHASUMS256.txt"); + HTTP.download_file( + self.shasums_url(version)?, + &shasums_file, + Some(ctx.pr.as_ref()), + )?; + if SETTINGS.node.gpg_verify != Some(false) { + self.verify_with_gpg(ctx, &shasums_file, version)?; + } + let shasums = file::read_to_string(&shasums_file)?; let shasums = hash::parse_shasums(&shasums); let shasum = shasums.get(&tarball_name).unwrap(); Ok(format!("sha256:{shasum}")) } + fn verify_with_gpg(&self, ctx: &InstallContext, shasums_file: &Path, v: &str) -> Result<()> { + if file::which_non_pristine("gpg").is_none() && SETTINGS.node.gpg_verify.is_none() { + warn!("gpg not found, skipping verification"); + return Ok(()); + } + let sig_file = shasums_file.with_extension("asc"); + let sig_url = format!("{}.sig", self.shasums_url(v)?); + HTTP.download_file(sig_url, &sig_file, Some(ctx.pr.as_ref()))?; + CmdLineRunner::new("gpg") + .arg("--keyserver") + .arg("hkps://keys.openpgp.org") + .arg("--recv-keys") + .arg("--quiet") + .arg("C0D6248439F1D5604AAFFB4021D900FFDB233756") // Antoine du Hamel + .arg("DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7") // Juan José Arboleda + .arg("CC68F5A3106FF448322E48ED27F5E38D5B0A215F") // Marco Ippolito + .arg("8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600") // Michaël Zasso + .arg("890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4") // Rafael Gonzaga + .arg("C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C") // Richard Lau + .arg("108F52B48DB57BB0CC439B2997B01419BD92F80A") // Ruy Adorno + .arg("A363A499291CBBC940DD62E41F10027AF002F8B0") // Ulises Gascón + .with_pr(ctx.pr.as_ref()) + .execute()?; + CmdLineRunner::new("gpg") + .arg("--quiet") + .arg("--trust-model") + .arg("always") + .arg("--verify") + .arg(sig_file) + .arg(shasums_file) + .with_pr(ctx.pr.as_ref()) + .execute()?; + Ok(()) + } + fn node_path(&self, tv: &ToolVersion) -> PathBuf { if cfg!(windows) { tv.install_path().join("node.exe") diff --git a/src/plugins/core/swift.rs b/src/plugins/core/swift.rs index f699e06774..55414cecac 100644 --- a/src/plugins/core/swift.rs +++ b/src/plugins/core/swift.rs @@ -107,23 +107,20 @@ impl SwiftPlugin { tv: &ToolVersion, tarball_path: &Path, ) -> Result<()> { - if file::which("gpg").is_none() && SETTINGS.swift.gpg_verify.is_none() { + if file::which_non_pristine("gpg").is_none() && SETTINGS.swift.gpg_verify.is_none() { ctx.pr .println("gpg not found, skipping verification".to_string()); return Ok(()); } - let add_key = |key: &str| { - self.gpg(ctx) - .arg("--quiet") - .arg("--keyserver") - .arg("hkp://keyserver.ubuntu.com") - .arg("--recv-keys") - .arg(key) - .execute() - }; - add_key("E813 C892 820A 6FA1 3755 B268 F167 DF1A CF9C E069")?; - add_key("A62A E125 BBBF BB96 A6E0 42EC 925C C1CC ED3D 1561")?; - add_key("52BB 7E3D E28A 71BE 22EC 05FF EF80 A866 B47A 981F")?; + self.gpg(ctx) + .arg("--quiet") + .arg("--keyserver") + .arg("hkp://keyserver.ubuntu.com") + .arg("--recv-keys") + .arg("E813 C892 820A 6FA1 3755 B268 F167 DF1A CF9C E069") + .arg("A62A E125 BBBF BB96 A6E0 42EC 925C C1CC ED3D 1561") + .arg("52BB 7E3D E28A 71BE 22EC 05FF EF80 A866 B47A 981F") + .execute()?; let sig_path = PathBuf::from(format!("{}.sig", tarball_path.to_string_lossy())); HTTP.download_file(format!("{}.sig", url(tv)), &sig_path, Some(ctx.pr.as_ref()))?; self.gpg(ctx)