openauth-core 0.0.4

Core types and primitives for OpenAuth.
Documentation
use crate::context::{AuthContext, SecretMaterial};
use crate::crypto::{symmetric_decrypt, symmetric_encrypt};
use crate::error::OpenAuthError;

pub fn set_token_util(
    token: Option<&str>,
    context: &AuthContext,
) -> Result<Option<String>, OpenAuthError> {
    let Some(token) = token else {
        return Ok(None);
    };
    if context.options.account.encrypt_oauth_tokens {
        encrypt_with_context(token, context).map(Some)
    } else {
        Ok(Some(token.to_owned()))
    }
}

pub fn decrypt_oauth_token(token: &str, context: &AuthContext) -> Result<String, OpenAuthError> {
    if token.is_empty() || !context.options.account.encrypt_oauth_tokens {
        return Ok(token.to_owned());
    }
    if !is_likely_encrypted(token) {
        return Ok(token.to_owned());
    }
    decrypt_with_context(token, context)
}

pub(crate) fn encrypt_with_context(
    data: &str,
    context: &AuthContext,
) -> Result<String, OpenAuthError> {
    match &context.secret_config {
        SecretMaterial::Single(secret) => symmetric_encrypt(secret.as_str(), data),
        SecretMaterial::Rotating(config) => symmetric_encrypt(config, data),
    }
}

pub(crate) fn decrypt_with_context(
    data: &str,
    context: &AuthContext,
) -> Result<String, OpenAuthError> {
    match &context.secret_config {
        SecretMaterial::Single(secret) => symmetric_decrypt(secret.as_str(), data),
        SecretMaterial::Rotating(config) => symmetric_decrypt(config, data),
    }
}

fn is_likely_encrypted(token: &str) -> bool {
    token.starts_with("$ba$")
        || (token.len() % 2 == 0 && token.chars().all(|character| character.is_ascii_hexdigit()))
}