durable-actors 0.6.0

Standalone regional durable-actors control plane, host, and durability runtime
Documentation
use anyhow::{Context, Result, ensure};
use aws_lc_rs::hmac;
use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
use subtle::ConstantTimeEq;

#[derive(Clone)]
pub(crate) struct Access {
    secret: String,
}
impl Access {
    pub fn new(secret: String) -> Result<Self> {
        ensure!(
            secret.len() >= 32,
            "replica secret must contain at least 32 bytes"
        );
        Ok(Self { secret })
    }
    pub fn admin(&self) -> &str {
        &self.secret
    }
    pub fn scoped(&self, actor: &crate::actor::ActorKey) -> Result<String> {
        let prefix = crate::storage_paths::snapshots(actor)?;
        let payload = URL_SAFE_NO_PAD.encode(prefix);
        let signature = hmac::sign(
            &hmac::Key::new(hmac::HMAC_SHA256, self.secret.as_bytes()),
            payload.as_bytes(),
        );
        Ok(format!(
            "{payload}.{}",
            URL_SAFE_NO_PAD.encode(signature.as_ref())
        ))
    }
    pub fn authorize(&self, token: &str, scope: Option<&str>) -> Result<()> {
        if bool::from(token.as_bytes().ct_eq(self.secret.as_bytes())) {
            return Ok(());
        }
        let scope = scope.context("replica administration requires the server credential")?;
        let (payload, signature) = token
            .split_once('.')
            .context("invalid replica capability")?;
        hmac::verify(
            &hmac::Key::new(hmac::HMAC_SHA256, self.secret.as_bytes()),
            payload.as_bytes(),
            &URL_SAFE_NO_PAD.decode(signature)?,
        )
        .map_err(|_| anyhow::anyhow!("invalid replica capability"))?;
        let prefix = String::from_utf8(URL_SAFE_NO_PAD.decode(payload)?)?;
        ensure!(
            scope.starts_with(&prefix),
            "replica capability belongs to another actor"
        );
        Ok(())
    }
}