Skip to main content

cloud_sdk/authentication/
value.rs

1use core::fmt;
2
3/// Maximum bytes in one provider-owned audience, account, or tenant binding.
4pub const MAX_SCOPE_VALUE_BYTES: usize = 512;
5
6/// Authentication-scope value validation error.
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub enum ScopeValueError {
9    /// Scope values must not be empty.
10    Empty,
11    /// Scope values exceed [`MAX_SCOPE_VALUE_BYTES`].
12    TooLong,
13    /// Scope values must contain visible ASCII without whitespace or controls.
14    InvalidByte,
15}
16
17impl_static_error!(ScopeValueError,
18    Self::Empty => "authentication scope value is empty",
19    Self::TooLong => "authentication scope value exceeds the length limit",
20    Self::InvalidByte => "authentication scope value contains an invalid byte",
21);
22
23/// Borrowed, bounded provider-owned authentication-scope value.
24///
25/// Diagnostics never expose the value. Providers decide whether a value is an
26/// audience, account, or tenant identifier by the field in which it is used.
27#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
28pub struct ScopeValue<'a>(&'a str);
29
30impl<'a> ScopeValue<'a> {
31    /// Validates a provider-owned authentication-scope value.
32    pub fn new(value: &'a str) -> Result<Self, ScopeValueError> {
33        if value.is_empty() {
34            return Err(ScopeValueError::Empty);
35        }
36        if value.len() > MAX_SCOPE_VALUE_BYTES {
37            return Err(ScopeValueError::TooLong);
38        }
39        if !value
40            .bytes()
41            .all(|byte| byte.is_ascii_graphic() && byte != b'\\')
42        {
43            return Err(ScopeValueError::InvalidByte);
44        }
45        Ok(Self(value))
46    }
47
48    /// Returns the validated value for exact provider-policy comparison.
49    #[must_use]
50    pub const fn as_str(self) -> &'a str {
51        self.0
52    }
53}
54
55impl fmt::Debug for ScopeValue<'_> {
56    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
57        formatter.write_str("ScopeValue([redacted])")
58    }
59}