totp-rs 6.0.0

RFC-compliant TOTP implementation with ease of use as a goal and additional QoL features.
Documentation
use crate::TotpError;

// Check that the number of digits is RFC-compliant.
// (between 6 and 8 inclusive).
pub fn assert_digits(digits: u8) -> Result<(), TotpError> {
    if !(6..=8).contains(&digits) {
        return Err(TotpError::InvalidDigits { digits });
    }

    Ok(())
}

// Check that the secret is AT LEAST 128 bits long, as per the RFC's requirements.
// It is still RECOMMENDED to have an at least 160 bits long secret.
pub fn assert_secret_length(secret: &[u8]) -> Result<(), TotpError> {
    if secret.as_ref().len() < 16 {
        return Err(TotpError::SecretTooShort {
            bits: secret.as_ref().len() * 8,
        });
    }

    Ok(())
}

// Checks that account_name is not empty AND doesn't contain `:`.
#[cfg(feature = "otpauth")]
pub fn assert_account_name_valid(account_name: &str) -> Result<(), TotpError> {
    if account_name.is_empty() {
        return Err(TotpError::AccountNameNotSet);
    }

    if account_name.contains(':') {
        return Err(TotpError::InvalidAccountName {
            account_name: account_name.into(),
        });
    }

    Ok(())
}

// Checks that issuer is either unset (not recommended) or doesn't contain `:`.
#[cfg(feature = "otpauth")]
pub fn assert_issuer_valid(issuer: &Option<impl AsRef<str>>) -> Result<(), TotpError> {
    if let Some(issuer) = issuer
        && issuer.as_ref().contains(':')
    {
        return Err(TotpError::InvalidIssuer {
            issuer: issuer.as_ref().into(),
        });
    }

    Ok(())
}