use {AuthError, AuthFuture};
use access_container;
use futures::Future;
use routing::{Action, EntryActions, PermissionSet, User};
use rust_sodium::crypto::sign;
use safe_core::{Client, DIR_TAG, FutureExt, MDataInfo, app_container_name, nfs};
#[cfg(test)]
pub fn fetch(client: &Client<()>, app_id: &str) -> Box<AuthFuture<Option<MDataInfo>>> {
let app_cont_name = app_container_name(app_id);
access_container::fetch_authenticator_entry(client)
.and_then(move |(_, mut ac_entries)| {
Ok(ac_entries.remove(&app_cont_name))
})
.into_box()
}
pub fn fetch_or_create(
client: &Client<()>,
app_id: &str,
app_sign_pk: sign::PublicKey,
) -> Box<AuthFuture<MDataInfo>> {
let c2 = client.clone();
let c3 = client.clone();
let app_cont_name = app_container_name(app_id);
access_container::fetch_authenticator_entry(client)
.and_then(move |(ac_entry_version, mut ac_entries)| {
match ac_entries.remove(&app_cont_name) {
Some(mdata_info) => {
let ps = PermissionSet::new()
.allow(Action::Insert)
.allow(Action::Update)
.allow(Action::Delete)
.allow(Action::ManagePermissions);
c2.get_mdata_version(mdata_info.name, mdata_info.type_tag)
.and_then(move |version| {
c2.set_mdata_user_permissions(
mdata_info.name,
mdata_info.type_tag,
User::Key(app_sign_pk),
ps,
version + 1,
).map(move |_| mdata_info)
})
.map_err(From::from)
.into_box()
}
None => {
create(&c2, app_sign_pk)
.and_then(move |md_info| {
let _ = ac_entries.insert(app_cont_name, md_info.clone());
access_container::put_authenticator_entry(
&c3,
&ac_entries,
ac_entry_version + 1,
).map(move |()| md_info)
})
.into_box()
}
}
})
.into_box()
}
pub fn remove(client: Client<()>, app_id: &str) -> Box<AuthFuture<bool>> {
let c2 = client.clone();
let app_cont_name = app_container_name(app_id);
access_container::fetch_authenticator_entry(&client)
.and_then(move |(ac_entry_version, mut ac_entries)| {
match ac_entries.remove(&app_cont_name) {
None => {
ok!(false)
}
Some(mdata_info) => {
let c3 = c2.clone();
c2.list_mdata_entries(mdata_info.name, mdata_info.type_tag)
.and_then(move |entries| {
let actions = entries.iter().fold(EntryActions::new(), |actions,
(entry_name, val)| {
actions.del(entry_name.clone(), val.entry_version + 1)
});
c3.mutate_mdata_entries(
mdata_info.name,
mdata_info.type_tag,
actions.into(),
)
})
.map_err(From::from)
.and_then(move |_| {
access_container::put_authenticator_entry(
&client,
&ac_entries,
ac_entry_version + 1,
)
})
.map_err(From::from)
.map(move |_| true)
.into_box()
}
}
})
.into_box()
}
fn create(client: &Client<()>, app_sign_pk: sign::PublicKey) -> Box<AuthFuture<MDataInfo>> {
let dir = fry!(MDataInfo::random_private(DIR_TAG).map_err(AuthError::from));
nfs::create_dir(
client,
&dir,
btree_map![],
btree_map![User::Key(app_sign_pk) => PermissionSet::new()
.allow(Action::Insert)
.allow(Action::Update)
.allow(Action::Delete)
.allow(Action::ManagePermissions)],
).map(move |()| dir).map_err(From::from)
.into_box()
}