use crate::{utils, Error, PublicKey, Result, XorName};
use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, fmt::Debug, hash::Hash};
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Action {
Read,
Append,
Admin,
}
pub type Entries = Vec<Entry>;
pub type Entry = Vec<u8>;
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, Debug)]
pub enum Address {
Public {
name: XorName,
tag: u64,
},
Private {
name: XorName,
tag: u64,
},
}
impl Address {
pub fn from_kind(kind: Kind, name: XorName, tag: u64) -> Self {
match kind {
Kind::Public => Address::Public { name, tag },
Kind::Private => Address::Private { name, tag },
}
}
pub fn kind(&self) -> Kind {
match self {
Address::Public { .. } => Kind::Public,
Address::Private { .. } => Kind::Private,
}
}
pub fn name(&self) -> &XorName {
match self {
Address::Public { ref name, .. } | Address::Private { ref name, .. } => name,
}
}
pub fn tag(&self) -> u64 {
match self {
Address::Public { tag, .. } | Address::Private { tag, .. } => *tag,
}
}
pub fn is_pub(&self) -> bool {
self.kind().is_pub()
}
pub fn is_private(&self) -> bool {
self.kind().is_private()
}
pub fn encode_to_zbase32(&self) -> Result<String> {
utils::encode(&self)
}
pub fn decode_from_zbase32<I: AsRef<str>>(encoded: I) -> Result<Self> {
utils::decode(encoded)
}
}
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, Debug)]
pub enum Kind {
Public,
Private,
}
impl Kind {
pub fn is_pub(self) -> bool {
self == Kind::Public
}
pub fn is_private(self) -> bool {
!self.is_pub()
}
}
#[derive(Copy, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum Index {
FromStart(u64),
FromEnd(u64),
}
impl From<u64> for Index {
fn from(index: u64) -> Self {
Index::FromStart(index)
}
}
#[derive(Copy, Clone, Serialize, Deserialize, PartialEq, PartialOrd, Ord, Eq, Hash, Debug)]
pub struct PublicPermissions {
append: Option<bool>,
admin: Option<bool>,
}
impl PublicPermissions {
pub fn new(append: impl Into<Option<bool>>, manage_perms: impl Into<Option<bool>>) -> Self {
Self {
append: append.into(),
admin: manage_perms.into(),
}
}
pub fn set_perms(&mut self, append: impl Into<Option<bool>>, admin: impl Into<Option<bool>>) {
self.append = append.into();
self.admin = admin.into();
}
pub fn is_allowed(self, action: Action) -> Option<bool> {
match action {
Action::Read => Some(true),
Action::Append => self.append,
Action::Admin => self.admin,
}
}
}
#[derive(Copy, Clone, Serialize, Deserialize, PartialEq, PartialOrd, Ord, Eq, Hash, Debug)]
pub struct PrivatePermissions {
read: bool,
append: bool,
admin: bool,
}
impl PrivatePermissions {
pub fn new(read: bool, append: bool, manage_perms: bool) -> Self {
Self {
read,
append,
admin: manage_perms,
}
}
pub fn set_perms(&mut self, read: bool, append: bool, manage_perms: bool) {
self.read = read;
self.append = append;
self.admin = manage_perms;
}
pub fn is_allowed(self, action: Action) -> bool {
match action {
Action::Read => self.read,
Action::Append => self.append,
Action::Admin => self.admin,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
pub enum User {
Anyone,
Key(PublicKey),
}
#[derive(Clone, Serialize, Deserialize, PartialEq, PartialOrd, Ord, Eq, Hash, Debug)]
pub struct PublicPolicy {
pub owner: PublicKey,
pub permissions: BTreeMap<User, PublicPermissions>,
}
impl PublicPolicy {
fn is_action_allowed_by_user(&self, user: &User, action: Action) -> Option<bool> {
self.permissions
.get(user)
.and_then(|perms| perms.is_allowed(action))
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, PartialOrd, Ord, Eq, Hash, Debug)]
pub struct PrivatePolicy {
pub owner: PublicKey,
pub permissions: BTreeMap<PublicKey, PrivatePermissions>,
}
pub trait Perm {
fn is_action_allowed(&self, requester: PublicKey, action: Action) -> Result<()>;
fn permissions(&self, user: User) -> Option<Permissions>;
fn owner(&self) -> &PublicKey;
}
impl Perm for PublicPolicy {
fn is_action_allowed(&self, requester: PublicKey, action: Action) -> Result<()> {
if action == Action::Read || requester == self.owner {
Ok(())
} else {
match self
.is_action_allowed_by_user(&User::Key(requester), action)
.or_else(|| self.is_action_allowed_by_user(&User::Anyone, action))
{
Some(true) => Ok(()),
Some(false) => Err(Error::AccessDenied),
None => Err(Error::AccessDenied),
}
}
}
fn permissions(&self, user: User) -> Option<Permissions> {
self.permissions.get(&user).map(|p| Permissions::Public(*p))
}
fn owner(&self) -> &PublicKey {
&self.owner
}
}
impl Perm for PrivatePolicy {
fn is_action_allowed(&self, requester: PublicKey, action: Action) -> Result<()> {
if requester == self.owner {
Ok(())
} else {
match self.permissions.get(&requester) {
Some(perms) => {
if perms.is_allowed(action) {
Ok(())
} else {
Err(Error::AccessDenied)
}
}
None => Err(Error::AccessDenied),
}
}
}
fn permissions(&self, user: User) -> Option<Permissions> {
match user {
User::Anyone => None,
User::Key(key) => self.permissions.get(&key).map(|p| Permissions::Private(*p)),
}
}
fn owner(&self) -> &PublicKey {
&self.owner
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, PartialOrd, Ord, Eq, Hash, Debug)]
pub enum Policy {
Public(PublicPolicy),
Private(PrivatePolicy),
}
impl From<PrivatePolicy> for Policy {
fn from(policy: PrivatePolicy) -> Self {
Policy::Private(policy)
}
}
impl From<PublicPolicy> for Policy {
fn from(policy: PublicPolicy) -> Self {
Policy::Public(policy)
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, PartialOrd, Ord, Eq, Hash, Debug)]
pub enum Permissions {
Public(PublicPermissions),
Private(PrivatePermissions),
}
impl From<PrivatePermissions> for Permissions {
fn from(permission_set: PrivatePermissions) -> Self {
Permissions::Private(permission_set)
}
}
impl From<PublicPermissions> for Permissions {
fn from(permission_set: PublicPermissions) -> Self {
Permissions::Public(permission_set)
}
}