viz_core/middleware/
helper.rs

1//! Cookie helper.
2
3use std::time::Duration;
4
5use crate::types::{Cookie, Cookies, SameSite};
6
7/// Cookie's Options
8#[derive(Debug)]
9pub struct CookieOptions {
10    /// Cookie's `name`, `viz.sid` by defaults
11    pub name: &'static str,
12    /// Cookie's `path`, `/` by defaults
13    pub path: &'static str,
14    /// Cookie's `secure`, `true` by defaults
15    pub secure: bool,
16    /// Cookie's `http_only`, `true` by defaults
17    pub http_only: bool,
18    /// Cookie's maximum age, `24H` by defaults
19    pub max_age: Option<Duration>,
20    /// Cookie's `domain`
21    pub domain: Option<&'static str>,
22    /// Cookie's `same_site`, `Lax` by defaults
23    pub same_site: Option<SameSite>,
24}
25
26impl CookieOptions {
27    /// By default 24h for cookie.
28    pub const MAX_AGE: u64 = 3600 * 24;
29
30    /// Creates new `CookieOptions`
31    #[must_use]
32    pub fn new(name: &'static str) -> Self {
33        Self::default().name(name)
34    }
35
36    /// Creates new `CookieOptions` with `name`
37    #[must_use]
38    pub const fn name(mut self, name: &'static str) -> Self {
39        self.name = name;
40        self
41    }
42
43    /// Creates new `CookieOptions` with `max_age`
44    #[must_use]
45    pub fn max_age(mut self, max_age: Duration) -> Self {
46        self.max_age.replace(max_age);
47        self
48    }
49
50    /// Creates new `CookieOptions` with `domain`
51    #[must_use]
52    pub fn domain(mut self, domain: &'static str) -> Self {
53        self.domain.replace(domain);
54        self
55    }
56
57    /// Creates new `CookieOptions` with `path`
58    #[must_use]
59    pub const fn path(mut self, path: &'static str) -> Self {
60        self.path = path;
61        self
62    }
63
64    /// Creates new `CookieOptions` with `secure`
65    #[must_use]
66    pub const fn secure(mut self, secure: bool) -> Self {
67        self.secure = secure;
68        self
69    }
70
71    /// Creates new `CookieOptions` with `http_only`
72    #[must_use]
73    pub const fn http_only(mut self, http_only: bool) -> Self {
74        self.http_only = http_only;
75        self
76    }
77
78    /// Creates new `CookieOptions` with `same_site`
79    #[must_use]
80    pub fn same_site(mut self, same_site: SameSite) -> Self {
81        self.same_site.replace(same_site);
82        self
83    }
84
85    /// Converts self into a [Cookie].
86    ///
87    /// # Panics
88    ///
89    /// Will panic if `std::time::Duration` cannot be converted to `cookie::ime::Duration`
90    pub fn into_cookie(&self, value: impl Into<String>) -> Cookie<'_> {
91        let mut cookie = Cookie::new(self.name, value.into());
92
93        cookie.set_path(self.path);
94        cookie.set_secure(self.secure);
95        cookie.set_http_only(self.http_only);
96        cookie.set_same_site(self.same_site);
97
98        if let Some(domain) = self.domain {
99            cookie.set_domain(domain);
100        }
101        if let Some(max_age) = self.max_age {
102            cookie
103                .set_max_age(::cookie::time::Duration::try_from(max_age).expect(
104                    "`std::time::Duration` cannot be converted to `cookie::ime::Duration`",
105                ));
106        }
107
108        cookie
109    }
110}
111
112impl Default for CookieOptions {
113    fn default() -> Self {
114        Self {
115            domain: None,
116            secure: true,
117            http_only: true,
118            path: "/",
119            name: "viz.sid",
120            same_site: Some(SameSite::Lax),
121            max_age: Some(Duration::from_secs(Self::MAX_AGE)),
122        }
123    }
124}
125
126/// An interface for managing the cookies.
127#[cfg(not(feature = "cookie-private"))]
128pub trait Cookieable {
129    /// Gets the options of the cookie.
130    fn options(&self) -> &CookieOptions;
131
132    /// Gets a cookie from the cookies.
133    fn get_cookie<'a>(&'a self, cookies: &'a Cookies) -> Option<Cookie<'a>> {
134        cookies.get(self.options().name)
135    }
136
137    /// Deletes a cookie from the cookies.
138    fn remove_cookie<'a>(&'a self, cookies: &'a Cookies) {
139        cookies.remove(self.options().name);
140    }
141
142    /// Sets a cookie from the cookies.
143    fn set_cookie<'a>(&'a self, cookies: &'a Cookies, value: impl Into<String>) {
144        cookies.add(self.options().into_cookie(value));
145    }
146}
147
148/// An interface for managing the `private` cookies.
149#[cfg(feature = "cookie-private")]
150pub trait Cookieable {
151    /// Gets the options of the cookie.
152    fn options(&self) -> &CookieOptions;
153
154    /// Gets a cookie from the cookies.
155    fn get_cookie<'a>(&'a self, cookies: &'a Cookies) -> Option<Cookie<'a>> {
156        cookies.private_get(self.options().name)
157    }
158
159    /// Deletes a cookie from the cookies.
160    fn remove_cookie<'a>(&'a self, cookies: &'a Cookies) {
161        cookies.private_remove(self.options().name);
162    }
163
164    /// Sets a cookie from the cookies.
165    fn set_cookie<'a>(&'a self, cookies: &'a Cookies, value: impl Into<String>) {
166        cookies.private_add(self.options().into_cookie(value));
167    }
168}