use std::time::Duration;
use crate::web::cookie::{Cookie, CookieJar, CookieKey, SameSite};
pub enum CookieSecurity {
Plain,
Private(CookieKey),
Signed(CookieKey),
}
pub struct CookieConfig {
security: CookieSecurity,
name: String,
path: String,
domain: Option<String>,
secure: bool,
http_only: bool,
max_age: Option<Duration>,
same_site: Option<SameSite>,
partitioned: bool,
}
impl Default for CookieConfig {
fn default() -> Self {
Self {
security: CookieSecurity::Plain,
name: "poem-session".to_string(),
path: "/".to_string(),
domain: None,
secure: true,
http_only: true,
max_age: None,
same_site: None,
partitioned: false,
}
}
}
impl CookieConfig {
pub fn new() -> Self {
Default::default()
}
pub fn private(key: CookieKey) -> Self {
Self {
security: CookieSecurity::Private(key),
..Default::default()
}
}
pub fn signed(key: CookieKey) -> Self {
Self {
security: CookieSecurity::Signed(key),
..Default::default()
}
}
#[must_use]
pub fn name(self, value: impl Into<String>) -> Self {
Self {
name: value.into(),
..self
}
}
#[must_use]
pub fn path(self, value: impl Into<String>) -> Self {
Self {
path: value.into(),
..self
}
}
#[must_use]
pub fn domain(self, value: impl Into<String>) -> Self {
Self {
domain: Some(value.into()),
..self
}
}
#[must_use]
pub fn secure(self, value: bool) -> Self {
Self {
secure: value,
..self
}
}
#[must_use]
pub fn http_only(self, value: bool) -> Self {
Self {
http_only: value,
..self
}
}
#[must_use]
pub fn same_site(self, value: impl Into<Option<SameSite>>) -> Self {
Self {
same_site: value.into(),
..self
}
}
#[must_use]
pub fn partitioned(self, value: bool) -> Self {
Self {
partitioned: value,
..self
}
}
#[must_use]
pub fn max_age(self, value: impl Into<Option<Duration>>) -> Self {
Self {
max_age: value.into(),
..self
}
}
#[inline]
pub(crate) fn ttl(&self) -> Option<Duration> {
self.max_age
}
pub fn set_cookie_value(&self, cookie_jar: &CookieJar, value: &str) {
let mut cookie = Cookie::new_with_str(&self.name, value);
cookie.set_path(&self.path);
if let Some(domain) = &self.domain {
cookie.set_domain(domain);
}
cookie.set_secure(self.secure);
cookie.set_http_only(self.http_only);
if let Some(max_age) = &self.max_age {
cookie.set_max_age(*max_age);
}
cookie.set_same_site(self.same_site);
cookie.set_partitioned(self.partitioned);
match &self.security {
CookieSecurity::Plain => cookie_jar.add(cookie),
CookieSecurity::Private(key) => cookie_jar.private_with_key(key).add(cookie),
CookieSecurity::Signed(key) => cookie_jar.signed_with_key(key).add(cookie),
}
}
pub fn remove_cookie(&self, cookie_jar: &CookieJar) {
match &self.security {
CookieSecurity::Plain => cookie_jar.remove(&self.name),
CookieSecurity::Private(key) => cookie_jar.private_with_key(key).remove(&self.name),
CookieSecurity::Signed(key) => cookie_jar.signed_with_key(key).remove(&self.name),
}
}
pub fn get_cookie_value(&self, cookie_jar: &CookieJar) -> Option<String> {
let cookie = match &self.security {
CookieSecurity::Plain => cookie_jar.get(&self.name),
CookieSecurity::Private(key) => cookie_jar.private_with_key(key).get(&self.name),
CookieSecurity::Signed(key) => cookie_jar.signed_with_key(key).get(&self.name),
};
cookie.map(|cookie| cookie.value_str().to_string())
}
}