openauth-plugins 0.0.4

Official OpenAuth plugin modules.
Documentation
use http::header;
use openauth_core::api::ApiResponse;
use openauth_core::cookies::{
    sign_cookie_value, verify_cookie_value, AuthCookie, Cookie, CookieOptions,
};
use openauth_core::error::OpenAuthError;

pub const TWO_FACTOR_COOKIE_NAME: &str = "two_factor";
pub const TRUST_DEVICE_COOKIE_NAME: &str = "trust_device";

pub fn plugin_cookie(base: &AuthCookie, name: &str, max_age: u64) -> AuthCookie {
    let mut attributes = base.attributes.clone();
    attributes.max_age = Some(max_age);
    AuthCookie {
        name: base.name.replace("session_token", name),
        attributes,
    }
}

pub fn signed_cookie(
    cookie: &AuthCookie,
    value: &str,
    secret: &str,
) -> Result<Cookie, OpenAuthError> {
    Ok(Cookie {
        name: cookie.name.clone(),
        value: sign_cookie_value(value, secret)?,
        attributes: cookie.attributes.clone(),
    })
}

pub fn expire_cookie(cookie: &AuthCookie) -> Cookie {
    Cookie {
        name: cookie.name.clone(),
        value: String::new(),
        attributes: CookieOptions {
            max_age: Some(0),
            ..cookie.attributes.clone()
        },
    }
}

pub fn read_signed_cookie(
    cookie_header: &str,
    name: &str,
    secret: &str,
) -> Result<Option<String>, OpenAuthError> {
    let Some(value) = openauth_core::cookies::parse_cookies(cookie_header)
        .get(name)
        .cloned()
    else {
        return Ok(None);
    };
    verify_cookie_value(&value, secret)
}

pub fn append_cookies(response: &mut ApiResponse, cookies: &[Cookie]) -> Result<(), OpenAuthError> {
    for cookie in cookies {
        response.headers_mut().append(
            header::SET_COOKIE,
            http::HeaderValue::from_str(&serialize_cookie(cookie))
                .map_err(|error| OpenAuthError::Cookie(error.to_string()))?,
        );
    }
    Ok(())
}

pub fn serialize_cookie(cookie: &Cookie) -> String {
    let mut parts = vec![format!("{}={}", cookie.name, cookie.value)];
    if let Some(max_age) = cookie.attributes.max_age {
        parts.push(format!("Max-Age={max_age}"));
    }
    if let Some(expires) = &cookie.attributes.expires {
        parts.push(format!("Expires={expires}"));
    }
    if let Some(domain) = &cookie.attributes.domain {
        parts.push(format!("Domain={domain}"));
    }
    if let Some(path) = &cookie.attributes.path {
        parts.push(format!("Path={path}"));
    }
    if cookie.attributes.secure == Some(true) {
        parts.push("Secure".to_owned());
    }
    if cookie.attributes.http_only == Some(true) {
        parts.push("HttpOnly".to_owned());
    }
    if let Some(same_site) = &cookie.attributes.same_site {
        parts.push(format!("SameSite={same_site}"));
    }
    if cookie.attributes.partitioned == Some(true) {
        parts.push("Partitioned".to_owned());
    }
    parts.join("; ")
}