use pubky_common::auth::{grant_session_responses::GrantInfo, jws::GrantId};
use pubky_common::crypto::PublicKey;
use reqwest::Method;
use std::sync::Arc;
use crate::actors::session::credential::SessionCredential;
use crate::actors::storage::resource::resolve_pubky;
use crate::errors::{RequestError, Result};
use crate::util::check_http_status;
use crate::{PubkyHttpClient, PubkySession};
#[derive(Debug, Clone)]
pub struct GrantManager {
client: PubkyHttpClient,
user: PublicKey,
credential: Arc<dyn SessionCredential>,
}
impl GrantManager {
#[must_use]
pub fn new(session: &PubkySession) -> Self {
Self {
client: session.client().clone(),
user: session.info().public_key().clone(),
credential: Arc::clone(session.credential()),
}
}
pub async fn list(&self) -> Result<Vec<GrantInfo>> {
let url = format!("pubky://{}/auth/grant/sessions", self.user.z32());
let resolved = resolve_pubky(&url)?;
let rb = self.client.cross_request(Method::GET, resolved).await?;
let resp = self
.credential
.attach(rb, &self.client)
.await?
.send()
.await?;
let resp = check_http_status(resp).await?;
let grants: Vec<GrantInfo> = resp.json().await.map_err(|e| RequestError::DecodeJson {
message: format!("decoding /auth/grant/sessions response: {e}"),
})?;
Ok(grants)
}
pub async fn revoke(&self, grant_id: &GrantId) -> Result<()> {
let url = format!(
"pubky://{}/auth/grant/session/{}",
self.user.z32(),
grant_id.as_str()
);
let resolved = resolve_pubky(&url)?;
let rb = self.client.cross_request(Method::DELETE, resolved).await?;
let resp = self
.credential
.attach(rb, &self.client)
.await?
.send()
.await?;
check_http_status(resp).await?;
Ok(())
}
}