use super::{DataId, Vault};
use safe_nd::{
Data, Error as SndError, PublicId, PublicKey, Response, Result as SndResult, SData,
SDataAction, SDataAddress, SDataRequest,
};
impl Vault {
pub(crate) fn process_sdata_req(
&mut self,
request: &SDataRequest,
requester: PublicId,
requester_pk: PublicKey,
owner_pk: PublicKey,
) -> Response {
match request {
SDataRequest::Store(sdata) => {
let owner_index = sdata.owners_index();
let address = *sdata.address();
let result = match sdata.owner(owner_index - 1) {
Some(key) => {
if key.public_key != owner_pk {
Err(SndError::InvalidOwners)
} else {
self.put_data(
DataId::Sequence(address),
Data::Sequence(sdata.clone()),
requester,
)
}
}
None => Err(SndError::NoSuchEntry),
};
Response::Mutation(result)
}
SDataRequest::Get(address) => {
let result = self.get_sdata(*address, requester_pk, &request);
Response::GetSData(result)
}
SDataRequest::Delete(address) => {
let id = DataId::Sequence(*address);
let result = self.get_sdata(*address, requester_pk, &request).and_then(
move |data| match data {
SData::Public(_) => Err(SndError::InvalidOperation),
SData::Private(_) => {
self.delete_data(id);
Ok(())
}
},
);
Response::Mutation(result)
}
SDataRequest::GetRange { address, range } => {
let result =
self.get_sdata(*address, requester_pk, &request)
.and_then(move |data| {
data.in_range(range.0, range.1).ok_or(SndError::NoSuchEntry)
});
Response::GetSDataRange(result)
}
SDataRequest::GetLastEntry(address) => {
let result =
self.get_sdata(*address, requester_pk, &request)
.and_then(move |data| {
let entry = data.last_entry().cloned().ok_or(SndError::NoSuchEntry)?;
Ok((data.entries_index() - 1, entry))
});
Response::GetSDataLastEntry(result)
}
SDataRequest::GetPermissions(address) => {
let data = self.get_sdata(*address, requester_pk, &request);
match (address.kind(), data) {
(kind, Ok(ref data)) if kind.is_pub() && data.is_pub() => {
Response::GetSDataPermissions(
data.pub_permissions(data.permissions_index())
.map(|perm| perm.clone().into()),
)
}
(kind, Ok(ref data)) if kind.is_priv() && data.is_priv() => {
Response::GetSDataPermissions(
data.priv_permissions(data.permissions_index())
.map(|perm| perm.clone().into()),
)
}
(_, Err(err)) => Response::GetSDataPermissions(Err(err)),
(_, Ok(_)) => Response::GetSDataPermissions(Err(SndError::NoSuchData)),
}
}
SDataRequest::GetUserPermissions { address, user } => {
let result = self
.get_sdata(*address, requester_pk, &request)
.and_then(move |data| data.user_permissions(*user, data.permissions_index()));
Response::GetSDataUserPermissions(result)
}
SDataRequest::Mutate(op) => {
let id = DataId::Sequence(op.address);
let result =
self.get_sdata(op.address, requester_pk, &request)
.map(move |mut sdata| {
sdata.apply_crdt_op(op.crdt_op.clone());
self.commit_mutation(requester.name());
self.insert_data(id, Data::Sequence(sdata));
});
Response::Mutation(result)
}
SDataRequest::MutatePubPermissions(op) => {
let id = DataId::Sequence(op.address);
let result = self.get_sdata(op.address, requester_pk, &request).and_then(
move |mut sdata| {
sdata.apply_crdt_pub_perms_op(op.crdt_op.clone())?;
self.commit_mutation(requester.name());
self.insert_data(id, Data::Sequence(sdata));
Ok(())
},
);
Response::Mutation(result)
}
SDataRequest::MutatePrivPermissions(op) => {
let id = DataId::Sequence(op.address);
let result = self.get_sdata(op.address, requester_pk, &request).and_then(
move |mut sdata| {
sdata.apply_crdt_priv_perms_op(op.crdt_op.clone())?;
self.commit_mutation(requester.name());
self.insert_data(id, Data::Sequence(sdata));
Ok(())
},
);
Response::Mutation(result)
}
SDataRequest::MutateOwner(op) => {
let id = DataId::Sequence(op.address);
let result =
self.get_sdata(op.address, requester_pk, &request)
.map(move |mut sdata| {
sdata.apply_crdt_owner_op(op.crdt_op.clone());
self.commit_mutation(requester.name());
self.insert_data(id, Data::Sequence(sdata));
});
Response::Mutation(result)
}
SDataRequest::GetOwner(address) => {
let result =
self.get_sdata(*address, requester_pk, &request)
.and_then(move |sdata| match sdata.owner(sdata.owners_index()) {
Some(owner) => Ok(*owner),
None => Err(SndError::NoSuchEntry),
});
Response::GetSDataOwner(result)
}
}
}
pub fn get_sdata(
&mut self,
address: SDataAddress,
requester_pk: PublicKey,
request: &SDataRequest,
) -> SndResult<SData> {
let data_id = DataId::Sequence(address);
match self.get_data(&data_id) {
Some(Data::Sequence(sdata)) => {
check_perms_sdata(&sdata, request, requester_pk).map(move |_| sdata)
}
Some(_) | None => Err(SndError::NoSuchData),
}
}
}
fn check_perms_sdata(sdata: &SData, request: &SDataRequest, requester: PublicKey) -> SndResult<()> {
match request {
SDataRequest::Get(..)
| SDataRequest::GetRange { .. }
| SDataRequest::GetLastEntry(..)
| SDataRequest::GetPermissions { .. }
| SDataRequest::GetUserPermissions { .. }
| SDataRequest::GetOwner { .. } => match sdata {
SData::Public(_) => Ok(()),
SData::Private(_) => sdata.check_permission(SDataAction::Read, requester),
},
SDataRequest::Mutate { .. } => sdata.check_permission(SDataAction::Append, requester),
SDataRequest::MutatePubPermissions(_) | SDataRequest::MutatePrivPermissions(_) => {
sdata.check_permission(SDataAction::ManagePermissions, requester)
}
SDataRequest::MutateOwner(_) => sdata.check_is_last_owner(requester),
SDataRequest::Delete(_) => match sdata {
SData::Public(_) => Err(SndError::InvalidOperation),
SData::Private(_) => sdata.check_is_last_owner(requester),
},
SDataRequest::Store { .. } => Err(SndError::InvalidOperation),
}
}