viewpoint_core/api/cookies/
mod.rs1use std::sync::Arc;
4
5use reqwest::cookie::{CookieStore, Jar};
6use reqwest::header::HeaderValue;
7use tracing::debug;
8
9use crate::context::Cookie;
10
11pub fn sync_to_jar(cookies: &[Cookie], jar: &Arc<Jar>) {
15 for cookie in cookies {
16 let url = cookie_to_url(cookie);
18
19 if let Ok(parsed_url) = url::Url::parse(&url) {
20 let cookie_str = cookie_to_string(cookie);
22
23 if let Ok(header_value) = HeaderValue::from_str(&cookie_str) {
25 let headers = [header_value];
27 jar.set_cookies(
28 &mut headers.iter(),
29 &parsed_url,
30 );
31 debug!("Synced cookie {} to API jar for {}", cookie.name, url);
32 }
33 }
34 }
35}
36
37fn cookie_to_url(cookie: &Cookie) -> String {
39 if let Some(ref url) = cookie.url {
40 return url.clone();
41 }
42
43 let scheme = if cookie.secure.unwrap_or(false) {
44 "https"
45 } else {
46 "http"
47 };
48
49 let domain = cookie.domain.as_deref().unwrap_or("localhost");
50 let domain = domain.trim_start_matches('.');
51 let path = cookie.path.as_deref().unwrap_or("/");
52
53 format!("{scheme}://{domain}{path}")
54}
55
56fn cookie_to_string(cookie: &Cookie) -> String {
58 let mut parts = vec![format!("{}={}", cookie.name, cookie.value)];
59
60 if let Some(ref domain) = cookie.domain {
61 parts.push(format!("Domain={domain}"));
62 }
63 if let Some(ref path) = cookie.path {
64 parts.push(format!("Path={path}"));
65 }
66 if cookie.secure.unwrap_or(false) {
67 parts.push("Secure".to_string());
68 }
69 if cookie.http_only.unwrap_or(false) {
70 parts.push("HttpOnly".to_string());
71 }
72 if let Some(same_site) = &cookie.same_site {
73 parts.push(format!("SameSite={}", match same_site {
74 crate::context::SameSite::Strict => "Strict",
75 crate::context::SameSite::Lax => "Lax",
76 crate::context::SameSite::None => "None",
77 }));
78 }
79 if let Some(expires) = cookie.expires {
80 if let Some(dt) = chrono::DateTime::from_timestamp(expires as i64, 0) {
82 parts.push(format!("Expires={}", dt.format("%a, %d %b %Y %H:%M:%S GMT")));
83 }
84 }
85
86 parts.join("; ")
87}
88
89pub fn extract_from_jar(jar: &Arc<Jar>, url: &str) -> Vec<Cookie> {
93 let mut cookies = Vec::new();
94
95 if let Ok(parsed_url) = url::Url::parse(url) {
96 if let Some(cookie_header) = jar.cookies(&parsed_url) {
97 let header_str = cookie_header.to_str().unwrap_or("");
99 for cookie_str in header_str.split("; ") {
100 if let Some((name, value)) = cookie_str.split_once('=') {
101 cookies.push(Cookie {
102 name: name.to_string(),
103 value: value.to_string(),
104 domain: parsed_url.host_str().map(String::from),
105 path: Some(parsed_url.path().to_string()),
106 url: Some(url.to_string()),
107 expires: None,
108 http_only: None,
109 secure: Some(parsed_url.scheme() == "https"),
110 same_site: None,
111 });
112 }
113 }
114 }
115 }
116
117 cookies
118}
119
120#[cfg(test)]
121mod tests;