From 0408edacc5bd3313f3d21542a72f96ab612a4640 Mon Sep 17 00:00:00 2001 From: Ruben Hensen Date: Thu, 16 Jul 2026 19:45:30 +0200 Subject: [PATCH] feat: configurable email attribute type for the finalize sender check Part 2 of encryption4all/postguard#236 (the cryptify leg). Finalize required exactly pbdf.sidn-pbdf.email.email in the sender's signing identity; test environments cannot issue pbdf credentials, blocking real end-to-end flows. The `email_attribute` config key (default: the production value, so deployed configs are unaffected) now names the attribute type carrying the sender's email. Companion changes: pg-pkg (encryption4all/postguard#244) and pg-js. --- src/config.rs | 32 ++++++++++++++++++++++++++++++++ src/main.rs | 12 +++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/config.rs b/src/config.rs index f3aa9e1..dfa66d3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -18,6 +18,7 @@ pub struct RawCryptifyConfig { staging_mode: Option, metrics_token: Option, usage_db: Option, + email_attribute: Option, } #[derive(Debug, Deserialize)] @@ -43,6 +44,11 @@ pub struct CryptifyConfig { /// (the in-memory map in `Store` is only a cache). `None` keeps usage /// entirely in memory, as it was before persistence was added. usage_db: Option, + /// Attribute type carrying the sender's email in the signing identity + /// (postguard#236). Finalize requires this attribute to be present. + /// Test environments override it with a test-scheme type (e.g. + /// `irma-demo.sidn-pbdf.email.email`); production keeps the default. + email_attribute: String, } impl From for CryptifyConfig { @@ -67,6 +73,9 @@ impl From for CryptifyConfig { staging_mode: config.staging_mode.unwrap_or(false), metrics_token: config.metrics_token, usage_db: config.usage_db, + email_attribute: config + .email_attribute + .unwrap_or_else(|| "pbdf.sidn-pbdf.email.email".to_owned()), } } } @@ -141,6 +150,12 @@ impl CryptifyConfig { self.usage_db.as_deref() } + /// The attribute type carrying the sender's email in the signing + /// identity. Defaults to the production `pbdf.sidn-pbdf.email.email`. + pub fn email_attribute(&self) -> &str { + &self.email_attribute + } + #[cfg(test)] pub(crate) fn for_test(server_url: &str, staging_mode: bool) -> Self { CryptifyConfig { @@ -160,6 +175,7 @@ impl CryptifyConfig { staging_mode, metrics_token: None, usage_db: None, + email_attribute: "pbdf.sidn-pbdf.email.email".to_owned(), } } } @@ -196,4 +212,20 @@ mod tests { .unwrap(); assert_eq!(config.usage_db(), None); } + + #[test] + fn email_attribute_defaults_to_production_type() { + let config: CryptifyConfig = Figment::from(Serialized::defaults(base_config())) + .extract() + .unwrap(); + assert_eq!(config.email_attribute(), "pbdf.sidn-pbdf.email.email"); + } + + #[test] + fn email_attribute_is_overridable() { + let mut raw = base_config(); + raw["email_attribute"] = serde_json::json!("irma-demo.sidn-pbdf.email.email"); + let config: CryptifyConfig = Figment::from(Serialized::defaults(raw)).extract().unwrap(); + assert_eq!(config.email_attribute(), "irma-demo.sidn-pbdf.email.email"); + } } diff --git a/src/main.rs b/src/main.rs index 745d715..81fa501 100644 --- a/src/main.rs +++ b/src/main.rs @@ -933,11 +933,17 @@ async fn upload_finalize( .pub_id .con; + // The attribute type carrying the sender's email is configurable + // (postguard#236): test environments use a test-scheme type since pbdf + // credentials cannot be issued outside production. + let email_attribute = config.email_attribute(); let sender = attributes .iter() - .find(|x| x.atype == "pbdf.sidn-pbdf.email.email") + .find(|x| x.atype == email_attribute) .ok_or_else(|| { - log::error!("finalized upload has no email attribute in postguard metadata"); + log::error!( + "finalized upload has no email attribute ({email_attribute}) in postguard metadata" + ); Error::InternalServerError(Some(GENERIC_INTERNAL_ERROR_MSG.to_owned())) })? .value @@ -945,7 +951,7 @@ async fn upload_finalize( let sender_attributes: Vec<(String, String)> = attributes .into_iter() - .filter(|x| x.atype != "pbdf.sidn-pbdf.email.email") + .filter(|x| x.atype != email_attribute) .filter_map(|x| { let atype = x.atype; x.value.map(|v| (atype, v))