use std::time::{SystemTime, UNIX_EPOCH};
use graphshell::admission::{CONNECT_ACTION, GRAPHSHELL_DOMAIN, PROJECTION_SERVICE};
use notochord::{NetworkId, ProfileRef};
use personae::delegation::{
CapabilityScope, DelegationCertificate, DelegationParent, SignedDelegationCertificate,
};
use personae::{IdentityProvider, InMemoryProvider};
use transport::Transport;
use transport::p2panda_transport::P2pandaTransport;
use crate::ROOT_AUTHORITY;
pub(crate) fn env_hash(var: &str) -> Result<[u8; 32], String> {
let value = std::env::var(var).map_err(|_| format!("set {var} (any string)"))?;
Ok(*blake3::hash(value.as_bytes()).as_bytes())
}
pub(crate) fn now_ms() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("clock is after the epoch")
.as_millis() as u64
}
pub(crate) fn profile() -> ProfileRef {
ProfileRef {
id: "mere.base".into(),
revision: 1,
}
}
pub(crate) fn grant(
owner: &InMemoryProvider,
subject: [u8; 32],
network: NetworkId,
expires_at_ms: u64,
) -> SignedDelegationCertificate {
SignedDelegationCertificate::issue(
owner,
DelegationCertificate::new(
DelegationParent::Root(ROOT_AUTHORITY),
owner.master_public_key().to_bytes(),
subject,
CapabilityScope {
domain: GRAPHSHELL_DOMAIN.into(),
resource: network.0.to_vec(),
path_prefix: PROJECTION_SERVICE.into(),
actions: [CONNECT_ACTION.to_string()].into_iter().collect(),
},
now_ms().saturating_sub(60_000),
now_ms().saturating_sub(60_000),
Some(expires_at_ms),
1,
[11; 32],
),
)
.expect("issue certificate")
}
pub(crate) fn assert_same_key(
carrier: &P2pandaTransport,
me: &InMemoryProvider,
) -> Result<(), String> {
let carried = carrier.local_peer_id().to_bytes();
let claimed = me.master_public_key().to_bytes();
if carried != claimed {
return Err(format!(
"carrier identity {} is not the Personae identity {}; seed both from the same bytes",
hex8(&carried),
hex8(&claimed)
));
}
Ok(())
}
pub(crate) fn hex8(bytes: &[u8; 32]) -> String {
bytes.iter().take(4).map(|b| format!("{b:02x}")).collect()
}