openauth-core 0.0.4

Core types and primitives for OpenAuth.
Documentation
use crate::error::OpenAuthError;

use super::chunked::ChunkedCookieStore;
use super::config::merge_options;
use super::parse::parse_cookies;
use super::signing::sign_cookie_value;
use super::types::{AuthCookie, AuthCookies, Cookie, SessionCookieOptions, SECURE_COOKIE_PREFIX};

pub fn get_session_cookie(
    cookie_header: &str,
    cookie_prefix: Option<&str>,
    cookie_name: Option<&str>,
) -> Option<String> {
    let prefix = cookie_prefix.unwrap_or("better-auth");
    let name = cookie_name.unwrap_or("session_token");
    let full_name = format!("{prefix}.{name}");
    let legacy_name = format!("{prefix}-{name}");
    let secure_name = format!("{SECURE_COOKIE_PREFIX}{full_name}");
    let secure_legacy_name = format!("{SECURE_COOKIE_PREFIX}{legacy_name}");
    let cookies = parse_cookies(cookie_header);

    cookies
        .get(&full_name)
        .or_else(|| cookies.get(&secure_name))
        .or_else(|| cookies.get(&legacy_name))
        .or_else(|| cookies.get(&secure_legacy_name))
        .cloned()
}

pub fn set_session_cookie(
    auth_cookies: &AuthCookies,
    secret: &str,
    token: &str,
    options: SessionCookieOptions,
) -> Result<Vec<Cookie>, OpenAuthError> {
    let mut attributes = merge_options(
        auth_cookies.session_token.attributes.clone(),
        options.overrides,
    );
    if options.dont_remember {
        attributes.max_age = None;
    }

    let mut cookies = vec![Cookie {
        name: auth_cookies.session_token.name.clone(),
        value: sign_cookie_value(token, secret)?,
        attributes,
    }];

    if options.dont_remember {
        cookies.push(Cookie {
            name: auth_cookies.dont_remember_token.name.clone(),
            value: sign_cookie_value("true", secret)?,
            attributes: auth_cookies.dont_remember_token.attributes.clone(),
        });
    }

    Ok(cookies)
}

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

pub fn delete_session_cookie(
    auth_cookies: &AuthCookies,
    cookie_header: &str,
    skip_dont_remember: bool,
) -> Vec<Cookie> {
    let mut expired = vec![
        expire_cookie(&auth_cookies.session_token),
        expire_cookie(&auth_cookies.session_data),
        expire_cookie(&auth_cookies.account_data),
    ];
    expired.extend(clean_chunked_cookie(
        &auth_cookies.session_data,
        cookie_header,
    ));
    expired.extend(clean_chunked_cookie(
        &auth_cookies.account_data,
        cookie_header,
    ));
    if !skip_dont_remember {
        expired.push(expire_cookie(&auth_cookies.dont_remember_token));
    }
    expired
}

fn clean_chunked_cookie(cookie: &AuthCookie, cookie_header: &str) -> Vec<Cookie> {
    ChunkedCookieStore::new(
        cookie.name.clone(),
        cookie.attributes.clone(),
        cookie_header,
    )
    .clean()
}