v0.35.0
This commit is contained in:
1 parent
2c03fcf248
commit
d3b492874b
95 files changed
+1628
-743
No files matched your search
@@ -286,7 +286,7 @@ pub fn for_all_frontends(
|
||||
}
|
||||
for cert in &mut result.certificates {
|
||||
cert.hosts.retain(|host| {
|
||||
!assignments.contains_key(&host.to_ascii_lowercase().trim_end_matches('.').to_string())
|
||||
!assignments.contains_key(host.to_ascii_lowercase().trim_end_matches('.'))
|
||||
});
|
||||
for (host, id) in &assignments {
|
||||
if id == &cert.id {
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
fn external_absolute_paths_follow_certbot_style_symlinks_on_each_reload() {
|
||||
use std::os::unix::fs::{symlink, PermissionsExt};
|
||||
|
||||
let root = tempfile::tempdir().unwrap();
|
||||
let root = private_tempdir();
|
||||
let cert_dir = root.path().join("rustproxy-certs");
|
||||
fs::create_dir(&cert_dir).unwrap();
|
||||
crate::auth::prepare_directory(&cert_dir).unwrap();
|
||||
initialize_default(&cert_dir).unwrap();
|
||||
|
||||
let archive = root.path().join("archive/example.test");
|
||||
@@ -100,7 +100,7 @@ fn external_absolute_paths_follow_certbot_style_symlinks_on_each_reload() {
|
||||
fn external_key_permissions_accept_acl_style_group_mask_but_reject_unsafe_write_or_world_read() {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
let root = tempfile::tempdir().unwrap();
|
||||
let root = private_tempdir();
|
||||
let key = root.path().join("external.key");
|
||||
fs::write(&key, b"not-a-real-key").unwrap();
|
||||
|
||||
@@ -119,7 +119,7 @@ fn external_key_permissions_accept_acl_style_group_mask_but_reject_unsafe_write_
|
||||
fn external_paths_reject_writable_non_sticky_parent_directories() {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
let root = tempfile::tempdir().unwrap();
|
||||
let root = private_tempdir();
|
||||
let unsafe_parent = root.path().join("unsafe");
|
||||
fs::create_dir(&unsafe_parent).unwrap();
|
||||
fs::set_permissions(&unsafe_parent, fs::Permissions::from_mode(0o770)).unwrap();
|
||||
@@ -133,7 +133,7 @@ fn external_paths_reject_writable_non_sticky_parent_directories() {
|
||||
fn certificate_input_rejects_fifo_without_waiting_for_a_writer() {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
let root = tempfile::tempdir().unwrap();
|
||||
let root = private_tempdir();
|
||||
let fifo = root.path().join("certificate.pipe");
|
||||
let path = std::ffi::CString::new(fifo.as_os_str().as_bytes()).unwrap();
|
||||
assert_eq!(unsafe { libc::mkfifo(path.as_ptr(), 0o600) }, 0);
|
||||
|
||||
@@ -85,10 +85,12 @@ pub struct CertificateMetadata {
|
||||
fn der_text(tag: u8, raw: &[u8]) -> Option<String> {
|
||||
let value = match tag {
|
||||
0x0c | 0x13 | 0x14 | 0x16 => std::str::from_utf8(raw).ok()?.to_owned(),
|
||||
0x1e if raw.len() % 2 == 0 => {
|
||||
0x1e if raw.len().is_multiple_of(2) => {
|
||||
let units: Vec<u16> = raw
|
||||
.chunks_exact(2)
|
||||
.map(|chunk| u16::from_be_bytes([chunk[0], chunk[1]]))
|
||||
.as_chunks::<2>()
|
||||
.0
|
||||
.iter()
|
||||
.map(|chunk| u16::from_be_bytes(*chunk))
|
||||
.collect();
|
||||
String::from_utf16(&units).ok()?
|
||||
}
|
||||
|
||||
+29
-15
@@ -1,5 +1,20 @@
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn private_tempdir() -> tempfile::TempDir {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
std::fs::set_permissions(
|
||||
dir.path(),
|
||||
std::fs::Permissions::from_mode(0o700),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
dir
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn certificate_removal_requires_prior_unassignment_including_administration() {
|
||||
let certificate = Certificate {
|
||||
@@ -67,7 +82,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn external_pair_stages_generation_and_rolls_back_cleanly() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let dir = private_tempdir();
|
||||
let generated = rcgen::generate_simple_self_signed(vec![
|
||||
"shared.example.test".into(),
|
||||
"www.shared.example.test".into(),
|
||||
@@ -96,7 +111,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn external_pair_reconcile_is_idempotent_and_repairs_missing_generation() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let dir = private_tempdir();
|
||||
let generated =
|
||||
rcgen::generate_simple_self_signed(vec!["reconcile.example.test".into()]).unwrap();
|
||||
let certificate = generated.cert.pem();
|
||||
@@ -166,7 +181,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn default_is_persistent_and_tls_advertises_both_protocols() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let dir = private_tempdir();
|
||||
initialize_default(dir.path()).unwrap();
|
||||
let before = fs::read(dir.path().join("default.pem")).unwrap();
|
||||
initialize_default(dir.path()).unwrap();
|
||||
@@ -293,7 +308,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn pqc_builds_both_tcp_tls_and_quic_configs() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let dir = private_tempdir();
|
||||
initialize_default(dir.path()).unwrap();
|
||||
let mut settings = Settings::default();
|
||||
settings.policy.post_quantum = true;
|
||||
@@ -308,7 +323,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn administration_tls_supports_default_and_selected_certificate() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let dir = private_tempdir();
|
||||
initialize_default(dir.path()).unwrap();
|
||||
generate(dir.path(), "panel", vec!["panel.localhost".into()]).unwrap();
|
||||
let settings = Settings {
|
||||
@@ -347,7 +362,7 @@ mod tests {
|
||||
b.signing_key.serialize_pem().as_bytes()
|
||||
)
|
||||
.is_err());
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let dir = private_tempdir();
|
||||
initialize_default(dir.path()).unwrap();
|
||||
generate(dir.path(), "a", vec!["a.localhost".into()]).unwrap();
|
||||
let mut settings = Settings {
|
||||
@@ -370,7 +385,7 @@ mod tests {
|
||||
}
|
||||
#[test]
|
||||
fn named_generation_never_overwrites_keys() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let dir = private_tempdir();
|
||||
generate(dir.path(), "app", vec!["app.localhost".into()]).unwrap();
|
||||
let before = fs::read(dir.path().join("app.key")).unwrap();
|
||||
assert!(generate(dir.path(), "app", vec!["other.localhost".into()]).is_err());
|
||||
@@ -378,7 +393,7 @@ mod tests {
|
||||
}
|
||||
#[test]
|
||||
fn certificate_hostname_bindings_are_not_artificially_capped() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let dir = private_tempdir();
|
||||
let hosts = (0..40)
|
||||
.map(|index| format!("host-{index}.example.test"))
|
||||
.collect::<Vec<_>>();
|
||||
@@ -408,7 +423,7 @@ mod tests {
|
||||
}
|
||||
#[test]
|
||||
fn uploads_validate_key_and_names_and_store_only_private_immutable_files() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let dir = private_tempdir();
|
||||
initialize_default(dir.path()).unwrap();
|
||||
let pair = rcgen::generate_simple_self_signed(vec![
|
||||
"app.localhost".into(),
|
||||
@@ -481,7 +496,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn legacy_certificate_coverage_can_be_read_from_existing_pem() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let dir = private_tempdir();
|
||||
let pair = rcgen::generate_simple_self_signed(vec![
|
||||
"app.example.org".into(),
|
||||
"*.example.org".into(),
|
||||
@@ -496,7 +511,7 @@ mod tests {
|
||||
}
|
||||
#[test]
|
||||
fn mismatched_named_certificate_requires_explicit_per_vhost_consent() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let dir = private_tempdir();
|
||||
initialize_default(dir.path()).unwrap();
|
||||
generate(dir.path(), "named", vec!["right.example.test".into()]).unwrap();
|
||||
let settings = Settings {
|
||||
@@ -511,13 +526,12 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
let mut config = crate::config::demo_config("127.0.0.1:9000".parse().unwrap());
|
||||
let vhost = &mut config.vhosts[0];
|
||||
vhost.certificate_id = Some("named".into());
|
||||
vhost.frontend.hosts = vec!["other.example.test".into()];
|
||||
config.vhosts[0].certificate_id = Some("named".into());
|
||||
config.vhosts[0].frontend.hosts = vec!["other.example.test".into()];
|
||||
let blocked = for_vhosts(&settings, &config.vhosts).unwrap();
|
||||
assert!(compile(&blocked, Some(dir.path())).is_err());
|
||||
assert!(blocked.forced_mismatches.is_empty());
|
||||
vhost.allow_certificate_mismatch = true;
|
||||
config.vhosts[0].allow_certificate_mismatch = true;
|
||||
let forced = for_vhosts(&settings, &config.vhosts).unwrap();
|
||||
assert!(forced
|
||||
.forced_mismatches
|
||||
|
||||
+1
-11
@@ -17,7 +17,7 @@ use zeroize::Zeroizing;
|
||||
|
||||
const MAX_PEM: u64 = 131_072;
|
||||
const MAX_CERTIFICATE_PATH: usize = 4096;
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Settings {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
@@ -28,16 +28,6 @@ pub struct Settings {
|
||||
#[serde(skip)]
|
||||
pub forced_mismatches: HashSet<(String, String)>,
|
||||
}
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
default_certificate: None,
|
||||
certificates: Vec::new(),
|
||||
policy: ProtocolPolicy::default(),
|
||||
forced_mismatches: HashSet::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Settings {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.default_certificate.is_none()
|
||||
|
||||
Reference in new issue
Block a user