Separate session store module
This commit is contained in:
parent
4fcf745b3b
commit
b4028fa08f
@ -7,6 +7,7 @@ mod demo;
|
|||||||
mod feed_utils;
|
mod feed_utils;
|
||||||
mod feeds;
|
mod feeds;
|
||||||
mod poll;
|
mod poll;
|
||||||
|
mod session_store;
|
||||||
mod user;
|
mod user;
|
||||||
|
|
||||||
use rocket::fairing::{self, AdHoc};
|
use rocket::fairing::{self, AdHoc};
|
||||||
@ -15,6 +16,7 @@ use rocket::response::Redirect;
|
|||||||
use rocket::{Build, Rocket, State};
|
use rocket::{Build, Rocket, State};
|
||||||
use rocket_db_pools::{sqlx, Connection, Database};
|
use rocket_db_pools::{sqlx, Connection, Database};
|
||||||
use rocket_dyn_templates::{context, Template};
|
use rocket_dyn_templates::{context, Template};
|
||||||
|
use session_store::SessionStore;
|
||||||
use user::AuthenticatedUser;
|
use user::AuthenticatedUser;
|
||||||
|
|
||||||
/// RSS Reader application
|
/// RSS Reader application
|
||||||
@ -136,7 +138,7 @@ fn rocket() -> _ {
|
|||||||
.attach(Template::fairing())
|
.attach(Template::fairing())
|
||||||
.attach(Db::init())
|
.attach(Db::init())
|
||||||
.manage(args.demo)
|
.manage(args.demo)
|
||||||
.manage(user::SessionStore::new())
|
.manage(SessionStore::new())
|
||||||
.attach(AdHoc::try_on_ignite("DB Setup", move |rocket| async move {
|
.attach(AdHoc::try_on_ignite("DB Setup", move |rocket| async move {
|
||||||
setup_database(args.demo, rocket).await
|
setup_database(args.demo, rocket).await
|
||||||
}))
|
}))
|
||||||
|
44
src/session_store.rs
Normal file
44
src/session_store.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::sync::RwLock;
|
||||||
|
use uuid::Uuid;
|
||||||
|
use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
|
||||||
|
|
||||||
|
pub struct SessionStore(RwLock<HashMap<Uuid, HashSet<String>>>);
|
||||||
|
|
||||||
|
impl SessionStore {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
SessionStore(RwLock::new(HashMap::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_secret() -> String {
|
||||||
|
let mut bytes = [0u8; 32];
|
||||||
|
getrandom::getrandom(&mut bytes).expect("Failed to generate random bytes");
|
||||||
|
BASE64.encode(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn store(&self, user_id: Uuid, secret: String) {
|
||||||
|
let mut store = self.0.write().unwrap();
|
||||||
|
store
|
||||||
|
.entry(user_id)
|
||||||
|
.or_insert_with(HashSet::new)
|
||||||
|
.insert(secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(&self, user_id: Uuid, secret: &str) -> bool {
|
||||||
|
let store = self.0.read().unwrap();
|
||||||
|
store
|
||||||
|
.get(&user_id)
|
||||||
|
.map_or(false, |secrets| secrets.contains(secret))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&self, user_id: Uuid, secret: &str) {
|
||||||
|
let mut store = self.0.write().unwrap();
|
||||||
|
if let Some(secrets) = store.get_mut(&user_id) {
|
||||||
|
secrets.remove(secret);
|
||||||
|
// Clean up the user entry if no sessions remain
|
||||||
|
if secrets.is_empty() {
|
||||||
|
store.remove(&user_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
src/user.rs
44
src/user.rs
@ -1,56 +1,14 @@
|
|||||||
use time::Duration;
|
use time::Duration;
|
||||||
|
|
||||||
use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
|
|
||||||
use rocket::http::{Cookie, CookieJar, Status};
|
use rocket::http::{Cookie, CookieJar, Status};
|
||||||
use rocket::serde::{json::Json, Deserialize, Serialize};
|
use rocket::serde::{json::Json, Deserialize, Serialize};
|
||||||
use rocket::State;
|
use rocket::State;
|
||||||
use rocket_db_pools::Connection;
|
use rocket_db_pools::Connection;
|
||||||
use rocket_dyn_templates::{context, Template};
|
use rocket_dyn_templates::{context, Template};
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
use std::sync::RwLock;
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::Db;
|
use crate::Db;
|
||||||
|
use crate::session_store::SessionStore;
|
||||||
pub struct SessionStore(RwLock<HashMap<Uuid, HashSet<String>>>);
|
|
||||||
|
|
||||||
impl SessionStore {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
SessionStore(RwLock::new(HashMap::new()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_secret() -> String {
|
|
||||||
let mut bytes = [0u8; 32];
|
|
||||||
getrandom::getrandom(&mut bytes).expect("Failed to generate random bytes");
|
|
||||||
BASE64.encode(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn store(&self, user_id: Uuid, secret: String) {
|
|
||||||
let mut store = self.0.write().unwrap();
|
|
||||||
store
|
|
||||||
.entry(user_id)
|
|
||||||
.or_insert_with(HashSet::new)
|
|
||||||
.insert(secret);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn verify(&self, user_id: Uuid, secret: &str) -> bool {
|
|
||||||
let store = self.0.read().unwrap();
|
|
||||||
store
|
|
||||||
.get(&user_id)
|
|
||||||
.map_or(false, |secrets| secrets.contains(secret))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove(&self, user_id: Uuid, secret: &str) {
|
|
||||||
let mut store = self.0.write().unwrap();
|
|
||||||
if let Some(secrets) = store.get_mut(&user_id) {
|
|
||||||
secrets.remove(secret);
|
|
||||||
// Clean up the user entry if no sessions remain
|
|
||||||
if secrets.is_empty() {
|
|
||||||
store.remove(&user_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(crate = "rocket::serde")]
|
#[serde(crate = "rocket::serde")]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user