haematite-cli 0.21.3

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
use super::Issuer;
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
use serde::Deserialize;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

pub(super) struct Cached {
    token: String,
    renew_at: tokio::time::Instant,
}
impl Cached {
    pub fn new(token: String) -> anyhow::Result<Self> {
        #[derive(Deserialize)]
        struct Expiry {
            exp: u64,
        }
        let payload = token
            .split('.')
            .nth(1)
            .ok_or_else(|| anyhow::anyhow!("permission_watch_pass_invalid"))?;
        let bytes = URL_SAFE_NO_PAD
            .decode(payload)
            .map_err(|_| anyhow::anyhow!("permission_watch_pass_invalid"))?;
        let expiry: Expiry = serde_json::from_slice(&bytes)
            .map_err(|_| anyhow::anyhow!("permission_watch_pass_invalid"))?;
        let remaining = expiry.exp.saturating_sub(now()?).saturating_sub(60);
        let renew_at = tokio::time::Instant::now()
            .checked_add(Duration::from_secs(remaining))
            .ok_or_else(|| anyhow::anyhow!("permission_watch_expiry_invalid"))?;
        Ok(Self { token, renew_at })
    }
}
fn now() -> anyhow::Result<u64> {
    Ok(SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs())
}
impl Issuer {
    pub(in crate::assistant) async fn watch_deadline(&self) -> tokio::time::Instant {
        self.watch_pass.lock().await.renew_at
    }
    pub(in crate::assistant) async fn watch_credentials(&self) -> anyhow::Result<String> {
        let mut cached = self.watch_pass.lock().await;
        if cached.renew_at <= tokio::time::Instant::now() {
            let response = self
                .http
                .post(format!("{}/api/agents/{}/pass", self.origin, self.agent))
                .headers(crate::assistant::tools::proof_headers(&self.launch)?)
                .json(&serde_json::json!({"audience":"haematite"}))
                .send()
                .await
                .map_err(|_| anyhow::anyhow!("permission_watch_renewal_unreachable"))?;
            let value = self.json(response).await?;
            let current = now()?;
            anyhow::ensure!(
                value["audience"] == "haematite"
                    && value["expires_at"]
                        .as_u64()
                        .is_some_and(|expiry| expiry > current.saturating_add(60)),
                "permission_watch_renewal_invalid"
            );
            let token = value["pass"]
                .as_str()
                .filter(|token| !token.is_empty())
                .ok_or_else(|| anyhow::anyhow!("permission_watch_renewal_invalid"))?;
            let renewed = Cached::new(token.to_owned())?;
            anyhow::ensure!(
                renewed.renew_at > tokio::time::Instant::now(),
                "permission_watch_renewal_expiry_invalid"
            );
            *cached = renewed;
        }
        Ok(cached.token.clone())
    }
}