decrypt_cookies/browser/
cookies.rs1use std::fmt::Display;
2
3use chrono::{DateTime, Utc};
4
5#[derive(Default, Clone)]
6#[derive(Debug)]
7#[derive(PartialEq, Eq, PartialOrd, Ord)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub struct LeetCodeCookies {
10 pub csrf: String,
11 pub session: String,
12 #[cfg_attr(feature = "serde", serde(skip))]
13 pub expiry: bool,
14}
15
16impl LeetCodeCookies {
17 pub fn is_completion(&self) -> bool {
18 !(self.expiry || self.csrf.is_empty() || self.session.is_empty())
19 }
20}
21
22impl Display for LeetCodeCookies {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 f.write_fmt(format_args!(
25 "LEETCODE_SESSION={};csrftoken={};",
26 self.session, self.csrf
27 ))
28 }
29}
30
31pub trait CookiesInfo {
32 fn csv_header<D: Display>(sep: D) -> String {
33 format!("domain{sep}name{sep}path{sep}value{sep}creation{sep}expires{sep}is_secure{sep}is_http_only")
34 }
35
36 fn to_csv<D: Display>(&self, sep: D) -> String {
37 format!(
38 "{}{sep}{}{sep}{}{sep}{}{sep}{}{sep}{}{sep}{}{sep}{}",
39 self.domain(),
40 self.name(),
41 self.path(),
42 self.value(),
43 self.creation().unwrap_or_default(),
44 self.expires().unwrap_or_default(),
45 self.is_secure(),
46 self.is_http_only(),
47 )
48 }
49
50 fn set_cookie_header(&self) -> String {
52 let mut properties = vec![
53 format!("{}={}", self.name(), self.value()),
54 format!("Path={}", self.path()),
55 ];
56 if !self.name().starts_with("__Host-") {
57 properties.push(format!("Domain={}", self.domain()));
58 }
59 if let Some(expiry) = self.expiry() {
60 properties.push(format!("Expires={}", expiry));
61 }
62 if self.is_secure() {
63 properties.push("Secure".to_owned());
64 }
65 if self.is_http_only() {
66 properties.push("HttpOnly".to_owned());
67 }
68 properties.push(format!("SameSite={}", self.same_site()));
69
70 properties.join("; ")
71 }
72
73 fn url(&self) -> String {
75 format!("https://{}{}", self.domain().trim_matches('.'), self.path())
76 }
77
78 fn name(&self) -> &str;
79 fn value(&self) -> &str;
80 fn path(&self) -> &str;
81 fn domain(&self) -> &str;
82 fn expiry(&self) -> Option<String>;
83 fn is_secure(&self) -> bool;
84 fn is_http_only(&self) -> bool;
85 fn same_site(&self) -> SameSite;
86 fn creation(&self) -> Option<DateTime<Utc>>;
87 fn expires(&self) -> Option<DateTime<Utc>>;
88}
89
90#[derive(Clone, Copy)]
91#[derive(Debug)]
92#[derive(Default)]
93#[derive(PartialEq, Eq, PartialOrd, Ord)]
94#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
95pub enum SameSite {
96 #[default]
97 None = 0,
98 Lax = 1,
99 Strict = 2,
100}
101
102impl From<i32> for SameSite {
103 fn from(value: i32) -> Self {
104 #[expect(clippy::wildcard_in_or_patterns, reason = "this is more clear")]
105 match value {
106 1 => Self::Lax,
107 2 => Self::Strict,
108 0 | _ => Self::None,
109 }
110 }
111}
112
113#[cfg(feature = "Safari")]
114impl From<binary_cookies::cookie::SameSite> for SameSite {
115 fn from(value: binary_cookies::cookie::SameSite) -> Self {
116 match value {
117 binary_cookies::cookie::SameSite::None => Self::None,
118 binary_cookies::cookie::SameSite::Lax => Self::Lax,
119 binary_cookies::cookie::SameSite::Strict => Self::Strict,
120 }
121 }
122}
123
124impl From<Option<i32>> for SameSite {
125 fn from(value: Option<i32>) -> Self {
126 value.unwrap_or_default().into()
127 }
128}
129
130impl Display for SameSite {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 match self {
133 Self::None => "None",
134 Self::Lax => "Lax",
135 Self::Strict => "Strict",
136 }
137 .fmt(f)
138 }
139}