use std::{borrow::Borrow, ffi::CStr, path::Path, ptr, sync::Mutex};
use bson::Document;
#[cfg(test)]
use convert::str_bytes_len;
use convert::{doc_binary, path_cstring};
use ctx::CtxBuilder;
use mongocrypt_sys as sys;
mod binary;
mod convert;
pub mod ctx;
pub mod error;
mod hooks;
mod native;
#[cfg(test)]
mod test;
use error::{HasStatus, Result};
pub use hooks::*;
use native::OwnedPtr;
use once_cell::sync::Lazy;
#[cfg(not(any(feature = "bson-2", feature = "bson-3")))]
compile_error!("One of the bson-2 and bson-3 features must be enabled.");
#[cfg(all(feature = "bson-2", not(feature = "bson-3")))]
use bson_2 as bson;
#[cfg(feature = "bson-3")]
use bson_3 as bson;
pub fn version() -> &'static str {
let c_version = unsafe { CStr::from_ptr(sys::mongocrypt_version(ptr::null_mut())) };
c_version.to_str().unwrap()
}
pub fn is_crypto_available() -> bool {
unsafe { sys::mongocrypt_is_crypto_available() }
}
pub struct CryptBuilder {
inner: OwnedPtr<sys::mongocrypt_t>,
cleanup: Vec<Box<dyn std::any::Any>>,
}
impl HasStatus for CryptBuilder {
unsafe fn native_status(&self, status: *mut sys::mongocrypt_status_t) {
sys::mongocrypt_status(*self.inner.borrow(), status);
}
}
static CRYPT_LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
unsafe extern "C" fn mongocrypt_destroy_locked(crypt: *mut sys::mongocrypt_t) {
let _guard = CRYPT_LOCK.lock().unwrap();
sys::mongocrypt_destroy(crypt);
}
impl CryptBuilder {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
inner: OwnedPtr::steal(unsafe { sys::mongocrypt_new() }, mongocrypt_destroy_locked),
cleanup: vec![],
}
}
#[cfg(test)]
pub(crate) fn kms_provider_aws(
self,
aws_access_key_id: &str,
aws_secret_access_key: &str,
) -> Result<Self> {
let (key_bytes, key_len) = str_bytes_len(aws_access_key_id)?;
let (secret_bytes, secret_len) = str_bytes_len(aws_secret_access_key)?;
unsafe {
if !sys::mongocrypt_setopt_kms_provider_aws(
*self.inner.borrow(),
key_bytes,
key_len,
secret_bytes,
secret_len,
) {
return Err(self.status().as_error());
}
}
Ok(self)
}
pub fn kms_providers(self, kms_providers: &Document) -> Result<Self> {
let mut binary = doc_binary(kms_providers)?;
unsafe {
if !sys::mongocrypt_setopt_kms_providers(*self.inner.borrow(), *binary.native()) {
return Err(self.status().as_error());
}
}
Ok(self)
}
pub fn schema_map(self, schema_map: &Document) -> Result<Self> {
let mut binary = doc_binary(schema_map)?;
unsafe {
if !sys::mongocrypt_setopt_schema_map(*self.inner.borrow(), *binary.native()) {
return Err(self.status().as_error());
}
}
Ok(self)
}
pub fn encrypted_field_config_map(self, efc_map: &Document) -> Result<Self> {
let mut binary = doc_binary(efc_map)?;
unsafe {
if !sys::mongocrypt_setopt_encrypted_field_config_map(
*self.inner.borrow(),
*binary.native(),
) {
return Err(self.status().as_error());
}
}
Ok(self)
}
pub fn append_crypt_shared_lib_search_path(self, path: &Path) -> Result<Self> {
let tmp = path_cstring(path)?;
unsafe {
sys::mongocrypt_setopt_append_crypt_shared_lib_search_path(
*self.inner.borrow(),
tmp.as_ptr(),
);
}
Ok(self)
}
pub fn set_crypt_shared_lib_path_override(self, path: &Path) -> Result<Self> {
let tmp = path_cstring(path)?;
unsafe {
sys::mongocrypt_setopt_set_crypt_shared_lib_path_override(
*self.inner.borrow(),
tmp.as_ptr(),
);
}
Ok(self)
}
pub fn use_need_kms_credentials_state(self) -> Self {
unsafe {
sys::mongocrypt_setopt_use_need_kms_credentials_state(*self.inner.borrow());
}
self
}
pub fn use_need_mongo_collinfo_with_db_state(self) -> Self {
unsafe {
sys::mongocrypt_setopt_use_need_mongo_collinfo_with_db_state(*self.inner.borrow());
}
self
}
pub fn enable_multiple_collinfo(self) -> Result<Self> {
let ok = unsafe { sys::mongocrypt_setopt_enable_multiple_collinfo(*self.inner.borrow()) };
if !ok {
return Err(self.status().as_error());
}
Ok(self)
}
pub fn bypass_query_analysis(self) -> Self {
unsafe {
sys::mongocrypt_setopt_bypass_query_analysis(*self.inner.borrow());
}
self
}
pub fn use_range_v2(self) -> Result<Self> {
let ok = unsafe { sys::mongocrypt_setopt_use_range_v2(*self.inner.borrow()) };
if !ok {
return Err(self.status().as_error());
}
Ok(self)
}
pub fn retry_kms(self, enable: bool) -> Result<Self> {
unsafe {
let ok = sys::mongocrypt_setopt_retry_kms(*self.inner.borrow(), enable);
if !ok {
return Err(self.status().as_error());
}
}
Ok(self)
}
pub fn key_cache_expiration(self, expiration_ms: u64) -> Result<Self> {
unsafe {
let ok = sys::mongocrypt_setopt_key_expiration(*self.inner.borrow(), expiration_ms);
if !ok {
return Err(self.status().as_error());
}
}
Ok(self)
}
pub fn build(mut self) -> Result<Crypt> {
let _guard = CRYPT_LOCK.lock().unwrap();
let ok = unsafe { sys::mongocrypt_init(*self.inner.borrow()) };
if !ok {
return Err(self.status().as_error());
}
Ok(Crypt {
inner: self.inner,
_cleanup: std::mem::take(&mut self.cleanup),
})
}
}
pub struct Crypt {
inner: OwnedPtr<sys::mongocrypt_t>,
_cleanup: Vec<Box<dyn std::any::Any>>,
}
unsafe impl Send for Crypt {}
unsafe impl Sync for Crypt {}
impl Crypt {
pub fn builder() -> CryptBuilder {
CryptBuilder::new()
}
pub fn shared_lib_version_string(&self) -> Option<String> {
let s_ptr = unsafe {
sys::mongocrypt_crypt_shared_lib_version_string(
*self.inner.borrow_const(),
ptr::null_mut(),
)
};
if s_ptr.is_null() {
return None;
}
let s = unsafe { CStr::from_ptr(s_ptr) };
Some(s.to_string_lossy().to_string())
}
pub fn shared_lib_version(&self) -> Option<u64> {
let out = unsafe { sys::mongocrypt_crypt_shared_lib_version(*self.inner.borrow_const()) };
if out == 0 {
return None;
}
Some(out)
}
pub fn ctx_builder(&self) -> CtxBuilder {
CtxBuilder::steal(unsafe { sys::mongocrypt_ctx_new(*self.inner.borrow()) })
}
}