use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use dpp_domain::{AccessTier, SectorCatalog};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SectorAccessPolicy {
pub name: String,
pub sector: String,
pub field_tiers: HashMap<String, AccessTier>,
#[serde(default = "tier_public")]
pub default_tier: AccessTier,
}
fn tier_public() -> AccessTier {
AccessTier::Public
}
pub(super) fn normalize_key(key: &str) -> String {
key.chars()
.filter(|c| c.is_ascii_alphanumeric())
.map(|c| c.to_ascii_lowercase())
.collect()
}
const COMMON_CONFIDENTIAL: &[&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_tiers: HashMap<String, AccessTier> = descriptor.access_tiers.clone();
for field in COMMON_CONFIDENTIAL {
field_tiers
.entry((*field).to_owned())
.or_insert(AccessTier::Confidential);
}
Some(Self {
name: format!("{sector_key}-{}", descriptor.current_schema_version),
sector: sector_key.to_owned(),
field_tiers,
default_tier: AccessTier::Public,
})
}
pub fn passport_default() -> Self {
let mut field_tiers = HashMap::new();
field_tiers.insert("batchId".into(), AccessTier::Professional);
field_tiers.insert("jwsSignature".into(), AccessTier::Confidential);
field_tiers.insert("retentionLocked".into(), AccessTier::Confidential);
Self {
name: "passport-v1.0".into(),
sector: "passport".into(),
field_tiers,
default_tier: AccessTier::Public,
}
}
pub fn tier_for_field(&self, field_name: &str) -> AccessTier {
let target = normalize_key(field_name);
self.field_tiers
.iter()
.find(|(k, _)| normalize_key(k) == target)
.map(|(_, t)| *t)
.unwrap_or(self.default_tier)
}
}