| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -49,22 +49,32 @@ impl<'de> Deserialize<'de> for AcmedConfig { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							D: Deserializer<'de>,
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						{
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							let unchecked = AcmedConfig::deserialize(deserializer)?;
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							// Checking hooks
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							for key in unchecked.hook.keys() {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								// Hook name must not start with `internal:`
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								if key.starts_with(crate::INTERNAL_HOOK_PREFIX) {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									return Err(de::Error::custom(format!("{key}: invalid hook name")));
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							// Checking groups
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							for (key, hook_lst) in &unchecked.group {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								// Group name must not start with `internal:`
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								if key.starts_with(crate::INTERNAL_HOOK_PREFIX) {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									return Err(de::Error::custom(format!("{key}: invalid group name")));
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								// Group must only contain valid hook names
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								for hook_name in hook_lst {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									if !unchecked.hook.contains_key(hook_name) {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										return Err(de::Error::custom(format!("{hook_name}: hook not found")));
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							// Checking accoutns
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							for account in unchecked.account.values() {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								// Account must only contain valid hook/group names
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								for hook_name in &account.hooks {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									if !unchecked.hook.contains_key(hook_name)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										&& !unchecked.group.contains_key(hook_name)
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -73,6 +83,34 @@ impl<'de> Deserialize<'de> for AcmedConfig { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							// Checking certificates
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							for cert in &unchecked.certificate {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								// Certificate must contain a valid account name
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								if !unchecked.account.contains_key(&cert.account) {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									return Err(de::Error::custom(format!(
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										"{}: account not found",
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										cert.account
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									)));
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								// Certificate must contain a valid endpoint name
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								if !unchecked.endpoint.contains_key(&cert.endpoint) {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									return Err(de::Error::custom(format!(
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										"{}: endpoint not found",
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										cert.endpoint
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									)));
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								// Certificate must only contain valid hook/group names
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								for hook_name in &cert.hooks {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									if !unchecked.hook.contains_key(hook_name)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										&& !unchecked.group.contains_key(hook_name)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									{
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										return Err(de::Error::custom(format!("{hook_name}: hook not found")));
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							// All tests passed
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							Ok(unchecked)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					}
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -307,6 +345,102 @@ contacts = [ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						{ mailto = "acme@example.org" },
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					hooks = ["not-found"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					"#;
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							let res = load_str::<AcmedConfig>(cfg);
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							assert!(res.is_err());
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						#[test]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						fn certificate() {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							let cfg = r#"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					[account."toto"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					contacts = [
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						{ mailto = "acme@example.org" },
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					[hook."my-hook"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					cmd = "cat"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					type = ["challenge-http-01"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					[endpoint."my-ca"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					url = "https://acme-v02.ac1.example.org/directory"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					[[certificate]]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					account = "toto"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					endpoint = "my-ca"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					identifiers = [
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						{ dns = "example.org", challenge = "http-01"},
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					hooks = ["my-hook"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					"#;
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							let res = load_str::<AcmedConfig>(cfg);
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							assert!(res.is_ok());
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						#[test]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						fn account_404_certificate() {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							let cfg = r#"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					[hook."my-hook"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					cmd = "cat"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					type = ["challenge-http-01"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					[endpoint."my-ca"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					url = "https://acme-v02.ac1.example.org/directory"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					[[certificate]]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					account = "toto"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					endpoint = "my-ca"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					identifiers = [
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						{ dns = "example.org", challenge = "http-01"},
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					hooks = ["my-hook"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					"#;
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							let res = load_str::<AcmedConfig>(cfg);
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							assert!(res.is_err());
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						#[test]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						fn endpoint_404_certificate() {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							let cfg = r#"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					[account."toto"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					contacts = [
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						{ mailto = "acme@example.org" },
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					[hook."my-hook"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					cmd = "cat"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					type = ["challenge-http-01"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					[[certificate]]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					account = "toto"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					endpoint = "my-ca"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					identifiers = [
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						{ dns = "example.org", challenge = "http-01"},
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					hooks = ["my-hook"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					"#;
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							let res = load_str::<AcmedConfig>(cfg);
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							assert!(res.is_err());
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						}
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						#[test]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						fn hook_404_certificate() {
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							let cfg = r#"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					[account."toto"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					contacts = [
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						{ mailto = "acme@example.org" },
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					[endpoint."my-ca"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					url = "https://acme-v02.ac1.example.org/directory"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					[[certificate]]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					account = "toto"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					endpoint = "my-ca"
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					identifiers = [
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						{ dns = "example.org", challenge = "http-01"},
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					hooks = ["my-hook"]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					"#;
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							let res = load_str::<AcmedConfig>(cfg);
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							assert!(res.is_err());
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				
					
  |