use http::HeaderValue;
use tako_rs_core::types::Response;
use super::token::build_cookie;
use super::token::generate_csrf_token;
use crate::middleware::session::SameSite;
use crate::middleware::session::Session;
pub(crate) fn req_session_token(resp: &Response) -> Option<String> {
resp
.headers()
.get_all(http::header::SET_COOKIE)
.iter()
.filter_map(|v| v.to_str().ok())
.find_map(|s| {
let pair = s.split(';').next()?;
let (name, value) = pair.split_once('=')?;
if name.trim() == "__csrf_seed" {
Some(value.trim().to_string())
} else {
None
}
})
}
pub(crate) fn strip_csrf_seed_cookie(resp: &mut Response) {
let headers = resp.headers_mut();
let kept: Vec<http::HeaderValue> = headers
.get_all(http::header::SET_COOKIE)
.iter()
.filter(|v| {
let s = v.to_str().unwrap_or("");
let first = s.split(';').next().unwrap_or("");
let name = first
.split_once('=')
.map_or(first.trim(), |(n, _)| n.trim());
name != "__csrf_seed"
})
.cloned()
.collect();
headers.remove(http::header::SET_COOKIE);
for v in kept {
headers.append(http::header::SET_COOKIE, v);
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn ensure_csrf_cookie(
resp: &mut Response,
cookie_name: &str,
secure: bool,
same_site: SameSite,
session_key: &str,
bind_to_session: bool,
preferred_token: Option<&String>,
session: Option<&Session>,
) {
let already_set = resp
.headers()
.get_all(http::header::SET_COOKIE)
.iter()
.filter_map(|v| v.to_str().ok())
.any(|s| {
let first = s.split(';').next().unwrap_or("");
let name = first
.split_once('=')
.map_or(first.trim(), |(n, _)| n.trim());
name == cookie_name
});
if already_set {
return;
}
let token = preferred_token.cloned().unwrap_or_else(generate_csrf_token);
if bind_to_session && let Some(session) = session {
session.set(session_key, token.clone());
}
let cookie = build_cookie(cookie_name, &token, secure, same_site);
if let Ok(v) = HeaderValue::from_str(&cookie) {
resp.headers_mut().append(http::header::SET_COOKIE, v);
}
}