use anyhow::anyhow;
use cid::Cid;
use noosphere_core::context::{
HasSphereContext, SphereAuthorityRead, SphereAuthorityWrite, SphereWalker,
};
use noosphere_core::{
authority::Authorization,
data::{Did, Jwt, Link, Mnemonic},
error::NoosphereError,
};
use safer_ffi::{char_p::InvalidNulTerminator, prelude::*};
use std::ffi::c_void;
use crate::ffi::{NsError, NsNoosphere, NsSphere};
#[ffi_export]
pub fn ns_sphere_authority_authorization_verify(
noosphere: &NsNoosphere,
sphere: &mut NsSphere,
cid: char_p::Ref<'_>,
context: Option<repr_c::Box<c_void>>,
callback: extern "C" fn(Option<repr_c::Box<c_void>>, Option<repr_c::Box<NsError>>),
) {
let sphere = sphere.inner().clone();
let cid = cid.to_string();
noosphere.async_runtime().spawn(async move {
let result = async {
let cid = Cid::try_from(cid.as_str()).map_err(|error| anyhow!(error))?;
let authorization = Authorization::Cid(cid);
sphere.verify_authorization(&authorization).await?;
Ok(()) as Result<_, NoosphereError>
}
.await;
match result {
Ok(_) => tokio::task::spawn_blocking(move || callback(context, None)),
Err(error) => tokio::task::spawn_blocking(move || {
callback(context, Some(NsError::from(error).into()))
}),
};
});
}
#[ffi_export]
pub fn ns_sphere_authority_authorize(
noosphere: &NsNoosphere,
sphere: &mut NsSphere,
name: char_p::Ref<'_>,
did: char_p::Ref<'_>,
context: Option<repr_c::Box<c_void>>,
callback: extern "C" fn(
Option<repr_c::Box<c_void>>,
Option<repr_c::Box<NsError>>,
Option<char_p::Box>,
),
) {
let mut sphere = sphere.inner_mut().clone();
let name = name.to_string();
let did = Did(did.to_string());
noosphere.async_runtime().spawn(async move {
let result = async {
let authorization: char_p::Box = sphere
.authorize(&name, &did)
.await?
.to_string()
.try_into()?;
Ok(authorization) as Result<_, anyhow::Error>
}
.await;
match result {
Ok(authorization) => {
tokio::task::spawn_blocking(move || callback(context, None, Some(authorization)))
}
Err(error) => tokio::task::spawn_blocking(move || {
callback(context, Some(NsError::from(error).into()), None)
}),
};
});
}
#[ffi_export]
pub fn ns_sphere_authority_authorization_revoke(
noosphere: &NsNoosphere,
sphere: &mut NsSphere,
cid: char_p::Ref<'_>,
context: Option<repr_c::Box<c_void>>,
callback: extern "C" fn(Option<repr_c::Box<c_void>>, Option<repr_c::Box<NsError>>),
) {
let mut sphere = sphere.inner_mut().clone();
let cid = cid.to_string();
noosphere.async_runtime().spawn(async move {
let result = async {
let authorization = Authorization::Cid(Cid::try_from(cid.as_str())?);
sphere.revoke_authorization(&authorization).await?;
Ok(()) as Result<_, anyhow::Error>
}
.await;
match result {
Ok(_) => tokio::task::spawn_blocking(move || callback(context, None)),
Err(error) => tokio::task::spawn_blocking(move || {
callback(context, Some(NsError::from(error).into()))
}),
};
});
}
#[ffi_export]
pub fn ns_sphere_authority_authorizations_list(
noosphere: &NsNoosphere,
sphere: &NsSphere,
context: Option<repr_c::Box<c_void>>,
callback: extern "C" fn(
Option<repr_c::Box<c_void>>,
Option<repr_c::Box<NsError>>,
c_slice::Box<char_p::Box>,
),
) {
let sphere = sphere.inner().clone();
noosphere.async_runtime().spawn(async move {
let result = async {
let authorizations = SphereWalker::from(&sphere).list_authorizations().await?;
let mut all_authorizations: Vec<char_p::Box> = Vec::new();
for authorization in authorizations.into_iter() {
all_authorizations.push(
authorization
.to_string()
.try_into()
.map_err(|error: InvalidNulTerminator<String>| anyhow!(error))?,
)
}
Ok(all_authorizations.into_boxed_slice().into())
as Result<c_slice::Box<char_p::Box>, anyhow::Error>
}
.await;
match result {
Ok(authorizations) => {
tokio::task::spawn_blocking(move || callback(context, None, authorizations))
}
Err(error) => tokio::task::spawn_blocking(move || {
callback(
context,
Some(NsError::from(error).into()),
Vec::new().into_boxed_slice().into(),
)
}),
};
});
}
#[ffi_export]
pub fn ns_sphere_authority_authorization_name(
noosphere: &NsNoosphere,
sphere: &NsSphere,
authorization: char_p::Ref<'_>,
context: Option<repr_c::Box<c_void>>,
callback: extern "C" fn(
Option<repr_c::Box<c_void>>,
Option<repr_c::Box<NsError>>,
Option<char_p::Box>,
),
) {
let sphere = sphere.inner().clone();
let authorization = authorization.to_string();
noosphere.async_runtime().spawn(async move {
let result = async {
let link = Link::<Jwt>::from(Cid::try_from(authorization)?);
let name: char_p::Box = sphere
.to_sphere()
.await?
.get_authority()
.await?
.get_delegations()
.await?
.require(&link)
.await?
.name
.clone()
.try_into()?;
Ok(name) as Result<_, anyhow::Error>
}
.await;
match result {
Ok(name) => tokio::task::spawn_blocking(move || callback(context, None, Some(name))),
Err(error) => tokio::task::spawn_blocking(move || {
callback(context, Some(NsError::from(error).into()), None)
}),
};
});
}
#[ffi_export]
pub fn ns_sphere_authority_authorization_identity(
noosphere: &NsNoosphere,
sphere: &NsSphere,
authorization: char_p::Ref<'_>,
context: Option<repr_c::Box<c_void>>,
callback: extern "C" fn(
Option<repr_c::Box<c_void>>,
Option<repr_c::Box<NsError>>,
Option<char_p::Box>,
),
) {
let sphere = sphere.inner().clone();
let authorization = authorization.to_string();
noosphere.async_runtime().spawn(async move {
let result = async {
let link = Link::<Jwt>::from(Cid::try_from(authorization)?);
let ucan = Authorization::Cid(link.into())
.as_ucan(sphere.sphere_context().await?.db())
.await?;
let identity: char_p::Box = ucan.audience().to_string().try_into()?;
Ok(identity) as Result<_, anyhow::Error>
}
.await;
match result {
Ok(identity) => {
tokio::task::spawn_blocking(move || callback(context, None, Some(identity)))
}
Err(error) => tokio::task::spawn_blocking(move || {
callback(context, Some(NsError::from(error).into()), None)
}),
};
});
}
#[ffi_export]
#[allow(clippy::type_complexity)]
pub fn ns_sphere_authority_escalate(
noosphere: &NsNoosphere,
sphere: &mut NsSphere,
mnemonic: char_p::Ref<'_>,
context: Option<repr_c::Box<c_void>>,
callback: extern "C" fn(
Option<repr_c::Box<c_void>>,
Option<repr_c::Box<NsError>>,
Option<repr_c::Box<NsSphere>>,
),
) {
let sphere = sphere.inner().clone();
let mnemonic = Mnemonic(mnemonic.to_string());
noosphere.async_runtime().spawn(async move {
let result = async {
let root_sphere_context = sphere.escalate_authority(&mnemonic).await?;
Ok(Box::new(NsSphere {
inner: root_sphere_context.into(),
})
.into()) as Result<repr_c::Box<NsSphere>, anyhow::Error>
}
.await;
match result {
Ok(sphere) => {
tokio::task::spawn_blocking(move || callback(context, None, Some(sphere)))
}
Err(error) => tokio::task::spawn_blocking(move || {
callback(context, Some(NsError::from(error).into()), None)
}),
};
});
}