diff --git a/src/ext.rs b/src/ext.rs index 27467aa..1e542b1 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -294,3 +294,20 @@ impl UnwrapErrInfallible for Result } } } + +/// Declair a `submodule`. +/// +/// Load the private module, and then re-export all its internals. +#[macro_export] macro_rules! submod { + (priv $name:path $(; $doc:literal)?) => { + $(#[doc=$doc])? + mod $name; + use $name::*; + }; + ($vis:vis $name:path $(; $doc:literal)?) => { + $(#[doc=$doc])? + mod $name; + $vis use $name::*; + }; + ($name:path $(; $doc:literal)) => ($crate::submod!(pub $name $(; $doc)?)); +} diff --git a/src/server/data.rs b/src/server/data.rs index 9bfb43b..ab5dad1 100644 --- a/src/server/data.rs +++ b/src/server/data.rs @@ -90,186 +90,8 @@ pub enum MaybeEncrypted Unencrypted(Data), } -#[non_exhaustive] -#[derive(Debug)] -enum EncryptedEntryErrorKind -{ - KeyNeeded, - Decrypt(aes::Error), - Deserialize(serde_cbor::Error), - - Encrypt(aes::Error), - Serialize(serde_cbor::Error), -} - -/// Error type returned when performing encryption/decryption operations on `Data` through `MaybeEncrypted`. -#[non_exhaustive] -#[derive(Debug)] -pub struct EncryptedEntryError(Box); - -impl EncryptedEntryError -{ - /// Consume into a nicely readable `eyre::Report` - pub fn report(self) -> eyre::Report - { - let (whe, sug) = match self.0.as_ref() { - EncryptedEntryErrorKind::Serialize(_) => ("Object serialisation", "Bad data?"), - EncryptedEntryErrorKind::Deserialize(_) => ("Object deserialisation", "Corrupted data?"), - EncryptedEntryErrorKind::Decrypt(_) => ("Data decryption", "Bad key?"), - EncryptedEntryErrorKind::Encrypt(_) => ("Data encryption" ,"Bad key?"), - EncryptedEntryErrorKind::KeyNeeded => return eyre::Report::from(self) - .with_suggestion(|| "Try providing a key"), - }; - - Err::(self) - .with_section(|| whe.header("In operation")) - .with_warning(|| sug) - .unwrap_err() - } -} - -impl error::Error for EncryptedEntryError -{ - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - Some(match self.0.as_ref() { - EncryptedEntryErrorKind::Decrypt(d) => d, - EncryptedEntryErrorKind::Deserialize(d) => d, - EncryptedEntryErrorKind::Encrypt(d) => d, - EncryptedEntryErrorKind::Serialize(d) => d, - _ => return None, - }) - } -} - -impl fmt::Display for EncryptedEntryError -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result - { - match self.0.as_ref() { - EncryptedEntryErrorKind::KeyNeeded => write!(f, "this entry needed a decryption key but none was provided"), - EncryptedEntryErrorKind::Decrypt(_) => write!(f, "decryption failed"), - EncryptedEntryErrorKind::Deserialize(_) => write!(f, "deserialisation failed"), - EncryptedEntryErrorKind::Encrypt(_) => write!(f, "encryption failed"), - EncryptedEntryErrorKind::Serialize(_) => write!(f, "serialisation failed"), - } - } -} - -impl From for EncryptedEntryError -{ - #[inline] fn from(from: EncryptedEntryErrorKind) -> Self - { - Self(Box::new(from)) - } -} - - -/// Encrypt a `Data` entry into this buffer -async fn encrypt_data_entry(output: &mut T, data: &Data, key: &AesKey) -> Result -where T: ?Sized + AsyncWrite + Unpin -{ - let bytes = serde_cbor::to_vec(data).map_err(EncryptedEntryErrorKind::Serialize)?; - Ok(aes::encrypt_stream(key, &mut &bytes[..], output).await.map_err(EncryptedEntryErrorKind::Encrypt)?) -} - -/// Decrypt an encrypted `Data` entry -async fn decrypt_data_entry(input: &mut T, key: &AesKey, init_buf: Option>) -> Result -where T: AsyncRead + Unpin -{ - let mut output = init_buf.unwrap_or_default(); - aes::decrypt_stream(key, input, &mut output).await.map_err(EncryptedEntryErrorKind::Decrypt)?; - Ok(serde_cbor::from_slice(&output[..]).map_err(EncryptedEntryErrorKind::Deserialize)?) -} - -impl MaybeEncrypted -{ - /// Create a new non-encrypted entry - #[inline(always)] pub const fn new_raw(data: Data) -> Self - { - Self::Unencrypted(data) - } - /// Create a new encrypted entry - #[inline] pub fn new_encrypted(data: Data, encrypt: &AesKey) -> Result - { - let mut buffer = Vec::new(); - encrypt_data_entry(&mut buffer, &data, encrypt).now_or_never().unwrap()?; - Ok(Self::Encrypted(buffer)) - } - - /// Is this data entry encrypted - #[inline] pub fn is_encrypted(&self) -> bool - { - if let MaybeEncrypted::Encrypted(_) = &self { - true - } else { - false - } - } - - /// Consume into a decrypted data instance - #[inline] pub fn into_unencrypted(self, key: Option<&AesKey>) -> Result - { - Ok(Self::Unencrypted(self.into_data(key)?)) - } - - - /// Make this entry unencrypted - pub fn make_unencrypted(&mut self, key: Option<&AesKey>) -> Result<(), EncryptedEntryError> - { - match self { - MaybeEncrypted::Encrypted(bytes) => { - *self = MaybeEncrypted::Unencrypted(decrypt_data_entry(&mut &bytes[..], key.ok_or(EncryptedEntryErrorKind::KeyNeeded)?, Some(Vec::with_capacity(bytes.len()))).now_or_never().unwrap()?); - }, - _ => (), - } - Ok(()) - } - - /// Make this entry encrypted - pub fn make_encrypted(&mut self, key: Option<&AesKey>) -> Result<(), EncryptedEntryError> - { - match self { - MaybeEncrypted::Unencrypted(data) => { - let mut buffer = Vec::new(); - encrypt_data_entry(&mut buffer, data, key.ok_or(EncryptedEntryErrorKind::KeyNeeded)?).now_or_never().unwrap()?; - *self = Self::Encrypted(buffer); - }, - _ => (), - } - Ok(()) - } - /// Consume into an encrypted data instance - pub fn into_encrypted(self, key: Option<&AesKey>) -> Result - { - match self { - MaybeEncrypted::Unencrypted(data) => Self::new_encrypted(data, key.ok_or(EncryptedEntryErrorKind::KeyNeeded)?), - _ => Ok(self), - } - } - - /// Attempt to get the `Data`, decrypting it if needed. - pub fn get_data<'a>(&'a self, key: Option<&AesKey>) -> Result, EncryptedEntryError> - { - Ok(match self { - Self::Unencrypted(data) => Cow::Borrowed(&data), - Self::Encrypted(bytes) => { - // decrypt - Cow::Owned(decrypt_data_entry(&mut &bytes[..], key.ok_or(EncryptedEntryErrorKind::KeyNeeded)?, Some(Vec::with_capacity(bytes.len()))).now_or_never().unwrap()?) - }, - }) - } - - /// Consume into the data object, decrypting it if needed. - pub fn into_data(self, key: Option<&AesKey>) -> Result - { - Ok(match self { - Self::Encrypted(bytes) => { - decrypt_data_entry(&mut &bytes[..], key.ok_or(EncryptedEntryErrorKind::KeyNeeded)?, Some(Vec::with_capacity(bytes.len()))).now_or_never().unwrap()? - }, - Self::Unencrypted(data) => data, - }) - } -} +submod!(encryption; "impl for `MaybeEncrypted`. \ + Other `Data` encryption helpers"); bitflags! { /// And additional metadata for values diff --git a/src/server/data/encryption.rs b/src/server/data/encryption.rs new file mode 100644 index 0000000..d51ed6f --- /dev/null +++ b/src/server/data/encryption.rs @@ -0,0 +1,181 @@ +use super::*; + +#[non_exhaustive] +#[derive(Debug)] +pub(super) enum EncryptedEntryErrorKind +{ + KeyNeeded, + Decrypt(aes::Error), + Deserialize(serde_cbor::Error), + + Encrypt(aes::Error), + Serialize(serde_cbor::Error), +} + +/// Error type returned when performing encryption/decryption operations on `Data` through `MaybeEncrypted`. +#[non_exhaustive] +#[derive(Debug)] +pub struct EncryptedEntryError(Box); + +impl EncryptedEntryError +{ + /// Consume into a nicely readable `eyre::Report` + pub fn report(self) -> eyre::Report + { + let (whe, sug) = match self.0.as_ref() { + EncryptedEntryErrorKind::Serialize(_) => ("Object serialisation", "Bad data?"), + EncryptedEntryErrorKind::Deserialize(_) => ("Object deserialisation", "Corrupted data?"), + EncryptedEntryErrorKind::Decrypt(_) => ("Data decryption", "Bad key?"), + EncryptedEntryErrorKind::Encrypt(_) => ("Data encryption" ,"Bad key?"), + EncryptedEntryErrorKind::KeyNeeded => return eyre::Report::from(self) + .with_suggestion(|| "Try providing a key"), + }; + + Err::(self) + .with_section(|| whe.header("In operation")) + .with_warning(|| sug) + .unwrap_err() + } +} + +impl error::Error for EncryptedEntryError +{ + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + Some(match self.0.as_ref() { + EncryptedEntryErrorKind::Decrypt(d) => d, + EncryptedEntryErrorKind::Deserialize(d) => d, + EncryptedEntryErrorKind::Encrypt(d) => d, + EncryptedEntryErrorKind::Serialize(d) => d, + _ => return None, + }) + } +} + +impl fmt::Display for EncryptedEntryError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self.0.as_ref() { + EncryptedEntryErrorKind::KeyNeeded => write!(f, "this entry needed a decryption key but none was provided"), + EncryptedEntryErrorKind::Decrypt(_) => write!(f, "decryption failed"), + EncryptedEntryErrorKind::Deserialize(_) => write!(f, "deserialisation failed"), + EncryptedEntryErrorKind::Encrypt(_) => write!(f, "encryption failed"), + EncryptedEntryErrorKind::Serialize(_) => write!(f, "serialisation failed"), + } + } +} + +impl From for EncryptedEntryError +{ + #[inline] fn from(from: EncryptedEntryErrorKind) -> Self + { + Self(Box::new(from)) + } +} + +/// Encrypt a `Data` entry into this buffer +pub(super) async fn encrypt_data_entry(output: &mut T, data: &Data, key: &AesKey) -> Result +where T: ?Sized + AsyncWrite + Unpin +{ + let bytes = serde_cbor::to_vec(data).map_err(EncryptedEntryErrorKind::Serialize)?; + Ok(aes::encrypt_stream(key, &mut &bytes[..], output).await.map_err(EncryptedEntryErrorKind::Encrypt)?) +} + +/// Decrypt an encrypted `Data` entry +pub(super) async fn decrypt_data_entry(input: &mut T, key: &AesKey, init_buf: Option>) -> Result +where T: AsyncRead + Unpin +{ + let mut output = init_buf.unwrap_or_default(); + aes::decrypt_stream(key, input, &mut output).await.map_err(EncryptedEntryErrorKind::Decrypt)?; + Ok(serde_cbor::from_slice(&output[..]).map_err(EncryptedEntryErrorKind::Deserialize)?) +} + +impl MaybeEncrypted +{ + /// Create a new non-encrypted entry + #[inline(always)] pub const fn new_raw(data: Data) -> Self + { + Self::Unencrypted(data) + } + /// Create a new encrypted entry + #[inline] pub fn new_encrypted(data: Data, encrypt: &AesKey) -> Result + { + let mut buffer = Vec::new(); + encrypt_data_entry(&mut buffer, &data, encrypt).now_or_never().unwrap()?; + Ok(Self::Encrypted(buffer)) + } + + /// Is this data entry encrypted + #[inline] pub fn is_encrypted(&self) -> bool + { + if let MaybeEncrypted::Encrypted(_) = &self { + true + } else { + false + } + } + + /// Consume into a decrypted data instance + #[inline] pub fn into_unencrypted(self, key: Option<&AesKey>) -> Result + { + Ok(Self::Unencrypted(self.into_data(key)?)) + } + + + /// Make this entry unencrypted + pub fn make_unencrypted(&mut self, key: Option<&AesKey>) -> Result<(), EncryptedEntryError> + { + match self { + MaybeEncrypted::Encrypted(bytes) => { + *self = MaybeEncrypted::Unencrypted(decrypt_data_entry(&mut &bytes[..], key.ok_or(EncryptedEntryErrorKind::KeyNeeded)?, Some(Vec::with_capacity(bytes.len()))).now_or_never().unwrap()?); + }, + _ => (), + } + Ok(()) + } + + /// Make this entry encrypted + pub fn make_encrypted(&mut self, key: Option<&AesKey>) -> Result<(), EncryptedEntryError> + { + match self { + MaybeEncrypted::Unencrypted(data) => { + let mut buffer = Vec::new(); + encrypt_data_entry(&mut buffer, data, key.ok_or(EncryptedEntryErrorKind::KeyNeeded)?).now_or_never().unwrap()?; + *self = Self::Encrypted(buffer); + }, + _ => (), + } + Ok(()) + } + /// Consume into an encrypted data instance + pub fn into_encrypted(self, key: Option<&AesKey>) -> Result + { + match self { + MaybeEncrypted::Unencrypted(data) => Self::new_encrypted(data, key.ok_or(EncryptedEntryErrorKind::KeyNeeded)?), + _ => Ok(self), + } + } + + /// Attempt to get the `Data`, decrypting it if needed. + pub fn get_data<'a>(&'a self, key: Option<&AesKey>) -> Result, EncryptedEntryError> + { + Ok(match self { + Self::Unencrypted(data) => Cow::Borrowed(&data), + Self::Encrypted(bytes) => { + // decrypt + Cow::Owned(decrypt_data_entry(&mut &bytes[..], key.ok_or(EncryptedEntryErrorKind::KeyNeeded)?, Some(Vec::with_capacity(bytes.len()))).now_or_never().unwrap()?) + }, + }) + } + + /// Consume into the data object, decrypting it if needed. + pub fn into_data(self, key: Option<&AesKey>) -> Result + { + Ok(match self { + Self::Encrypted(bytes) => { + decrypt_data_entry(&mut &bytes[..], key.ok_or(EncryptedEntryErrorKind::KeyNeeded)?, Some(Vec::with_capacity(bytes.len()))).now_or_never().unwrap()? + }, + Self::Unencrypted(data) => data, + }) + } +} diff --git a/src/server/user.rs b/src/server/user.rs index 05a98c6..41c3dc2 100644 --- a/src/server/user.rs +++ b/src/server/user.rs @@ -366,31 +366,4 @@ pub struct Userspace groups: HashMap, } -impl Userspace -{ - /// Is this `User` or `Group` ID present in this space? - pub fn contains_id(&self, ent: &impl AsEntityId) -> bool - { - ent.entity_id().find_in_space(self).is_some() - } - - /// Get a user reference from their ID - pub fn user_ref(&self, id: UserID) -> Option> - { - if self.users.contains_key(&id) { - Some(UserRef(id, &self)) - } else { - None - } - } - - /// Get a group reference from their ID - pub fn group_ref(&self, id: GroupID) -> Option> - { - if self.groups.contains_key(&id) { - Some(GroupRef(id, &self)) - } else { - None - } - } -} +submod!(userspace; "impl for `Userspace`"); diff --git a/src/server/user/userspace.rs b/src/server/user/userspace.rs new file mode 100644 index 0000000..8fa511b --- /dev/null +++ b/src/server/user/userspace.rs @@ -0,0 +1,30 @@ +use super::*; + +impl Userspace +{ + /// Is this `User` or `Group` ID present in this space? + pub fn contains_id(&self, ent: &impl AsEntityId) -> bool + { + ent.entity_id().find_in_space(self).is_some() + } + + /// Get a user reference from their ID + pub fn user_ref(&self, id: UserID) -> Option> + { + if self.users.contains_key(&id) { + Some(UserRef(id, &self)) + } else { + None + } + } + + /// Get a group reference from their ID + pub fn group_ref(&self, id: GroupID) -> Option> + { + if self.groups.contains_key(&id) { + Some(GroupRef(id, &self)) + } else { + None + } + } +}