use axum::http::header::COOKIE;
use axum::http::HeaderMap;
pub(crate) const SESSION_COOKIE: &str = "sbol-db-token";
pub(crate) fn token_from_cookie(headers: &HeaderMap) -> Option<&str> {
headers
.get_all(COOKIE)
.iter()
.filter_map(|value| value.to_str().ok())
.flat_map(|value| value.split(';'))
.filter_map(|pair| pair.trim().split_once('='))
.find_map(|(name, value)| {
let value = value.trim();
(name.trim() == SESSION_COOKIE && !value.is_empty()).then_some(value)
})
}
pub(crate) fn login_cookie(token: &str, secure: bool) -> String {
let secure = if secure { "; Secure" } else { "" };
format!("{SESSION_COOKIE}={token}; Path=/; HttpOnly; SameSite=Lax{secure}")
}
pub(crate) fn logout_cookie(secure: bool) -> String {
let secure = if secure { "; Secure" } else { "" };
format!("{SESSION_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0{secure}")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reads_only_the_exact_nonempty_cookie() {
let mut headers = HeaderMap::new();
headers.insert(
COOKIE,
"theme=dark; sbol-db-token=abc-123; another=x"
.parse()
.unwrap(),
);
assert_eq!(token_from_cookie(&headers), Some("abc-123"));
headers.insert(COOKIE, "sbol-db-token-extra=nope".parse().unwrap());
assert_eq!(token_from_cookie(&headers), None);
headers.insert(COOKIE, "sbol-db-token=".parse().unwrap());
assert_eq!(token_from_cookie(&headers), None);
}
#[test]
fn secure_attribute_is_explicit() {
assert!(!login_cookie("token", false).contains("; Secure"));
assert!(login_cookie("token", true).ends_with("; Secure"));
assert!(logout_cookie(true).ends_with("; Secure"));
}
}