diff --git a/Cargo.toml b/Cargo.toml index c12075685..a25f2a96e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ futures = "0.1" tokio-io = "0.1" tokio-core = "0.1" redis-async = "0.0" +time = "0.1" # actix web session actix-web = { version="0.6", optional=true } diff --git a/src/lib.rs b/src/lib.rs index 71a2c86a9..52cb761f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ extern crate log; extern crate redis_async; #[macro_use] extern crate failure; +extern crate time; mod redis; pub use redis::{Command, RedisActor}; diff --git a/src/session.rs b/src/session.rs index 011f1ad58..77e41d69f 100644 --- a/src/session.rs +++ b/src/session.rs @@ -6,13 +6,14 @@ use actix::prelude::*; use actix_web::middleware::session::{SessionBackend, SessionImpl}; use actix_web::middleware::Response as MiddlewareResponse; use actix_web::{error, Error, HttpRequest, HttpResponse, Result}; -use cookie::{Cookie, CookieJar, Key}; +use cookie::{Cookie, CookieJar, Key, SameSite}; use futures::future::{err as FutErr, ok as FutOk, Either}; use futures::Future; use http::header::{self, HeaderValue}; use rand::{self, Rng}; use redis_async::resp::RespValue; use serde_json; +use time::Duration; use redis::{Command, RedisActor}; @@ -79,6 +80,11 @@ impl RedisSessionBackend { ttl: "7200".to_owned(), addr: RedisActor::start(addr), name: "actix-session".to_owned(), + path: "/".to_owned(), + domain: None, + secure: false, + max_age: Some(Duration::days(7)), + same_site: None, })) } @@ -93,6 +99,38 @@ impl RedisSessionBackend { Rc::get_mut(&mut self.0).unwrap().name = name.to_owned(); self } + + /// Set custom cookie path + pub fn cookie_path(mut self, path: &str) -> Self { + Rc::get_mut(&mut self.0).unwrap().path = path.to_owned(); + self + } + + /// Set custom cookie domain + pub fn cookie_domain(mut self, domain: &str) -> Self { + Rc::get_mut(&mut self.0).unwrap().domain = Some(domain.to_owned()); + self + } + + /// Set custom cookie secure + /// If the `secure` field is set, a cookie will only be transmitted when the + /// connection is secure - i.e. `https` + pub fn cookie_secure(mut self, secure: bool) -> Self { + Rc::get_mut(&mut self.0).unwrap().secure = secure; + self + } + + /// Set custom cookie max-age + pub fn cookie_max_age(mut self, max_age: Duration) -> Self { + Rc::get_mut(&mut self.0).unwrap().max_age = Some(max_age); + self + } + + /// Set custom cookie SameSite + pub fn cookie_same_site(mut self, same_site: SameSite) -> Self { + Rc::get_mut(&mut self.0).unwrap().same_site = Some(same_site); + self + } } impl SessionBackend for RedisSessionBackend { @@ -125,8 +163,13 @@ impl SessionBackend for RedisSessionBackend { struct Inner { key: Key, ttl: String, - name: String, addr: Addr, + name: String, + path: String, + domain: Option, + secure: bool, + max_age: Option, + same_site: Option, } impl Inner { @@ -197,9 +240,22 @@ impl Inner { let value = String::from_iter(rng.gen_ascii_chars().take(32)); let mut cookie = Cookie::new(self.name.clone(), value.clone()); - cookie.set_path("/"); + cookie.set_path(self.path.clone()); + cookie.set_secure(self.secure); cookie.set_http_only(true); + if let Some(ref domain) = self.domain { + cookie.set_domain(domain.clone()); + } + + if let Some(max_age) = self.max_age { + cookie.set_max_age(max_age); + } + + if let Some(same_site) = self.same_site { + cookie.set_same_site(same_site); + } + // set cookie let mut jar = CookieJar::new(); jar.signed(&self.key).add(cookie);