84 lines
2.3 KiB
Rust
84 lines
2.3 KiB
Rust
|
use std::convert::TryFrom;
|
||
|
use std::future::{ready, Ready};
|
||
|
use std::time::{Duration, SystemTime};
|
||
|
|
||
|
use actix_web::dev::Payload;
|
||
|
use actix_web::http::header::LOCATION;
|
||
|
use actix_web::http::Uri;
|
||
|
use actix_web::{FromRequest, HttpRequest, HttpResponse};
|
||
|
use lettre::EmailAddress;
|
||
|
use rand::{thread_rng, Fill};
|
||
|
|
||
|
pub struct Session(actix_session::Session);
|
||
|
|
||
|
impl FromRequest for Session {
|
||
|
type Config = <actix_session::Session as FromRequest>::Config;
|
||
|
type Error = <actix_session::Session as FromRequest>::Error;
|
||
|
type Future = Ready<Result<Self, Self::Error>>;
|
||
|
|
||
|
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
||
|
ready(
|
||
|
actix_session::Session::from_request(req, payload)
|
||
|
.into_inner()
|
||
|
.map(Self),
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl Session {
|
||
|
pub fn init(&self, email: &EmailAddress) {
|
||
|
self.0.clear();
|
||
|
self.0
|
||
|
.insert("email", email)
|
||
|
.expect("email serialization to work");
|
||
|
let mut buf: [u8; 32] = [0; 32];
|
||
|
buf.try_fill(&mut thread_rng()).expect("rng to fill buf");
|
||
|
self.0
|
||
|
.insert(
|
||
|
"expires",
|
||
|
SystemTime::now() + Duration::from_secs(60 * 60 * 24),
|
||
|
)
|
||
|
.expect("setting expiration to work");
|
||
|
}
|
||
|
|
||
|
pub fn purge(&self) {
|
||
|
self.0.purge();
|
||
|
}
|
||
|
|
||
|
pub fn validate_or_redirect(&self, redirect_to: &Uri) -> Result<(), HttpResponse> {
|
||
|
if self.expired() {
|
||
|
self.0.clear();
|
||
|
self.set_redirect_url(redirect_to);
|
||
|
Err(HttpResponse::SeeOther()
|
||
|
.insert_header((LOCATION, "/login"))
|
||
|
.finish())
|
||
|
} else {
|
||
|
Ok(())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn expired(&self) -> bool {
|
||
|
self.0
|
||
|
.get("expires")
|
||
|
.ok()
|
||
|
.flatten()
|
||
|
.map_or(true, |expires: SystemTime| expires < SystemTime::now())
|
||
|
}
|
||
|
|
||
|
pub fn get_redirect_url(&self) -> Option<Uri> {
|
||
|
self.0
|
||
|
.remove("redirect_to")
|
||
|
.and_then(|v| Uri::try_from(&v).ok())
|
||
|
}
|
||
|
|
||
|
pub fn set_redirect_url(&self, url: &Uri) {
|
||
|
self.0
|
||
|
.insert("redirect_to", url.to_string())
|
||
|
.expect("setting a str to work");
|
||
|
}
|
||
|
|
||
|
pub fn email(&self) -> Option<EmailAddress> {
|
||
|
self.0.get("email").ok().flatten()
|
||
|
}
|
||
|
}
|