use std::fmt::Debug;
use cosmwasm_std::{Addr, Deps, Env};
use crate::error::{NeptAuthError, NeptAuthResult};
#[derive(Clone, Debug)]
pub enum PermissionGroup {
Public,
Restricted(Vec<Addr>),
}
impl From<Vec<Addr>> for PermissionGroup {
fn from(vec: Vec<Addr>) -> Self { Self::Restricted(vec) }
}
pub type PermissionGroupList<'a> = Vec<&'a dyn GetPermissionGroup>;
pub trait NeptuneAuth {
fn permissions(&self) -> NeptAuthResult<PermissionGroupList>;
fn neptune_authorize(&self, deps: Deps, env: &Env, address: &Addr) -> NeptAuthResult<()> {
let permissions = self.permissions()?;
authorize_permissions(deps, env, address, &permissions)
}
}
pub trait GetPermissionGroup: Debug {
fn get_permission_group(&self, deps: Deps, env: &Env) -> NeptAuthResult<PermissionGroup>;
}
#[derive(Clone, Debug)]
pub enum BasePermissionGroups {
Internal,
Public,
}
impl GetPermissionGroup for BasePermissionGroups {
fn get_permission_group(&self, _deps: Deps, env: &Env) -> NeptAuthResult<PermissionGroup> {
Ok(match self {
Self::Internal => PermissionGroup::Restricted(vec![env.contract.address.clone()]),
Self::Public => PermissionGroup::Public,
})
}
}
pub fn authorize_permissions(
deps: Deps, env: &Env, addr: &Addr, permissions: &PermissionGroupList,
) -> NeptAuthResult<()> {
let collected_permissions =
permissions.iter().map(|x| x.get_permission_group(deps, env)).collect::<Result<Vec<_>, _>>()?;
let flattened = flatten_permissions(collected_permissions)?;
match flattened {
PermissionGroup::Public => Ok(()),
PermissionGroup::Restricted(vec) => {
if vec.contains(addr) {
Ok(())
} else {
Err(NeptAuthError::Unauthorized {
sender: addr.clone(),
permission_group: format!("{permissions:?}"),
})
}
}
}
}
fn flatten_permissions(permission_group_vec: Vec<PermissionGroup>) -> NeptAuthResult<PermissionGroup> {
if permission_group_vec.is_empty() {
Err(NeptAuthError::EmptyPermissionGroupList)
} else if permission_group_vec.len() == 1 {
Ok(permission_group_vec[0].clone())
} else {
let mut result_vec: Vec<Addr> = vec![];
for permission_group in permission_group_vec {
match permission_group {
PermissionGroup::Public => return Err(NeptAuthError::InvalidPublic),
PermissionGroup::Restricted(vec) => result_vec = [result_vec, vec].concat(),
}
}
return Ok(PermissionGroup::Restricted(result_vec));
}
}