pub use crate::internal::document_api::{
AssociationType, DocAccessEditErr, DocumentAccessResult, DocumentDecryptResult,
DocumentEncryptResult, DocumentListMeta, DocumentListResult, DocumentMetadataResult,
UserOrGroup, VisibleGroup, VisibleUser,
};
use crate::{
internal::{
add_optional_timeout,
document_api::{self, DocumentId, DocumentName},
group_api::GroupId,
user_api::UserId,
SdkOperation,
},
policy::*,
Result,
};
use itertools::{Either, EitherOrBoth, Itertools};
pub mod advanced;
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct DocumentEncryptOpts {
id: Option<DocumentId>,
name: Option<DocumentName>,
grants: EitherOrBoth<ExplicitGrant, PolicyGrant>,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct ExplicitGrant {
grant_to_author: bool,
grants: Vec<UserOrGroup>,
}
impl ExplicitGrant {
pub fn new(grant_to_author: bool, grants: &[UserOrGroup]) -> ExplicitGrant {
ExplicitGrant {
grant_to_author,
grants: grants.to_vec(),
}
}
}
impl DocumentEncryptOpts {
pub fn new(
id: Option<DocumentId>,
name: Option<DocumentName>,
grants: EitherOrBoth<ExplicitGrant, PolicyGrant>,
) -> DocumentEncryptOpts {
DocumentEncryptOpts { grants, name, id }
}
pub fn with_explicit_grants(
id: Option<DocumentId>,
name: Option<DocumentName>,
grant_to_author: bool,
grants: Vec<UserOrGroup>,
) -> DocumentEncryptOpts {
DocumentEncryptOpts {
id,
name,
grants: EitherOrBoth::Left(ExplicitGrant {
grants,
grant_to_author,
}),
}
}
pub fn with_policy_grants(
id: Option<DocumentId>,
name: Option<DocumentName>,
policy: PolicyGrant,
) -> DocumentEncryptOpts {
DocumentEncryptOpts {
id,
name,
grants: EitherOrBoth::Right(policy),
}
}
}
impl Default for DocumentEncryptOpts {
fn default() -> Self {
DocumentEncryptOpts::with_explicit_grants(None, None, true, vec![])
}
}
#[async_trait]
pub trait DocumentOps {
async fn document_list(&self) -> Result<DocumentListResult>;
async fn document_get_metadata(&self, id: &DocumentId) -> Result<DocumentMetadataResult>;
fn document_get_id_from_bytes(&self, encrypted_document: &[u8]) -> Result<DocumentId>;
async fn document_encrypt(
&self,
document_data: &[u8],
encrypt_opts: &DocumentEncryptOpts,
) -> Result<DocumentEncryptResult>;
async fn document_update_bytes(
&self,
id: &DocumentId,
new_document_data: &[u8],
) -> Result<DocumentEncryptResult>;
async fn document_decrypt(&self, encrypted_document: &[u8]) -> Result<DocumentDecryptResult>;
async fn document_update_name(
&self,
id: &DocumentId,
name: Option<&DocumentName>,
) -> Result<DocumentMetadataResult>;
async fn document_grant_access(
&self,
document_id: &DocumentId,
grant_list: &Vec<UserOrGroup>,
) -> Result<DocumentAccessResult>;
async fn document_revoke_access(
&self,
document_id: &DocumentId,
revoke_list: &Vec<UserOrGroup>,
) -> Result<DocumentAccessResult>;
}
#[async_trait]
impl DocumentOps for crate::IronOxide {
async fn document_list(&self) -> Result<DocumentListResult> {
add_optional_timeout(
document_api::document_list(self.device.auth()),
self.config.sdk_operation_timeout,
SdkOperation::DocumentList,
)
.await?
}
async fn document_get_metadata(&self, id: &DocumentId) -> Result<DocumentMetadataResult> {
add_optional_timeout(
document_api::document_get_metadata(self.device.auth(), id),
self.config.sdk_operation_timeout,
SdkOperation::DocumentGetMetadata,
)
.await?
}
fn document_get_id_from_bytes(&self, encrypted_document: &[u8]) -> Result<DocumentId> {
document_api::get_id_from_bytes(encrypted_document)
}
async fn document_encrypt(
&self,
document_data: &[u8],
encrypt_opts: &DocumentEncryptOpts,
) -> Result<DocumentEncryptResult> {
let encrypt_opts = encrypt_opts.clone();
let (explicit_users, explicit_groups, grant_to_author, policy_grants) =
match encrypt_opts.grants {
EitherOrBoth::Left(explicit_grants) => {
let (users, groups) = partition_user_or_group(&explicit_grants.grants);
(users, groups, explicit_grants.grant_to_author, None)
}
EitherOrBoth::Right(policy_grant) => (vec![], vec![], false, Some(policy_grant)),
EitherOrBoth::Both(explicit_grants, policy_grant) => {
let (users, groups) = partition_user_or_group(&explicit_grants.grants);
(
users,
groups,
explicit_grants.grant_to_author,
Some(policy_grant),
)
}
};
add_optional_timeout(
document_api::encrypt_document(
self.device.auth(),
&self.config,
&self.recrypt,
&self.user_master_pub_key,
&self.rng,
document_data,
encrypt_opts.id,
encrypt_opts.name,
grant_to_author,
&explicit_users,
&explicit_groups,
policy_grants.as_ref(),
&self.policy_eval_cache,
),
self.config.sdk_operation_timeout,
SdkOperation::DocumentEncrypt,
)
.await?
}
async fn document_update_bytes(
&self,
id: &DocumentId,
new_document_data: &[u8],
) -> Result<DocumentEncryptResult> {
add_optional_timeout(
document_api::document_update_bytes(
self.device.auth(),
&self.recrypt,
self.device.device_private_key(),
&self.rng,
id,
new_document_data,
),
self.config.sdk_operation_timeout,
SdkOperation::DocumentUpdateBytes,
)
.await?
}
async fn document_decrypt(&self, encrypted_document: &[u8]) -> Result<DocumentDecryptResult> {
add_optional_timeout(
document_api::decrypt_document(
self.device.auth(),
&self.recrypt,
self.device.device_private_key(),
encrypted_document,
),
self.config.sdk_operation_timeout,
SdkOperation::DocumentDecrypt,
)
.await?
}
async fn document_update_name(
&self,
id: &DocumentId,
name: Option<&DocumentName>,
) -> Result<DocumentMetadataResult> {
add_optional_timeout(
document_api::update_document_name(self.device.auth(), id, name),
self.config.sdk_operation_timeout,
SdkOperation::DocumentUpdateName,
)
.await?
}
async fn document_grant_access(
&self,
id: &DocumentId,
grant_list: &Vec<UserOrGroup>,
) -> Result<DocumentAccessResult> {
let (users, groups) = partition_user_or_group(grant_list);
add_optional_timeout(
document_api::document_grant_access(
self.device.auth(),
&self.recrypt,
id,
&self.user_master_pub_key,
self.device.device_private_key(),
&users,
&groups,
),
self.config.sdk_operation_timeout,
SdkOperation::DocumentGrantAccess,
)
.await?
}
async fn document_revoke_access(
&self,
id: &DocumentId,
revoke_list: &Vec<UserOrGroup>,
) -> Result<DocumentAccessResult> {
add_optional_timeout(
document_api::document_revoke_access(self.device.auth(), id, revoke_list),
self.config.sdk_operation_timeout,
SdkOperation::DocumentRevokeAccess,
)
.await?
}
}
fn partition_user_or_group(uog_slice: &[UserOrGroup]) -> (Vec<UserId>, Vec<GroupId>) {
uog_slice
.iter()
.partition_map(|access_grant| match access_grant {
UserOrGroup::User { id } => Either::Left(id.clone()),
UserOrGroup::Group { id } => Either::Right(id.clone()),
})
}