use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::{Disclosure, PASSPORT_FIELD_DISCLOSURE, SectorCatalog};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SectorAccessPolicy {
pub name: String,
pub sector: String,
pub field_disclosure: HashMap<String, Disclosure>,
#[serde(default = "disclosure_public")]
pub default_disclosure: Disclosure,
}
fn disclosure_public() -> Disclosure {
Disclosure::Public
}
fn keys_match_normalized(a: &str, b: &str) -> bool {
let mut a_chars = a.chars().filter(char::is_ascii_alphanumeric);
let mut b_chars = b.chars().filter(char::is_ascii_alphanumeric);
loop {
match (a_chars.next(), b_chars.next()) {
(Some(x), Some(y)) if x.eq_ignore_ascii_case(&y) => {}
(None, None) => return true,
_ => return false,
}
}
}
const COMMON_CONFORMITY: &[&str] = &[
"jwsSignature",
"complianceReport",
"auditHistory",
"supplyChainTrace",
];
impl SectorAccessPolicy {
pub fn from_catalog(catalog: &SectorCatalog, sector_key: &str) -> Option<Self> {
let descriptor = catalog.get(sector_key)?;
let mut field_disclosure: HashMap<String, Disclosure> = descriptor.disclosure.clone();
for field in COMMON_CONFORMITY {
field_disclosure
.entry((*field).to_owned())
.or_insert(Disclosure::Conformity);
}
Some(Self {
name: format!("{sector_key}-{}", descriptor.current_schema_version),
sector: sector_key.to_owned(),
field_disclosure,
default_disclosure: Disclosure::Public,
})
}
pub fn passport_default() -> Self {
let mut field_disclosure = HashMap::new();
for (field, class) in PASSPORT_FIELD_DISCLOSURE {
field_disclosure.insert((*field).to_owned(), *class);
}
Self {
name: "passport-v1.0".into(),
sector: "passport".into(),
field_disclosure,
default_disclosure: Disclosure::Public,
}
}
pub fn disclosure_for_field(&self, field_name: &str) -> Disclosure {
self.field_disclosure
.iter()
.find(|(k, _)| keys_match_normalized(k, field_name))
.map(|(_, d)| *d)
.unwrap_or(self.default_disclosure)
}
}