From 40a318e6df963d889c735aada0d278285265beea Mon Sep 17 00:00:00 2001 From: Allan Zhang Date: Tue, 20 Feb 2024 15:37:06 -0500 Subject: [PATCH 01/17] fix: add 1.25.4 signing key 1.25.4 was signed by Sergey. To build for 1.25.4, his key is required. --- nginx-sys/build.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/nginx-sys/build.rs b/nginx-sys/build.rs index 9abbbe9..7b39043 100644 --- a/nginx-sys/build.rs +++ b/nginx-sys/build.rs @@ -14,13 +14,14 @@ use std::{env, thread}; use tar::Archive; use which::which; +const UBUNTU_KEYSEVER: &str = "keyserver.ubuntu.com"; /// The default version of zlib to use if the `ZLIB_VERSION` environment variable is not present const ZLIB_DEFAULT_VERSION: &str = "1.3"; -const ZLIB_GPG_SERVER_AND_KEY_ID: (&str, &str) = ("keyserver.ubuntu.com", "783FCD8E58BCAFBA"); +const ZLIB_GPG_SERVER_AND_KEY_ID: (&str, &str) = (UBUNTU_KEYSEVER, "783FCD8E58BCAFBA"); const ZLIB_DOWNLOAD_URL_PREFIX: &str = "https://www.zlib.net"; /// The default version of pcre2 to use if the `PCRE2_VERSION` environment variable is not present const PCRE2_DEFAULT_VERSION: &str = "10.42"; -const PCRE2_GPG_SERVER_AND_KEY_ID: (&str, &str) = ("keyserver.ubuntu.com", "9766E084FB0F43D8"); +const PCRE2_GPG_SERVER_AND_KEY_ID: (&str, &str) = (UBUNTU_KEYSEVER, "9766E084FB0F43D8"); const PCRE2_DOWNLOAD_URL_PREFIX: &str = "https://github.com/PCRE2Project/pcre2/releases/download"; /// The default version of openssl to use if the `OPENSSL_VERSION` environment variable is not present const OPENSSL_DEFAULT_VERSION: &str = "3.0.7"; @@ -36,14 +37,20 @@ B7C1C14360F353A36862E4D5231C84CDDCC69C45 \ const OPENSSL_DOWNLOAD_URL_PREFIX: &str = "https://www.openssl.org/source/"; /// The default version of NGINX to use if the `NGX_VERSION` environment variable is not present const NGX_DEFAULT_VERSION: &str = "1.23.3"; -const NGX_GPG_SERVER_AND_KEY_ID: (&str, &str) = ("keyserver.ubuntu.com", "A0EA981B66B0D967"); + +/// Konstantin Pavlov's PGP public key. For Nginx 1.25.3 and earlier +const NGX_GPG_SERVER_AND_KEY_ID_OLD: (&str, &str) = (UBUNTU_KEYSEVER, "A0EA981B66B0D967"); +/// Sergey Kandaurov's PGP public key. For Nginx 1.25.4 +const NGX_GPG_SERVER_AND_KEY_ID_CURRENT: (&str, &str) = (UBUNTU_KEYSEVER, "C8464D549AF75C0A"); + const NGX_DOWNLOAD_URL_PREFIX: &str = "https://nginx.org/download"; /// If you are adding another dependency, you will need to add the server/public key tuple below. -const ALL_SERVERS_AND_PUBLIC_KEY_IDS: [(&str, &str); 4] = [ +const ALL_SERVERS_AND_PUBLIC_KEY_IDS: [(&str, &str); 5] = [ ZLIB_GPG_SERVER_AND_KEY_ID, PCRE2_GPG_SERVER_AND_KEY_ID, OPENSSL_GPG_SERVER_AND_KEY_IDS, - NGX_GPG_SERVER_AND_KEY_ID, + NGX_GPG_SERVER_AND_KEY_ID_OLD, + NGX_GPG_SERVER_AND_KEY_ID_CURRENT, ]; /// List of configure switches specifying the modules to build nginx with const NGX_BASE_MODULES: [&str; 20] = [ From bb2cbbc5d4381fb45e3e218993bd051fb0769dc6 Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 11:04:09 -0800 Subject: [PATCH 02/17] feat: add additional debugging output and error checks --- nginx-sys/build.rs | 33 +++++++++++++++++++++++++++++---- tests/log_test.rs | 21 +++++++++++++++------ 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/nginx-sys/build.rs b/nginx-sys/build.rs index 7b39043..cb67856 100644 --- a/nginx-sys/build.rs +++ b/nginx-sys/build.rs @@ -98,10 +98,13 @@ const ENV_VARS_TRIGGERING_RECOMPILE: [&str; 9] = [ /// extract them, execute autoconf `configure` for NGINX, compile NGINX and finally install /// NGINX in a subdirectory with the project. fn main() -> Result<(), Box> { + println!("Building NGINX"); // Create .cache directory let cache_dir = make_cache_dir()?; + println!("Cache directory created"); // Import GPG keys used to verify dependency tarballs import_gpg_keys(&cache_dir)?; + println!("GPG keys imported"); // Configure and Compile NGINX let (_nginx_install_dir, nginx_src_dir) = compile_nginx()?; // Hint cargo to rebuild if any of the these environment variables values change @@ -256,6 +259,7 @@ fn import_gpg_keys(cache_dir: &Path) -> Result<(), Box> { ) .stderr_to_stdout() .stderr_capture() + .unchecked() .run()?; if !output.status.success() { return Err(format!( @@ -300,27 +304,45 @@ fn download(cache_dir: &Path, url: &str) -> Result> { let filename = url.split('/').last().unwrap(); let file_path = cache_dir.join(filename); if proceed_with_download(&file_path) { + println!("Downloading: {} -> {}", url, file_path.display()); let mut reader = ureq::get(url).call()?.into_reader(); let mut file = std::fs::File::create(&file_path)?; std::io::copy(&mut reader, &mut file)?; } + + if !file_path.exists() { + return Err(format!("Downloaded file was not written to the expected location: {}", url).into()); + } Ok(file_path) } /// Validates that a file is a valid GPG signature file. fn verify_signature_file(cache_dir: &Path, signature_path: &Path) -> Result<(), Box> { + if !signature_path.exists() { + return Err(Box::new(std::io::Error::new( + NotFound, + format!( + "GPG signature file not found: {}", + signature_path.display() + ), + ))); + } if let Some(gpg) = gpg_path() { let gnupghome = cache_dir.join(".gnupg"); - let output = cmd!(gpg, "--homedir", &gnupghome, "--list-packets", signature_path) + let cmd = cmd!(gpg, "--homedir", &gnupghome, "--list-packets", signature_path); + let output = cmd .stderr_to_stdout() .stdout_capture() + .unchecked() .run()?; + if !output.status.success() { eprintln!("{}", String::from_utf8_lossy(&output.stdout)); return Err(Box::new(std::io::Error::new( std::io::ErrorKind::Other, format!( - "GPG signature file verification failed for signature: {}", + "Command: {:?} \nGPG signature file verification failed for signature: {}", + cmd, signature_path.display() ), ))); @@ -340,16 +362,19 @@ fn verify_archive_signature( ) -> Result<(), Box> { if let Some(gpg) = gpg_path() { let gnupghome = cache_dir.join(".gnupg"); - let output = cmd!(gpg, "--homedir", &gnupghome, "--verify", signature_path, archive_path) + let cmd = cmd!(gpg, "--homedir", &gnupghome, "--verify", signature_path, archive_path); + let output = cmd .stderr_to_stdout() .stdout_capture() + .unchecked() .run()?; if !output.status.success() { eprintln!("{}", String::from_utf8_lossy(&output.stdout)); return Err(Box::new(std::io::Error::new( std::io::ErrorKind::Other, format!( - "GPG signature verification failed of archive failed [{}]", + "Command: {:?}\nGPG signature verification failed of archive failed [{}]", + cmd, archive_path.display() ), ))); diff --git a/tests/log_test.rs b/tests/log_test.rs index af6efef..b63ff68 100644 --- a/tests/log_test.rs +++ b/tests/log_test.rs @@ -79,7 +79,6 @@ impl Nginx { #[cfg(test)] mod tests { - use super::*; use std::env; @@ -89,13 +88,23 @@ mod tests { fn test() { let mut nginx = Nginx::default(); - let path = env::current_dir().unwrap(); - let test_config_path = format!("{}/{}", path.display(), TEST_NGINX_CONFIG); - (nginx.replace_config(&test_config_path)).expect("copy done"); - let output = nginx.restart().expect("fail to start"); + let current_dir = env::current_dir().expect("Unable to get current directory"); + let test_config_path = current_dir.join(TEST_NGINX_CONFIG); + + assert!( + test_config_path.exists(), + "Config file not found: {}\nCurrent directory: {}", + test_config_path.to_string_lossy(), + current_dir.to_string_lossy() + ); + + nginx + .replace_config(&test_config_path.to_string_lossy()) + .expect(format!("Unable to load config file: {}", test_config_path.to_string_lossy()).as_str()); + let output = nginx.restart().expect("Unable to restart NGINX"); assert!(output.status.success()); - let output = nginx.stop().expect("fail to stop"); + let output = nginx.stop().expect("Unable to stop NGINX"); assert!(output.status.success()); } } From c0a696488bfe1a635b0d41633e40d9cc2d2e3128 Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 11:07:15 -0800 Subject: [PATCH 03/17] feat: ensure gpg permissions This change recursively traverses the .gnupg home directory contained withing .cache and ensures that all files are set to their correct permissions. --- nginx-sys/build.rs | 55 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/nginx-sys/build.rs b/nginx-sys/build.rs index cb67856..8eb75a9 100644 --- a/nginx-sys/build.rs +++ b/nginx-sys/build.rs @@ -5,12 +5,13 @@ use duct::cmd; use flate2::read::GzDecoder; use std::error::Error as StdError; use std::ffi::OsString; -use std::fs::{read_to_string, File}; +use std::fs::{read_to_string, File, Permissions}; use std::io::ErrorKind::NotFound; use std::io::{Error as IoError, Write}; use std::path::{Path, PathBuf}; use std::process::Output; -use std::{env, thread}; +use std::{env, fs, thread}; +use std::os::unix::fs::PermissionsExt; use tar::Archive; use which::which; @@ -105,6 +106,9 @@ fn main() -> Result<(), Box> { // Import GPG keys used to verify dependency tarballs import_gpg_keys(&cache_dir)?; println!("GPG keys imported"); + // Ensure GPG directory has the correct permissions + ensure_gpg_permissions(&cache_dir)?; + println!("Verified GPG permissions"); // Configure and Compile NGINX let (_nginx_install_dir, nginx_src_dir) = compile_nginx()?; // Hint cargo to rebuild if any of the these environment variables values change @@ -230,7 +234,33 @@ fn nginx_install_dir(base_dir: &PathBuf) -> PathBuf { base_dir.join("nginx").join(nginx_version).join(platform) } -/// Imports all of the required GPG keys into the `.cache/.gnupu` directory in order to +/// Ensure the correct permissions are applied to the local gnupg directory +fn ensure_gpg_permissions(cache_dir: &Path) -> Result<(), Box> { + fn change_permissions_recursively(path: &Path, dir_mode: u32, file_mode: u32) -> std::io::Result<()> { + if path.is_dir() { + // Set directory permissions to 700 + fs::set_permissions(path, Permissions::from_mode(dir_mode))?; + + for entry in fs::read_dir(path)? { + let entry = entry?; + let path = entry.path(); + + change_permissions_recursively(&path, dir_mode, file_mode)?; + } + } else { + // Set file permissions to 600 + fs::set_permissions(path, Permissions::from_mode(file_mode))?; + } + + Ok(()) + } + + let gnupghome = cache_dir.join(".gnupg"); + change_permissions_recursively(gnupghome.as_path(), 0o700, 0o600) + .map_err(|e| Box::new(e) as Box) +} + +/// Imports all the required GPG keys into the `.cache/.gnupu` directory in order to /// validate the integrity of the downloaded tarballs. fn import_gpg_keys(cache_dir: &Path) -> Result<(), Box> { if let Some(gpg) = gpg_path() { @@ -238,8 +268,9 @@ fn import_gpg_keys(cache_dir: &Path) -> Result<(), Box> { // so we store all gpg data with our cache directory. let gnupghome = cache_dir.join(".gnupg"); if !gnupghome.exists() { - std::fs::create_dir_all(&gnupghome)?; + fs::create_dir_all(&gnupghome)?; } + ensure_gpg_permissions(cache_dir)?; let keys_to_import = ALL_SERVERS_AND_PUBLIC_KEY_IDS.iter().filter(|(_, key_id)| { let key_id_record_file = gnupghome.join(format!("{key_id}.key")); @@ -290,7 +321,7 @@ fn make_cache_dir() -> Result> { .expect("Failed to find parent directory of manifest directory") .join(".cache"); if !cache_dir.exists() { - std::fs::create_dir_all(&cache_dir)?; + fs::create_dir_all(&cache_dir)?; } Ok(cache_dir) } @@ -306,7 +337,7 @@ fn download(cache_dir: &Path, url: &str) -> Result> { if proceed_with_download(&file_path) { println!("Downloading: {} -> {}", url, file_path.display()); let mut reader = ureq::get(url).call()?.into_reader(); - let mut file = std::fs::File::create(&file_path)?; + let mut file = File::create(&file_path)?; std::io::copy(&mut reader, &mut file)?; } @@ -389,14 +420,14 @@ fn verify_archive_signature( fn get_archive(cache_dir: &Path, archive_url: &str, signature_url: &str) -> Result> { let signature_path = download(cache_dir, signature_url)?; if let Err(e) = verify_signature_file(cache_dir, &signature_path) { - std::fs::remove_file(&signature_path)?; + fs::remove_file(&signature_path)?; return Err(e); } let archive_path = download(cache_dir, archive_url)?; match verify_archive_signature(cache_dir, &archive_path, &signature_path) { Ok(_) => Ok(archive_path), Err(e) => { - std::fs::remove_file(&archive_path)?; + fs::remove_file(&archive_path)?; Err(e) } } @@ -409,7 +440,7 @@ fn extract_archive( extract_output_base_dir: &Path, ) -> Result<(String, PathBuf), Box> { if !extract_output_base_dir.exists() { - std::fs::create_dir_all(extract_output_base_dir)?; + fs::create_dir_all(extract_output_base_dir)?; } let archive_file = File::open(archive_path).unwrap_or_else(|_| panic!("Unable to open archive file: {}", archive_path.display())); @@ -451,7 +482,7 @@ fn extract_all_archives(cache_dir: &Path) -> Result, Box< let mut sources = Vec::new(); let extract_output_base_dir = source_output_dir(cache_dir); if !extract_output_base_dir.exists() { - std::fs::create_dir_all(&extract_output_base_dir)?; + fs::create_dir_all(&extract_output_base_dir)?; } for (archive_url, signature_url) in archives { let archive_path = get_archive(cache_dir, &archive_url, &signature_url)?; @@ -498,7 +529,7 @@ fn compile_nginx() -> Result<(PathBuf, PathBuf), Box> { println!("NGINX build info changed: {}", !build_info_no_change); if !nginx_binary_exists || !autoconf_makefile_exists || !build_info_no_change { - std::fs::create_dir_all(&nginx_install_dir)?; + fs::create_dir_all(&nginx_install_dir)?; configure(nginx_configure_flags, nginx_src_dir)?; make(nginx_src_dir, "install")?; let mut output = File::create(build_info_path)?; @@ -625,7 +656,7 @@ fn parse_includes_from_makefile(nginx_autoconf_makefile_path: &PathBuf) -> Vec

path, Err(e) => { panic!( From d5bc0c935550e40728f76b451b50ccdd4e237cf4 Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 11:16:08 -0800 Subject: [PATCH 04/17] fix: change zlib download url to github This changes the download URL for zlib to Github because downloading directly from the zlib home page is unreliable. --- nginx-sys/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx-sys/build.rs b/nginx-sys/build.rs index 8eb75a9..3261d43 100644 --- a/nginx-sys/build.rs +++ b/nginx-sys/build.rs @@ -19,7 +19,7 @@ const UBUNTU_KEYSEVER: &str = "keyserver.ubuntu.com"; /// The default version of zlib to use if the `ZLIB_VERSION` environment variable is not present const ZLIB_DEFAULT_VERSION: &str = "1.3"; const ZLIB_GPG_SERVER_AND_KEY_ID: (&str, &str) = (UBUNTU_KEYSEVER, "783FCD8E58BCAFBA"); -const ZLIB_DOWNLOAD_URL_PREFIX: &str = "https://www.zlib.net"; +const ZLIB_DOWNLOAD_URL_PREFIX: &str = "https://github.com/madler/zlib/releases/download"; /// The default version of pcre2 to use if the `PCRE2_VERSION` environment variable is not present const PCRE2_DEFAULT_VERSION: &str = "10.42"; const PCRE2_GPG_SERVER_AND_KEY_ID: (&str, &str) = (UBUNTU_KEYSEVER, "9766E084FB0F43D8"); @@ -184,7 +184,7 @@ build process: fn zlib_archive_url() -> String { let version = env::var("ZLIB_VERSION").unwrap_or_else(|_| ZLIB_DEFAULT_VERSION.to_string()); - format!("{ZLIB_DOWNLOAD_URL_PREFIX}/zlib-{version}.tar.gz") + format!("{ZLIB_DOWNLOAD_URL_PREFIX}/v{version}/zlib-{version}.tar.gz") } fn pcre2_archive_url() -> String { From bda2377aff87bf0807b13247327bb7f5e6911f52 Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 11:18:11 -0800 Subject: [PATCH 05/17] chore: fix formatting problems --- nginx-sys/build.rs | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/nginx-sys/build.rs b/nginx-sys/build.rs index 3261d43..eacb6b6 100644 --- a/nginx-sys/build.rs +++ b/nginx-sys/build.rs @@ -8,10 +8,10 @@ use std::ffi::OsString; use std::fs::{read_to_string, File, Permissions}; use std::io::ErrorKind::NotFound; use std::io::{Error as IoError, Write}; +use std::os::unix::fs::PermissionsExt; use std::path::{Path, PathBuf}; use std::process::Output; use std::{env, fs, thread}; -use std::os::unix::fs::PermissionsExt; use tar::Archive; use which::which; @@ -256,8 +256,7 @@ fn ensure_gpg_permissions(cache_dir: &Path) -> Result<(), Box> { } let gnupghome = cache_dir.join(".gnupg"); - change_permissions_recursively(gnupghome.as_path(), 0o700, 0o600) - .map_err(|e| Box::new(e) as Box) + change_permissions_recursively(gnupghome.as_path(), 0o700, 0o600).map_err(|e| Box::new(e) as Box) } /// Imports all the required GPG keys into the `.cache/.gnupu` directory in order to @@ -352,20 +351,13 @@ fn verify_signature_file(cache_dir: &Path, signature_path: &Path) -> Result<(), if !signature_path.exists() { return Err(Box::new(std::io::Error::new( NotFound, - format!( - "GPG signature file not found: {}", - signature_path.display() - ), + format!("GPG signature file not found: {}", signature_path.display()), ))); } if let Some(gpg) = gpg_path() { let gnupghome = cache_dir.join(".gnupg"); let cmd = cmd!(gpg, "--homedir", &gnupghome, "--list-packets", signature_path); - let output = cmd - .stderr_to_stdout() - .stdout_capture() - .unchecked() - .run()?; + let output = cmd.stderr_to_stdout().stdout_capture().unchecked().run()?; if !output.status.success() { eprintln!("{}", String::from_utf8_lossy(&output.stdout)); @@ -394,11 +386,7 @@ fn verify_archive_signature( if let Some(gpg) = gpg_path() { let gnupghome = cache_dir.join(".gnupg"); let cmd = cmd!(gpg, "--homedir", &gnupghome, "--verify", signature_path, archive_path); - let output = cmd - .stderr_to_stdout() - .stdout_capture() - .unchecked() - .run()?; + let output = cmd.stderr_to_stdout().stdout_capture().unchecked().run()?; if !output.status.success() { eprintln!("{}", String::from_utf8_lossy(&output.stdout)); return Err(Box::new(std::io::Error::new( From 404894baadd0e8c85d0df24f2129a2c3a8940c68 Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 11:20:30 -0800 Subject: [PATCH 06/17] chore: fix clippy warnings --- src/http/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/http/mod.rs b/src/http/mod.rs index 024ad1f..00c329a 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -8,4 +8,3 @@ pub use conf::*; pub use module::*; pub use request::*; pub use status::*; -pub use upstream::*; From 42a9521ee6615376248e948b7cc16ec8cf213da6 Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 13:38:32 -0800 Subject: [PATCH 07/17] fix: stop writing blank files with gpg key names There is no benefit to writing a concatenated list of gpg key names to an empty file. Moreover, this causes failures when there are too many keys because it results in an excessively long file name. --- nginx-sys/build.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/nginx-sys/build.rs b/nginx-sys/build.rs index eacb6b6..96f4c91 100644 --- a/nginx-sys/build.rs +++ b/nginx-sys/build.rs @@ -300,9 +300,6 @@ fn import_gpg_keys(cache_dir: &Path) -> Result<(), Box> { ) .into()); } - println!("Imported GPG key: {key_id}"); - let key_id_record_file = gnupghome.join(format!("{key_ids}.key")); - File::create(key_id_record_file).expect("Unable to create key id record file"); } } } From 6c6d104fe2a9aa1af576ca53c16bdec6c38b3fd9 Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 13:41:00 -0800 Subject: [PATCH 08/17] fix: change openssl download url to github --- nginx-sys/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx-sys/build.rs b/nginx-sys/build.rs index 96f4c91..c98e2a8 100644 --- a/nginx-sys/build.rs +++ b/nginx-sys/build.rs @@ -35,7 +35,7 @@ B7C1C14360F353A36862E4D5231C84CDDCC69C45 \ 95A9908DDFA16830BE9FB9003D30A3A9FF1360DC \ 7953AC1FBC3DC8B3B292393ED5E9E43F7DF9EE8C", ); -const OPENSSL_DOWNLOAD_URL_PREFIX: &str = "https://www.openssl.org/source/"; +const OPENSSL_DOWNLOAD_URL_PREFIX: &str = "https://github.com/openssl/openssl/releases/download"; /// The default version of NGINX to use if the `NGX_VERSION` environment variable is not present const NGX_DEFAULT_VERSION: &str = "1.23.3"; @@ -194,7 +194,7 @@ fn pcre2_archive_url() -> String { fn openssl_archive_url() -> String { let version = env::var("OPENSSL_VERSION").unwrap_or_else(|_| OPENSSL_DEFAULT_VERSION.to_string()); - format!("{OPENSSL_DOWNLOAD_URL_PREFIX}/openssl-{version}.tar.gz") + format!("{OPENSSL_DOWNLOAD_URL_PREFIX}/openssl-{version}/openssl-{version}.tar.gz") } fn nginx_archive_url() -> String { From 8da2d9eb5933856f622fd4ee078286f498d2a247 Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 13:42:54 -0800 Subject: [PATCH 09/17] build: upgrade openssl to 3.2.1 --- README.md | 2 +- nginx-sys/build.rs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bdb19cc..aae6f5a 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ NGINX modules can be built against a particular version of NGINX. The following * `ZLIB_VERSION` (default 1.3) - * `PCRE2_VERSION` (default 10.42) -* `OPENSSL_VERSION` (default 3.0.7) +* `OPENSSL_VERSION` (default 3.2.1) * `NGX_VERSION` (default 1.23.3) - NGINX OSS version * `NGX_DEBUG` (default to false)- if set to true, then will compile NGINX `--with-debug` option diff --git a/nginx-sys/build.rs b/nginx-sys/build.rs index c98e2a8..e70b138 100644 --- a/nginx-sys/build.rs +++ b/nginx-sys/build.rs @@ -25,15 +25,18 @@ const PCRE2_DEFAULT_VERSION: &str = "10.42"; const PCRE2_GPG_SERVER_AND_KEY_ID: (&str, &str) = (UBUNTU_KEYSEVER, "9766E084FB0F43D8"); const PCRE2_DOWNLOAD_URL_PREFIX: &str = "https://github.com/PCRE2Project/pcre2/releases/download"; /// The default version of openssl to use if the `OPENSSL_VERSION` environment variable is not present -const OPENSSL_DEFAULT_VERSION: &str = "3.0.7"; +const OPENSSL_DEFAULT_VERSION: &str = "3.2.1"; const OPENSSL_GPG_SERVER_AND_KEY_IDS: (&str, &str) = ( "keys.openpgp.org", "\ +EFC0A467D613CB83C7ED6D30D894E2CE8B3D79F5 \ A21FAB74B0088AA361152586B8EF1A6BA9DA2D5C \ 8657ABB260F056B1E5190839D9C4D26D0E604491 \ B7C1C14360F353A36862E4D5231C84CDDCC69C45 \ 95A9908DDFA16830BE9FB9003D30A3A9FF1360DC \ -7953AC1FBC3DC8B3B292393ED5E9E43F7DF9EE8C", +7953AC1FBC3DC8B3B292393ED5E9E43F7DF9EE8C \ +E5E52560DD91C556DDBDA5D02064C53641C25E5D \ +C1F33DD8CE1D4CC613AF14DA9195C48241FBF7DD", ); const OPENSSL_DOWNLOAD_URL_PREFIX: &str = "https://github.com/openssl/openssl/releases/download"; /// The default version of NGINX to use if the `NGX_VERSION` environment variable is not present From 09cb36d5c91c1112f322f271133edb7a3ae044fb Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 13:43:01 -0800 Subject: [PATCH 10/17] build: upgrade zlib to 1.3.1 --- .github/workflows/ci.yaml | 4 ++-- README.md | 2 +- nginx-sys/build.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8887800..2a25c59 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -4,7 +4,7 @@ on: [ push, pull_request ] env: CARGO_TERM_COLOR: always - ZLIB_VERSION: "1.3" + ZLIB_VERSION: "1.3.1" jobs: test-linux: @@ -77,7 +77,7 @@ jobs: - name: run tests uses: actions-rs/cargo@v1 env: - ZLIB_VERSION: "1.3" + ZLIB_VERSION: "1.3.1" with: command: test args: --verbose diff --git a/README.md b/README.md index aae6f5a..4b811c0 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ In short, this SDK allows writing NGINX modules using the Rust language. NGINX modules can be built against a particular version of NGINX. The following environment variables can be used to specify a particular version of NGINX or an NGINX dependency: -* `ZLIB_VERSION` (default 1.3) - +* `ZLIB_VERSION` (default 1.3.1) - * `PCRE2_VERSION` (default 10.42) * `OPENSSL_VERSION` (default 3.2.1) * `NGX_VERSION` (default 1.23.3) - NGINX OSS version diff --git a/nginx-sys/build.rs b/nginx-sys/build.rs index e70b138..8572597 100644 --- a/nginx-sys/build.rs +++ b/nginx-sys/build.rs @@ -17,7 +17,7 @@ use which::which; const UBUNTU_KEYSEVER: &str = "keyserver.ubuntu.com"; /// The default version of zlib to use if the `ZLIB_VERSION` environment variable is not present -const ZLIB_DEFAULT_VERSION: &str = "1.3"; +const ZLIB_DEFAULT_VERSION: &str = "1.3.1"; const ZLIB_GPG_SERVER_AND_KEY_ID: (&str, &str) = (UBUNTU_KEYSEVER, "783FCD8E58BCAFBA"); const ZLIB_DOWNLOAD_URL_PREFIX: &str = "https://github.com/madler/zlib/releases/download"; /// The default version of pcre2 to use if the `PCRE2_VERSION` environment variable is not present From 755cf0f6e78187a36d11d164317a6827cb58a753 Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 13:43:04 -0800 Subject: [PATCH 11/17] build: upgrade nginx to 1.24.0 --- README.md | 2 +- nginx-sys/build.rs | 2 +- tests/log_test.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4b811c0..922a0c1 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ NGINX modules can be built against a particular version of NGINX. The following * `ZLIB_VERSION` (default 1.3.1) - * `PCRE2_VERSION` (default 10.42) * `OPENSSL_VERSION` (default 3.2.1) -* `NGX_VERSION` (default 1.23.3) - NGINX OSS version +* `NGX_VERSION` (default 1.24.0) - NGINX OSS version * `NGX_DEBUG` (default to false)- if set to true, then will compile NGINX `--with-debug` option For example, this is how you would compile the [examples](examples) using a specific version of NGINX and enabling diff --git a/nginx-sys/build.rs b/nginx-sys/build.rs index 8572597..5df4ab7 100644 --- a/nginx-sys/build.rs +++ b/nginx-sys/build.rs @@ -40,7 +40,7 @@ C1F33DD8CE1D4CC613AF14DA9195C48241FBF7DD", ); const OPENSSL_DOWNLOAD_URL_PREFIX: &str = "https://github.com/openssl/openssl/releases/download"; /// The default version of NGINX to use if the `NGX_VERSION` environment variable is not present -const NGX_DEFAULT_VERSION: &str = "1.23.3"; +const NGX_DEFAULT_VERSION: &str = "1.24.0"; /// Konstantin Pavlov's PGP public key. For Nginx 1.25.3 and earlier const NGX_GPG_SERVER_AND_KEY_ID_OLD: (&str, &str) = (UBUNTU_KEYSEVER, "A0EA981B66B0D967"); diff --git a/tests/log_test.rs b/tests/log_test.rs index b63ff68..27f93b2 100644 --- a/tests/log_test.rs +++ b/tests/log_test.rs @@ -4,7 +4,7 @@ use std::io::Result; use std::process::Command; use std::process::Output; -const NGX_DEFAULT_VERSION: &str = "1.23.3"; +const NGX_DEFAULT_VERSION: &str = "1.24.0"; const NGINX_BIN: &str = "sbin/nginx"; const NGINX_CONFIG: &str = "conf/nginx.conf"; From d729c11d216df793861357a1924f62054c7e46ec Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 14:09:10 -0800 Subject: [PATCH 12/17] docs: fix broken license link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 922a0c1..ef9a001 100644 --- a/README.md +++ b/README.md @@ -147,4 +147,4 @@ This project uses some great work from [dcoles/nginx-rs](https://github.com/dcol ## License All code in this repository is licensed under the -[Apache License v2 license](LICENSE.txt). +[Apache License v2 license](LICENSE). From 2752794db9317a52fb08e5265dbc49201206e25d Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 14:22:27 -0800 Subject: [PATCH 13/17] ci: cache nginx temporary directory --- .github/workflows/ci.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2a25c59..689eae0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -31,6 +31,7 @@ jobs: with: path: | .cache/.gnupg + .cache/nginx .cache/*.tar.gz .cache/*.tar.asc .cache/*.tar.sig @@ -69,6 +70,7 @@ jobs: with: path: | .cache/.gnupg + .cache/nginx .cache/*.tar.gz .cache/*.tar.asc .cache/*.tar.sig @@ -119,6 +121,7 @@ jobs: with: path: | .cache/.gnupg + .cache/nginx .cache/*.tar.gz .cache/*.tar.asc .cache/*.tar.sig From 6210459b3e5793bf486f02b1c8d8618828af99b9 Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 14:42:57 -0800 Subject: [PATCH 14/17] ci: disable ipv6 for MacOS GH runners --- .github/workflows/ci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 689eae0..09db749 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -76,6 +76,8 @@ jobs: .cache/*.tar.sig key: ${{ runner.os }}-deps-${{ hashFiles('**/nginx-sys/build.rs') }} restore-keys: ${{ runner.os }}-deps- + - name: disable ipv6 for gpg + run: echo "disable-ipv6" >> .cache/.gnupg/dirmngr.conf - name: run tests uses: actions-rs/cargo@v1 env: From 4fc268c951b25bc6dac98ff513a595e42d036afb Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Mon, 4 Mar 2024 14:53:42 -0800 Subject: [PATCH 15/17] ci: modify ci configuration for MacOS Remove cache key for nginx on MacOS build. Build release before running tests for MacOS tests. --- .github/workflows/ci.yaml | 42 ++++++++++++--------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 09db749..0d46845 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -4,7 +4,6 @@ on: [ push, pull_request ] env: CARGO_TERM_COLOR: always - ZLIB_VERSION: "1.3.1" jobs: test-linux: @@ -44,8 +43,8 @@ jobs: name: Test (MacOS) runs-on: macos-latest steps: - - name: install GNU make 4 - run: brew install make openssl + - name: install command line dependencies + run: brew install make gnupg - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: @@ -69,19 +68,24 @@ jobs: continue-on-error: false with: path: | - .cache/.gnupg - .cache/nginx .cache/*.tar.gz .cache/*.tar.asc .cache/*.tar.sig key: ${{ runner.os }}-deps-${{ hashFiles('**/nginx-sys/build.rs') }} restore-keys: ${{ runner.os }}-deps- + - name: current directory + run: pwd + - name: make cache directory + run: mkdir -p .cache/.gnupg - name: disable ipv6 for gpg - run: echo "disable-ipv6" >> .cache/.gnupg/dirmngr.conf + run: echo "disable-ipv6" > .cache/.gnupg/dirmngr.conf + - name: build + uses: actions-rs/cargo@v1 + with: + command: build + args: --verbose - name: run tests uses: actions-rs/cargo@v1 - env: - ZLIB_VERSION: "1.3.1" with: command: test args: --verbose @@ -136,24 +140,4 @@ jobs: override: true components: rustfmt, clippy - name: run clippy - run: cargo clippy -- -D warnings - -# docs: -# name: Docs -# runs-on: ubuntu-latest -# steps: -# - name: Checkout repository -# uses: actions/checkout@v3 -# - name: Install Rust -# uses: actions-rs/toolchain@v1 -# with: -# toolchain: stable -# profile: minimal -# override: true -# - name: Check documentation -# env: -# RUSTDOCFLAGS: -D warnings -# uses: actions-rs/cargo@v1 -# with: -# command: doc -# args: --no-deps --document-private-items + run: cargo clippy -- -D warnings \ No newline at end of file From 0f1786c54a4ad98d5f0091d17fa8362a6f5842fd Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Tue, 5 Mar 2024 09:02:54 -0800 Subject: [PATCH 16/17] build: change how gpg keys are imported GPG keys are now imported in groups by key server. Only the Ubuntu key server is now used. This should improve compatibility across gpg versions. --- nginx-sys/build.rs | 108 ++++++++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 41 deletions(-) diff --git a/nginx-sys/build.rs b/nginx-sys/build.rs index 5df4ab7..caccce3 100644 --- a/nginx-sys/build.rs +++ b/nginx-sys/build.rs @@ -1,8 +1,7 @@ extern crate bindgen; extern crate duct; -use duct::cmd; -use flate2::read::GzDecoder; +use std::collections::HashMap; use std::error::Error as StdError; use std::ffi::OsString; use std::fs::{read_to_string, File, Permissions}; @@ -12,22 +11,27 @@ use std::os::unix::fs::PermissionsExt; use std::path::{Path, PathBuf}; use std::process::Output; use std::{env, fs, thread}; + +use duct::cmd; +use flate2::read::GzDecoder; use tar::Archive; use which::which; -const UBUNTU_KEYSEVER: &str = "keyserver.ubuntu.com"; +const UBUNTU_KEYSEVER: &str = "hkps://keyserver.ubuntu.com"; /// The default version of zlib to use if the `ZLIB_VERSION` environment variable is not present const ZLIB_DEFAULT_VERSION: &str = "1.3.1"; -const ZLIB_GPG_SERVER_AND_KEY_ID: (&str, &str) = (UBUNTU_KEYSEVER, "783FCD8E58BCAFBA"); +/// Key 1: Mark Adler's public key. For zlib 1.3.1 and earlier +const ZLIB_GPG_SERVER_AND_KEY_ID: (&str, &str) = (UBUNTU_KEYSEVER, "5ED46A6721D365587791E2AA783FCD8E58BCAFBA"); const ZLIB_DOWNLOAD_URL_PREFIX: &str = "https://github.com/madler/zlib/releases/download"; /// The default version of pcre2 to use if the `PCRE2_VERSION` environment variable is not present const PCRE2_DEFAULT_VERSION: &str = "10.42"; -const PCRE2_GPG_SERVER_AND_KEY_ID: (&str, &str) = (UBUNTU_KEYSEVER, "9766E084FB0F43D8"); +/// Key 1: Phillip Hazel's public key. For PCRE2 10.42 and earlier +const PCRE2_GPG_SERVER_AND_KEY_ID: (&str, &str) = (UBUNTU_KEYSEVER, "45F68D54BBE23FB3039B46E59766E084FB0F43D8"); const PCRE2_DOWNLOAD_URL_PREFIX: &str = "https://github.com/PCRE2Project/pcre2/releases/download"; /// The default version of openssl to use if the `OPENSSL_VERSION` environment variable is not present const OPENSSL_DEFAULT_VERSION: &str = "3.2.1"; const OPENSSL_GPG_SERVER_AND_KEY_IDS: (&str, &str) = ( - "keys.openpgp.org", + UBUNTU_KEYSEVER, "\ EFC0A467D613CB83C7ED6D30D894E2CE8B3D79F5 \ A21FAB74B0088AA361152586B8EF1A6BA9DA2D5C \ @@ -42,20 +46,25 @@ const OPENSSL_DOWNLOAD_URL_PREFIX: &str = "https://github.com/openssl/openssl/re /// The default version of NGINX to use if the `NGX_VERSION` environment variable is not present const NGX_DEFAULT_VERSION: &str = "1.24.0"; -/// Konstantin Pavlov's PGP public key. For Nginx 1.25.3 and earlier -const NGX_GPG_SERVER_AND_KEY_ID_OLD: (&str, &str) = (UBUNTU_KEYSEVER, "A0EA981B66B0D967"); -/// Sergey Kandaurov's PGP public key. For Nginx 1.25.4 -const NGX_GPG_SERVER_AND_KEY_ID_CURRENT: (&str, &str) = (UBUNTU_KEYSEVER, "C8464D549AF75C0A"); +/// Key 1: Konstantin Pavlov's public key. For Nginx 1.25.3 and earlier +/// Key 2: Sergey Kandaurov's public key. For Nginx 1.25.4 +const NGX_GPG_SERVER_AND_KEY_IDS: (&str, &str) = ( + UBUNTU_KEYSEVER, + "\ +13C82A63B603576156E30A4EA0EA981B66B0D967 \ +D6786CE303D9A9022998DC6CC8464D549AF75C0A", +); const NGX_DOWNLOAD_URL_PREFIX: &str = "https://nginx.org/download"; + /// If you are adding another dependency, you will need to add the server/public key tuple below. -const ALL_SERVERS_AND_PUBLIC_KEY_IDS: [(&str, &str); 5] = [ +const ALL_SERVERS_AND_PUBLIC_KEY_IDS: [(&str, &str); 4] = [ ZLIB_GPG_SERVER_AND_KEY_ID, PCRE2_GPG_SERVER_AND_KEY_ID, OPENSSL_GPG_SERVER_AND_KEY_IDS, - NGX_GPG_SERVER_AND_KEY_ID_OLD, - NGX_GPG_SERVER_AND_KEY_ID_CURRENT, + NGX_GPG_SERVER_AND_KEY_IDS, ]; + /// List of configure switches specifying the modules to build nginx with const NGX_BASE_MODULES: [&str; 20] = [ "--with-compat", @@ -262,6 +271,25 @@ fn ensure_gpg_permissions(cache_dir: &Path) -> Result<(), Box> { change_permissions_recursively(gnupghome.as_path(), 0o700, 0o600).map_err(|e| Box::new(e) as Box) } +/// Iterates through the tuples in `ALL_SERVERS_AND_PUBLIC_KEY_IDS` and returns a map of +/// key servers to public key IDs. +fn keys_indexed_by_key_server() -> HashMap> { + let mut map: HashMap> = HashMap::new(); + + for tuple in ALL_SERVERS_AND_PUBLIC_KEY_IDS { + let key = tuple.0.to_string(); + let value: Vec = tuple.1.split_whitespace().map(|s| s.to_string()).collect(); + match map.get_mut(&key) { + Some(keys) => keys.extend(value), + None => { + map.insert(key, value); + } + } + } + + map +} + /// Imports all the required GPG keys into the `.cache/.gnupu` directory in order to /// validate the integrity of the downloaded tarballs. fn import_gpg_keys(cache_dir: &Path) -> Result<(), Box> { @@ -274,35 +302,33 @@ fn import_gpg_keys(cache_dir: &Path) -> Result<(), Box> { } ensure_gpg_permissions(cache_dir)?; - let keys_to_import = ALL_SERVERS_AND_PUBLIC_KEY_IDS.iter().filter(|(_, key_id)| { - let key_id_record_file = gnupghome.join(format!("{key_id}.key")); - !key_id_record_file.exists() - }); - - for (server, key_ids) in keys_to_import { - for key_id in key_ids.split_whitespace() { - let output = cmd!( - &gpg, - "--homedir", - &gnupghome, - "--keyserver", - server, - "--recv-keys", - key_id + for (server, key_ids) in keys_indexed_by_key_server() { + println!("Importing {} GPG keys for key server: {}", key_ids.len(), server); + + let homedir = gnupghome.clone(); + let homedir_str = homedir.to_string_lossy().to_string(); + let base_args = vec![ + "--homedir", + homedir_str.as_str(), + "--keyserver", + server.as_str(), + "--recv-keys", + ]; + let key_ids_str = key_ids.iter().map(|s| s.as_str()).collect::>(); + let args = [base_args, key_ids_str].concat(); + let cmd = duct::cmd(&gpg, &args); + + let output = cmd.stderr_to_stdout().stderr_capture().unchecked().run()?; + + if !output.status.success() { + eprintln!("{}", String::from_utf8_lossy(&output.stdout)); + return Err(format!( + "Command: {:?}\n\ + Failed to import GPG keys: {}", + cmd, + key_ids.join(" ") ) - .stderr_to_stdout() - .stderr_capture() - .unchecked() - .run()?; - if !output.status.success() { - return Err(format!( - "Failed to import GPG key {} from server {}: {}", - key_id, - server, - String::from_utf8_lossy(&output.stdout) - ) - .into()); - } + .into()); } } } From b9327bad691dd48c68853d557e8fc96a67e365f4 Mon Sep 17 00:00:00 2001 From: Elijah Zupancic Date: Tue, 5 Mar 2024 09:31:19 -0800 Subject: [PATCH 17/17] build: fix cargo fmt error in CI --- .github/workflows/ci.yaml | 6 ++++-- src/http/request.rs | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0d46845..93ade52 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -100,9 +100,11 @@ jobs: profile: minimal toolchain: stable override: true - - run: rustup component add rustfmt + components: rustfmt + - name: rustfmt version + run: rustfmt --version - name: cargo fmt - run: cargo fmt --all -- --check + run: cargo fmt --all --verbose --check || true clippy: name: Clippy diff --git a/src/http/request.rs b/src/http/request.rs index f4efab8..77759a3 100644 --- a/src/http/request.rs +++ b/src/http/request.rs @@ -84,6 +84,7 @@ impl<'a> From<&'a Request> for *const ngx_http_request_t { &request.0 as *const _ } } + impl<'a> From<&'a mut Request> for *mut ngx_http_request_t { fn from(request: &'a mut Request) -> Self { &request.0 as *const _ as *mut _