use crate::key::private::{
PRIVATE_KEY_WRAPPED_SECRET_LEN_MAX, PRIVATE_KEY_WRAPPED_SECRET_LOCAL_CAP_DEFAULT,
};
use crate::key::public::{RECIPIENT_STRING_LEN_LOCAL_CAP_DEFAULT, RECIPIENT_STRING_LEN_MAX};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct KeyReadLimits {
pub(crate) max_recipient_string_chars: u32,
pub(crate) max_private_key_wrapped_secret_len: u32,
}
impl Default for KeyReadLimits {
fn default() -> Self {
Self {
max_recipient_string_chars: Self::RECIPIENT_STRING_CHARS_DEFAULT,
max_private_key_wrapped_secret_len: Self::PRIVATE_KEY_WRAPPED_SECRET_LEN_DEFAULT,
}
}
}
impl KeyReadLimits {
pub const RECIPIENT_STRING_CHARS_STRUCTURAL_MAX: u32 = RECIPIENT_STRING_LEN_MAX as u32;
pub const PRIVATE_KEY_WRAPPED_SECRET_LEN_STRUCTURAL_MAX: u32 =
PRIVATE_KEY_WRAPPED_SECRET_LEN_MAX;
pub const RECIPIENT_STRING_CHARS_DEFAULT: u32 = RECIPIENT_STRING_LEN_LOCAL_CAP_DEFAULT as u32;
pub const PRIVATE_KEY_WRAPPED_SECRET_LEN_DEFAULT: u32 =
PRIVATE_KEY_WRAPPED_SECRET_LOCAL_CAP_DEFAULT;
pub fn max_recipient_string_chars(mut self, value: u32) -> Self {
self.max_recipient_string_chars = value.min(Self::RECIPIENT_STRING_CHARS_STRUCTURAL_MAX);
self
}
pub fn max_private_key_wrapped_secret_len(mut self, value: u32) -> Self {
self.max_private_key_wrapped_secret_len =
value.min(Self::PRIVATE_KEY_WRAPPED_SECRET_LEN_STRUCTURAL_MAX);
self
}
pub(crate) fn recipient_string_chars(self) -> usize {
self.max_recipient_string_chars as usize
}
pub(crate) fn private_key_wrapped_secret_len(self) -> u32 {
self.max_private_key_wrapped_secret_len
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_match_the_reader_constants() {
let limits = KeyReadLimits::default();
assert_eq!(
limits.recipient_string_chars(),
RECIPIENT_STRING_LEN_LOCAL_CAP_DEFAULT
);
assert_eq!(
limits.private_key_wrapped_secret_len(),
PRIVATE_KEY_WRAPPED_SECRET_LOCAL_CAP_DEFAULT
);
}
#[test]
fn builders_round_trip_in_range_values() {
let limits = KeyReadLimits::default()
.max_recipient_string_chars(4_096)
.max_private_key_wrapped_secret_len(8_192);
assert_eq!(limits.recipient_string_chars(), 4_096);
assert_eq!(limits.private_key_wrapped_secret_len(), 8_192);
}
#[test]
fn structural_maxima_fit_the_key_file_read_caps() {
use crate::key::private::{
PRIVATE_KEY_EXT_LEN_MAX, PRIVATE_KEY_FILE_READ_CAP_BYTES,
PRIVATE_KEY_HEADER_FIXED_SIZE, PRIVATE_KEY_PUBLIC_LEN_MAX,
};
use crate::key::public::PUBLIC_KEY_FILE_READ_CAP_BYTES;
use crate::recipient::name::TYPE_NAME_MAX_LEN;
let widest_public_key_file =
KeyReadLimits::RECIPIENT_STRING_CHARS_STRUCTURAL_MAX as usize + 1;
assert!(
widest_public_key_file <= PUBLIC_KEY_FILE_READ_CAP_BYTES,
"a {widest_public_key_file}-byte public.key must fit the \
{PUBLIC_KEY_FILE_READ_CAP_BYTES}-byte read cap"
);
let widest_private_key_file = PRIVATE_KEY_HEADER_FIXED_SIZE
+ TYPE_NAME_MAX_LEN
+ PRIVATE_KEY_PUBLIC_LEN_MAX as usize
+ PRIVATE_KEY_EXT_LEN_MAX as usize
+ KeyReadLimits::PRIVATE_KEY_WRAPPED_SECRET_LEN_STRUCTURAL_MAX as usize;
assert!(
widest_private_key_file <= PRIVATE_KEY_FILE_READ_CAP_BYTES,
"a {widest_private_key_file}-byte private.key must fit the \
{PRIVATE_KEY_FILE_READ_CAP_BYTES}-byte read cap"
);
}
#[test]
fn builders_clamp_at_structural_maxima() {
let clamped = KeyReadLimits::default()
.max_recipient_string_chars(u32::MAX)
.max_private_key_wrapped_secret_len(u32::MAX);
assert_eq!(
clamped.recipient_string_chars(),
RECIPIENT_STRING_LEN_MAX,
"recipient-string cap must clamp at the 20,000-character ceiling"
);
assert_eq!(
clamped.private_key_wrapped_secret_len(),
PRIVATE_KEY_WRAPPED_SECRET_LEN_MAX,
"wrapped-secret cap must clamp at the 16 MiB ceiling"
);
}
}