Browse Source

Forbid hook or group names to start with `internal:`

ng
Rodolphe Bréard 4 weeks ago
parent
commit
562bf3acb9
Failed to extract signature
  1. 6
      man/en/acmed.toml.5
  2. 59
      src/config.rs
  3. 1
      src/main.rs

6
man/en/acmed.toml.5

@ -321,11 +321,13 @@ section. Default is 30d.
Array containing the path to root certificates that should be added to the trust store. Array containing the path to root certificates that should be added to the trust store.
.El .El
.It Ic group .It Ic group
Table of array allowing to group several hooks as one. A group is considered as new hook. The array contains the names of the hooks that are grouped. The hooks are guaranteed to be called sequentially in the declaration order.
Table of array allowing to group several hooks as one. A group is considered as new hook. The array contains the names of the hooks that are grouped. The hooks are guaranteed to be called sequentially in the declaration order. The group name must not start with
.Dq internal: .
.It Ic hook .It Ic hook
Table where each element defines a command that will be launched at a defined point. See section Table where each element defines a command that will be launched at a defined point. See section
.Sx WRITING A HOOK .Sx WRITING A HOOK
for more details.
for more details. The hook name must not start with
.Dq internal: .
.Bl -tag .Bl -tag
.It Cm allow_failure Ar boolean .It Cm allow_failure Ar boolean
Defines if an error return value for this hook is allowed or not. If not allowed, a failure in this hook will fail the whole certificate request process. Default is false. Defines if an error return value for this hook is allowed or not. If not allowed, a failure in this hook will fail the whole certificate request process. Default is false.

59
src/config.rs

@ -16,6 +16,7 @@ pub use rate_limit::*;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use config::{Config, File}; use config::{Config, File};
use serde::{de, Deserialize, Deserializer};
use serde_derive::Deserialize; use serde_derive::Deserialize;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -24,6 +25,7 @@ use walkdir::WalkDir;
const ALLOWED_FILE_EXT: &[&str] = &["toml"]; const ALLOWED_FILE_EXT: &[&str] = &["toml"];
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(remote = "Self")]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct AcmedConfig { pub struct AcmedConfig {
pub(in crate::config) global: Option<GlobalOptions>, pub(in crate::config) global: Option<GlobalOptions>,
@ -41,6 +43,26 @@ pub struct AcmedConfig {
pub(in crate::config) certificate: Vec<Certificate>, pub(in crate::config) certificate: Vec<Certificate>,
} }
impl<'de> Deserialize<'de> for AcmedConfig {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let unchecked = AcmedConfig::deserialize(deserializer)?;
for key in unchecked.hook.keys() {
if key.starts_with(crate::INTERNAL_HOOK_PREFIX) {
return Err(de::Error::custom(format!("{key}: invalid hook name")));
}
}
for key in unchecked.group.keys() {
if key.starts_with(crate::INTERNAL_HOOK_PREFIX) {
return Err(de::Error::custom(format!("{key}: invalid group name")));
}
}
Ok(unchecked)
}
}
pub fn load<P: AsRef<Path>>(config_dir: P) -> Result<AcmedConfig> { pub fn load<P: AsRef<Path>>(config_dir: P) -> Result<AcmedConfig> {
let config_dir = config_dir.as_ref(); let config_dir = config_dir.as_ref();
tracing::debug!("loading config directory: {config_dir:?}"); tracing::debug!("loading config directory: {config_dir:?}");
@ -195,4 +217,41 @@ mod tests {
assert!(account.signature_algorithm.is_none()); assert!(account.signature_algorithm.is_none());
assert!(cfg.certificate.is_empty()); assert!(cfg.certificate.is_empty());
} }
#[test]
fn invalid_hook_name() {
let cfg = r#"
[hook."internal:hook"]
cmd = "cat"
type = ["file-pre-edit"]
"#;
let res = load_str::<AcmedConfig>(cfg);
assert!(res.is_err());
}
#[test]
fn invalid_group_name() {
let cfg = r#"
[hook."test"]
cmd = "cat"
type = ["file-pre-edit"]
[group]
internal:grp = ["test"]
"#;
let res = load_str::<AcmedConfig>(cfg);
assert!(res.is_err());
}
#[test]
fn valid_group_name() {
let cfg = r#"
[hook."internaltest"]
cmd = "cat"
type = ["file-pre-edit"]
[group]
internal-grp = ["internaltest"]
"#;
let res = load_str::<AcmedConfig>(cfg);
assert!(res.is_ok());
}
} }

1
src/main.rs

@ -14,6 +14,7 @@ use std::process;
pub const APP_IDENTITY: &[u8] = b"acmed\0"; pub const APP_IDENTITY: &[u8] = b"acmed\0";
pub const APP_THREAD_NAME: &str = "acmed-runtime"; pub const APP_THREAD_NAME: &str = "acmed-runtime";
pub const DEFAULT_LOG_LEVEL: log::Level = log::Level::Warn; pub const DEFAULT_LOG_LEVEL: log::Level = log::Level::Warn;
pub const INTERNAL_HOOK_PREFIX: &str = "internal:";
fn main() { fn main() {
// CLI // CLI

Loading…
Cancel
Save