use super::{DataId, Vault};
use safe_nd::{
AData, ADataAction, ADataAddress, ADataIndex, ADataRequest, AppendOnlyData, Data,
Error as SndError, PublicId, PublicKey, Response, Result as SndResult, SeqAppendOnly,
UnseqAppendOnly,
};
impl Vault {
pub(crate) fn process_adata_req(
&mut self,
request: &ADataRequest,
requester: PublicId,
requester_pk: PublicKey,
owner_pk: PublicKey,
) -> Response {
match request {
ADataRequest::Put(adata) => {
let owner_index = adata.owners_index();
let address = *adata.address();
let result = match adata.owner(owner_index - 1) {
Some(key) => {
if key.public_key != owner_pk {
Err(SndError::InvalidOwners)
} else {
self.put_data(
DataId::AppendOnly(address),
Data::AppendOnly(adata.clone()),
requester,
)
}
}
None => Err(SndError::NoSuchEntry),
};
Response::Mutation(result)
}
ADataRequest::Get(address) => {
let result = self.get_adata(*address, requester_pk, &request);
Response::GetAData(result)
}
ADataRequest::Delete(address) => {
let id = DataId::AppendOnly(*address);
let result = self.get_adata(*address, requester_pk, &request).and_then(
move |data| match data {
AData::PubSeq(_) | AData::PubUnseq(_) => Err(SndError::InvalidOperation),
AData::UnpubSeq(_) | AData::UnpubUnseq(_) => {
self.delete_data(id);
Ok(())
}
},
);
Response::Mutation(result)
}
ADataRequest::GetShell {
address,
data_index,
} => {
let result =
self.get_adata(*address, requester_pk, &request)
.and_then(move |data| {
let index = match data_index {
ADataIndex::FromStart(index) => *index,
ADataIndex::FromEnd(index) => (data.permissions_index() - index),
};
data.shell(index)
});
Response::GetADataShell(result)
}
ADataRequest::GetRange { address, range } => {
let result =
self.get_adata(*address, requester_pk, &request)
.and_then(move |data| {
data.in_range(range.0, range.1).ok_or(SndError::NoSuchEntry)
});
Response::GetADataRange(result)
}
ADataRequest::GetValue { address, ref key } => {
let result = self
.get_adata(*address, requester_pk, &request)
.and_then(move |data| data.get(key).cloned().ok_or(SndError::NoSuchEntry));
Response::GetADataValue(result)
}
ADataRequest::GetIndices(address) => {
let result = self
.get_adata(*address, requester_pk, &request)
.and_then(move |data| data.indices());
Response::GetADataIndices(result)
}
ADataRequest::GetLastEntry(address) => {
let result = self
.get_adata(*address, requester_pk, &request)
.and_then(move |data| data.last_entry().cloned().ok_or(SndError::NoSuchEntry));
Response::GetADataLastEntry(result)
}
ADataRequest::GetPermissions {
address,
permissions_index,
} => {
let data = self.get_adata(*address, requester_pk, &request);
match (address.kind(), data) {
(kind, Ok(ref data)) if kind.is_pub() && data.is_pub() => {
Response::GetADataPermissions(
data.pub_permissions(*permissions_index)
.map(|perm| perm.clone().into()),
)
}
(kind, Ok(ref data)) if kind.is_unpub() && data.is_unpub() => {
Response::GetADataPermissions(
data.unpub_permissions(*permissions_index)
.map(|perm| perm.clone().into()),
)
}
(_, Err(err)) => Response::GetADataPermissions(Err(err)),
(_, Ok(_)) => Response::GetADataPermissions(Err(SndError::NoSuchData)),
}
}
ADataRequest::GetPubUserPermissions {
address,
permissions_index,
user,
} => {
let result = self
.get_adata(*address, requester_pk, &request)
.and_then(move |data| data.pub_user_permissions(*user, *permissions_index));
Response::GetPubADataUserPermissions(result)
}
ADataRequest::GetUnpubUserPermissions {
address,
permissions_index,
public_key,
} => {
let result =
self.get_adata(*address, requester_pk, &request)
.and_then(move |data| {
data.unpub_user_permissions(*public_key, *permissions_index)
});
Response::GetUnpubADataUserPermissions(result)
}
ADataRequest::AppendSeq { append, index } => {
let id = DataId::AppendOnly(append.address);
let result = self
.get_adata(append.address, requester_pk, &request)
.and_then(move |data| match data {
AData::PubSeq(mut adata) => {
adata.append(append.values.clone(), *index)?;
self.commit_mutation(requester.name());
self.insert_data(id, Data::AppendOnly(AData::PubSeq(adata)));
Ok(())
}
AData::UnpubSeq(mut adata) => {
adata.append(append.values.clone(), *index)?;
self.commit_mutation(requester.name());
self.insert_data(id, Data::AppendOnly(AData::UnpubSeq(adata)));
Ok(())
}
_ => Err(SndError::NoSuchData),
});
Response::Mutation(result)
}
ADataRequest::AppendUnseq(append) => {
let id = DataId::AppendOnly(append.address);
let result = self
.get_adata(append.address, requester_pk, &request)
.and_then(move |data| match data {
AData::PubUnseq(mut adata) => {
adata.append(append.values.clone())?;
self.commit_mutation(requester.name());
self.insert_data(id, Data::AppendOnly(AData::PubUnseq(adata)));
Ok(())
}
AData::UnpubUnseq(mut adata) => {
adata.append(append.values.clone())?;
self.commit_mutation(requester.name());
self.insert_data(id, Data::AppendOnly(AData::UnpubUnseq(adata)));
Ok(())
}
_ => Err(SndError::NoSuchData),
});
Response::Mutation(result)
}
ADataRequest::AddPubPermissions {
address,
permissions,
permissions_index,
} => {
let id = DataId::AppendOnly(*address);
let result =
self.get_adata(*address, requester_pk, &request)
.and_then(move |data| match address {
ADataAddress::PubSeq { .. } => match data {
AData::PubSeq(mut adata) => {
adata.append_permissions(
permissions.clone(),
*permissions_index,
)?;
self.commit_mutation(requester.name());
self.insert_data(id, Data::AppendOnly(AData::PubSeq(adata)));
Ok(())
}
_ => Err(SndError::NoSuchData),
},
ADataAddress::PubUnseq { .. } => match data {
AData::PubUnseq(mut adata) => {
adata.append_permissions(
permissions.clone(),
*permissions_index,
)?;
self.commit_mutation(requester.name());
self.insert_data(id, Data::AppendOnly(AData::PubUnseq(adata)));
Ok(())
}
_ => Err(SndError::NoSuchData),
},
_ => Err(SndError::AccessDenied),
});
Response::Mutation(result)
}
ADataRequest::AddUnpubPermissions {
address,
permissions,
permissions_index,
} => {
let id = DataId::AppendOnly(*address);
let result = self
.get_adata(*address, requester_pk, &request)
.and_then(|data| match address {
ADataAddress::UnpubSeq { .. } => match data.clone() {
AData::UnpubSeq(mut adata) => {
adata
.append_permissions(permissions.clone(), *permissions_index)?;
self.commit_mutation(requester.name());
self.insert_data(id, Data::AppendOnly(AData::UnpubSeq(adata)));
Ok(())
}
_ => Err(SndError::NoSuchData),
},
ADataAddress::UnpubUnseq { .. } => match data {
AData::UnpubUnseq(mut adata) => {
adata
.append_permissions(permissions.clone(), *permissions_index)?;
self.commit_mutation(requester.name());
self.insert_data(id, Data::AppendOnly(AData::UnpubUnseq(adata)));
Ok(())
}
_ => Err(SndError::NoSuchData),
},
_ => Err(SndError::AccessDenied),
});
Response::Mutation(result)
}
ADataRequest::SetOwner {
address,
owner,
owners_index,
} => {
let id = DataId::AppendOnly(*address);
let result =
self.get_adata(*address, requester_pk, &request)
.and_then(move |data| match address {
ADataAddress::PubSeq { .. } => match data {
AData::PubSeq(mut adata) => {
adata.append_owner(*owner, *owners_index)?;
self.commit_mutation(requester.name());
self.insert_data(id, Data::AppendOnly(AData::PubSeq(adata)));
Ok(())
}
_ => Err(SndError::NoSuchData),
},
ADataAddress::PubUnseq { .. } => match data {
AData::PubUnseq(mut adata) => {
adata.append_owner(*owner, *owners_index)?;
self.commit_mutation(requester.name());
self.insert_data(id, Data::AppendOnly(AData::PubUnseq(adata)));
Ok(())
}
_ => Err(SndError::NoSuchData),
},
ADataAddress::UnpubSeq { .. } => match data.clone() {
AData::UnpubSeq(mut adata) => {
adata.append_owner(*owner, *owners_index)?;
self.commit_mutation(requester.name());
self.insert_data(id, Data::AppendOnly(AData::UnpubSeq(adata)));
Ok(())
}
_ => Err(SndError::NoSuchData),
},
ADataAddress::UnpubUnseq { .. } => match data {
AData::UnpubUnseq(mut adata) => {
adata.append_owner(*owner, *owners_index)?;
self.commit_mutation(requester.name());
self.insert_data(
id,
Data::AppendOnly(AData::UnpubUnseq(adata)),
);
Ok(())
}
_ => Err(SndError::NoSuchData),
},
});
Response::Mutation(result)
}
ADataRequest::GetOwners {
address,
owners_index,
} => {
let result =
self.get_adata(*address, requester_pk, &request)
.and_then(move |data| {
let index = match owners_index {
ADataIndex::FromStart(index) => *index,
ADataIndex::FromEnd(index) => (data.owners_index() - index),
};
match data.owner(index) {
Some(owner) => Ok(*owner),
None => Err(SndError::NoSuchEntry),
}
});
Response::GetADataOwners(result)
}
}
}
pub fn get_adata(
&mut self,
address: ADataAddress,
requester_pk: PublicKey,
request: &ADataRequest,
) -> SndResult<AData> {
let data_id = DataId::AppendOnly(address);
match self.get_data(&data_id) {
Some(data_type) => match data_type {
Data::AppendOnly(data) => {
check_perms_adata(&data, request, requester_pk).map(move |_| data)
}
_ => Err(SndError::NoSuchData),
},
None => Err(SndError::NoSuchData),
}
}
}
fn check_perms_adata(data: &AData, request: &ADataRequest, requester: PublicKey) -> SndResult<()> {
match request {
ADataRequest::Get(..)
| ADataRequest::GetShell { .. }
| ADataRequest::GetValue { .. }
| ADataRequest::GetRange { .. }
| ADataRequest::GetIndices(..)
| ADataRequest::GetLastEntry(..)
| ADataRequest::GetPermissions { .. }
| ADataRequest::GetPubUserPermissions { .. }
| ADataRequest::GetUnpubUserPermissions { .. }
| ADataRequest::GetOwners { .. } => match data {
AData::PubUnseq(_) | AData::PubSeq(_) => Ok(()),
AData::UnpubSeq(_) | AData::UnpubUnseq(_) => {
data.check_permission(ADataAction::Read, requester)
}
},
ADataRequest::AppendSeq { .. } | ADataRequest::AppendUnseq { .. } => {
data.check_permission(ADataAction::Append, requester)
}
ADataRequest::AddPubPermissions { .. } | ADataRequest::AddUnpubPermissions { .. } => {
data.check_permission(ADataAction::ManagePermissions, requester)
}
ADataRequest::SetOwner { .. } => data.check_is_last_owner(requester),
ADataRequest::Delete(_) => match data {
AData::PubSeq(_) | AData::PubUnseq(_) => Err(SndError::InvalidOperation),
AData::UnpubSeq(_) | AData::UnpubUnseq(_) => data.check_is_last_owner(requester),
},
ADataRequest::Put { .. } => Err(SndError::InvalidOperation),
}
}