embystream 0.0.22

Another Emby streaming application (frontend/backend separation) written in Rust.
Documentation
use crate::{
    AppState, STREAM_LOGGER_DOMAIN,
    core::{error::Error as AppStreamError, sign::Sign},
    crypto::{Crypto, CryptoInput, CryptoOperation, CryptoOutput},
    debug_log,
    sign::SignParams,
    util::StringUtil,
};

pub struct SignDecryptor;

impl SignDecryptor {
    pub async fn decrypt(
        sign_str: &str,
        params: &SignParams,
        state: &AppState,
    ) -> Result<Sign, AppStreamError> {
        if sign_str.is_empty() {
            return Err(AppStreamError::EmptySignature);
        }

        let decrypt_cache = state.get_decrypt_cache().await;
        let cache_key = Self::build_cache_key(params)?;

        if let Some(sign) = decrypt_cache.get(&cache_key) {
            debug_log!(STREAM_LOGGER_DOMAIN, "Sign cache hit: {:?}", sign);
            return Ok(sign);
        }

        let config = state.get_config().await;
        let crypto_result = Crypto::execute(
            CryptoOperation::Decrypt,
            CryptoInput::Encrypted(sign_str.to_string()),
            &config.general.encipher_key,
            &config.general.encipher_iv,
        )
        .map_err(AppStreamError::CommonError)?;

        match crypto_result {
            CryptoOutput::Encrypted(_) => {
                Err(AppStreamError::InvalidEncryptedSignature)
            }
            CryptoOutput::Dictionary(sign_map) => {
                debug_log!(
                    STREAM_LOGGER_DOMAIN,
                    "Successfully decrypted signature: {:?}",
                    sign_map
                );
                decrypt_cache.insert(cache_key, sign_map.clone());
                Ok(Sign::from_map(&sign_map))
            }
        }
    }

    fn build_cache_key(params: &SignParams) -> Result<String, AppStreamError> {
        if params.sign.is_empty() {
            return Err(AppStreamError::InvalidEncryptedSignature);
        }
        let input = params.sign.to_lowercase();
        Ok(StringUtil::md5(&input))
    }
}