systemprompt_security/extraction/
cookie.rs1use axum::http::HeaderMap;
7
8#[derive(Debug, Clone)]
9pub struct CookieExtractor {
10 cookie_name: String,
11}
12
13impl Default for CookieExtractor {
14 fn default() -> Self {
15 Self::new(Self::DEFAULT_COOKIE_NAME)
16 }
17}
18
19impl CookieExtractor {
20 pub const DEFAULT_COOKIE_NAME: &'static str = "access_token";
21
22 pub fn new(cookie_name: impl Into<String>) -> Self {
23 Self {
24 cookie_name: cookie_name.into(),
25 }
26 }
27
28 pub fn extract(&self, headers: &HeaderMap) -> Result<String, CookieExtractionError> {
29 self.extract_internal(headers)
30 }
31
32 pub fn extract_access_token(headers: &HeaderMap) -> Result<String, CookieExtractionError> {
33 Self::default().extract(headers)
34 }
35
36 fn extract_internal(&self, headers: &HeaderMap) -> Result<String, CookieExtractionError> {
37 let cookie_header = headers
38 .get("cookie")
39 .ok_or(CookieExtractionError::MissingCookie)?
40 .to_str()
41 .map_err(|_e| CookieExtractionError::InvalidCookieFormat)?;
42
43 for cookie in cookie_header.split(';') {
44 let cookie = cookie.trim();
45 let cookie_prefix = format!("{}=", self.cookie_name);
46 if let Some(value) = cookie.strip_prefix(&cookie_prefix)
47 && !value.is_empty()
48 {
49 return Ok(value.to_owned());
50 }
51 }
52
53 Err(CookieExtractionError::TokenNotFoundInCookie)
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub enum CookieExtractionError {
59 MissingCookie,
60 InvalidCookieFormat,
61 TokenNotFoundInCookie,
62}
63
64impl std::fmt::Display for CookieExtractionError {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 match self {
67 Self::MissingCookie => write!(f, "Missing cookie header"),
68 Self::InvalidCookieFormat => write!(f, "Invalid cookie format"),
69 Self::TokenNotFoundInCookie => {
70 write!(f, "Access token not found in cookies")
71 },
72 }
73 }
74}
75
76impl std::error::Error for CookieExtractionError {}