app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

installation.rs (1863B)


      1 use harvestcircle_domain::{SafeError, SafeErrorCode, SafeMessage};
      2 
      3 #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
      4 pub struct InstallationIdentity(String);
      5 
      6 impl InstallationIdentity {
      7     pub fn parse(value: impl Into<String>) -> Result<Self, SafeError> {
      8         let value = value.into();
      9         if value.len() != 32
     10             || !value
     11                 .bytes()
     12                 .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
     13         {
     14             return Err(invalid_installation_identity());
     15         }
     16         Ok(Self(value))
     17     }
     18 
     19     #[must_use]
     20     pub fn as_str(&self) -> &str {
     21         self.0.as_str()
     22     }
     23 }
     24 
     25 pub trait InstallationIdentitySource: Send + Sync {
     26     fn generate(&self) -> Result<InstallationIdentity, SafeError>;
     27 }
     28 
     29 #[derive(Clone, Copy, Debug, Default)]
     30 pub struct UuidInstallationIdentitySource;
     31 
     32 impl InstallationIdentitySource for UuidInstallationIdentitySource {
     33     fn generate(&self) -> Result<InstallationIdentity, SafeError> {
     34         InstallationIdentity::parse(uuid::Uuid::new_v4().simple().to_string())
     35     }
     36 }
     37 
     38 const fn invalid_installation_identity() -> SafeError {
     39     SafeError::new(
     40         SafeErrorCode::InvalidApplicationState,
     41         SafeMessage::new("The installation identity is invalid."),
     42     )
     43 }
     44 
     45 #[cfg(test)]
     46 mod tests {
     47     use super::{InstallationIdentity, InstallationIdentitySource, UuidInstallationIdentitySource};
     48 
     49     #[test]
     50     fn installation_identity_is_fixed_width_lowercase_hex() {
     51         let identity = UuidInstallationIdentitySource.generate().expect("identity");
     52         assert_eq!(identity.as_str().len(), 32);
     53         assert!(InstallationIdentity::parse(identity.as_str()).is_ok());
     54         for denied in ["", "AAaabbccddeeff001122334455667788", "not-an-identity"] {
     55             assert!(InstallationIdentity::parse(denied).is_err());
     56         }
     57     }
     58 }