From d24af144fa18e4472e08a9e533589497a261f148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Tue, 31 Dec 2019 01:37:13 +0100 Subject: [PATCH] implement cookie based polymorphic session --- Cargo.lock | 74 +++++++++++++++++ Cargo.toml | 1 + src/main.rs | 19 ++++- src/session.rs | 168 ++++++++++++++++++++++++++++++++++++++ templates/index.html.tera | 2 + 5 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 src/session.rs diff --git a/Cargo.lock b/Cargo.lock index ed77eb7..b329b7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,6 +101,14 @@ name = "byteorder" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "c2-chacha" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cc" version = "1.0.48" @@ -249,6 +257,16 @@ dependencies = [ "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "getrandom" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "glob" version = "0.2.11" @@ -653,6 +671,11 @@ dependencies = [ "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ppv-lite86" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "proc-macro-hack" version = "0.5.11" @@ -695,6 +718,43 @@ dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_syscall" version = "0.1.56" @@ -766,6 +826,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rocket 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rocket_contrib 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1140,6 +1201,11 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasi" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.2.8" @@ -1218,6 +1284,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" @@ -1237,6 +1304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" "checksum hermit-abi 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f629dc602392d3ec14bfc8a09b5e644d7ffd725102b48b81e59f90f2633621d7" @@ -1285,11 +1353,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" "checksum pest_generator 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9fcf299b5712d06ee128a556c94709aaa04512c4dffb8ead07c5c998447fc0" "checksum pest_meta 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df43fd99896fd72c485fe47542c7b500e4ac1e8700bf995544d1317a60ded547" +"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" +"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" @@ -1342,6 +1415,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index 0dc1062..7fe3f34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ serde_json = { version="1.0", features= ["preserve_order"] } serde_yaml = "0.8.11" json_dotpath = "0.1.2" titlecase = "0.10.0" +rand = "0.7.2" # special data structure that preserves order indexmap = { version="1.3.0", features=["serde-1"] } diff --git a/src/main.rs b/src/main.rs index 3abad41..c4cdde0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ use rocket_contrib::serve::StaticFiles; use rocket_contrib::templates::Template; mod store; +mod session; use crate::store::form::{render_card_fields, render_empty_fields, RenderedCard, RenderedField, MapFromForm, collect_card_form}; use crate::store::Store; @@ -20,8 +21,9 @@ use parking_lot::RwLock; use rocket::request::Form; use rocket::response::Redirect; -use rocket::State; +use rocket::{State, Request}; use std::env; +use crate::session::{SessionID, SessionStore, Session}; #[derive(Serialize, Debug)] pub struct ListContext<'a> { @@ -29,6 +31,7 @@ pub struct ListContext<'a> { pub cards: Vec>, pub page: usize, pub pages: usize, + pub count : usize, } const PER_PAGE: usize = 20; // TODO configurable @@ -48,9 +51,19 @@ fn find_page_with_card(store: &Store, card_id: usize) -> Option { } #[get("/?")] -fn route_index(store: State>, page: Option) -> Template { +fn route_index( + store: State>, + session : Session, + page: Option +) -> Template { let rg = store.read(); + let mut count : usize = session.get_or_default("foo.bar.count"); + count += 1; + session.set("foo.bar.count", count); + + println!("{:?}", session); + let mut page = page.unwrap_or_default(); let n_pages = (rg.data.cards.len() as f64 / PER_PAGE as f64).ceil() as usize; @@ -62,6 +75,7 @@ fn route_index(store: State>, page: Option) -> Template { fields: render_empty_fields(&rg), pages: n_pages, page, + count, cards: rg .data .cards @@ -174,6 +188,7 @@ fn main() { rocket::ignite() .attach(Template::fairing()) + .attach(Session::fairing()) .manage(RwLock::new(store)) .mount("/", StaticFiles::from(cwd.join("templates/static/"))) .mount( diff --git a/src/session.rs b/src/session.rs new file mode 100644 index 0000000..260cbd6 --- /dev/null +++ b/src/session.rs @@ -0,0 +1,168 @@ +use rocket::request::FromRequest; +use rocket::{Outcome, Request, State, http::{Status, Cookies, Cookie}, Response, Data, Rocket}; +use std::ops::{Deref, DerefMut}; +use std::collections::HashMap; +use parking_lot::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use serde_json::{Value, Map}; +use rocket::fairing::{self, Fairing, Info}; +use rand::Rng; +use std::borrow::Cow; +use serde::{Deserialize, Serialize}; +use serde::de::DeserializeOwned; +use json_dotpath::DotPaths; +use rocket::response::ResponseBuilder; + +const SESSION_ID : &'static str = "SESSID"; + +type SessionsMap = HashMap; + +#[derive(Debug)] +struct SessionInstance { + data: serde_json::Map, + // TODO expiration +} + +#[derive(Default, Debug)] +pub struct SessionStore { + inner: RwLock, +} + +#[derive(PartialEq, Hash, Clone, Debug)] +pub struct SessionID(String); + +impl<'a, 'r> FromRequest<'a, 'r> for &'a SessionID { + type Error = (); + + fn from_request(request: &'a Request<'r>) -> Outcome { + Outcome::Success(request.local_cache(|| { + println!("get id"); + if let Some(cookie) = request.cookies().get(SESSION_ID) { + println!("from cookie"); + SessionID(cookie.value().to_string()) // FIXME avoid cloning + } else { + println!("new id"); + SessionID(rand::thread_rng() + .sample_iter(&rand::distributions::Alphanumeric) + .take(16) + .collect()) + } + })) + } +} + +#[derive(Debug)] +pub struct Session<'a> { + store: State<'a, SessionStore>, + id : &'a SessionID, +} + +impl<'a, 'r> FromRequest<'a, 'r> for Session<'a> { + type Error = (); + + fn from_request(request: &'a Request<'r>) -> Outcome { + Outcome::Success(Session { + id: request.local_cache(|| { + if let Some(cookie) = request.cookies().get(SESSION_ID) { + SessionID(cookie.value().to_string()) + } else { + SessionID(rand::thread_rng() + .sample_iter(&rand::distributions::Alphanumeric) + .take(16) + .collect()) + } + }), + store: request.guard().unwrap() + }) + } +} + +impl<'a> Session<'a> { + pub fn fairing() -> impl Fairing { + SessionFairing + } + + pub fn get(&self, path : &str) -> Option { + let rg = self.store.inner.read(); + if let Some(ses) = rg.get(&self.id.0) { + ses.data.dot_get(path) + } else { + None + } + } + + pub fn get_or(&self, path : &str, def : T) -> T { + self.get(path).unwrap_or(def) + } + + pub fn get_or_else T>(&self, path : &str, def : F) -> T { + self.get(path).unwrap_or_else(def) + } + + pub fn get_or_default(&self, path : &str) -> T { + self.get(path).unwrap_or_default() + } + + pub fn take(&self, path : &str) -> Option { + let mut wg = self.store.inner.write(); + if let Some(ses) = wg.get_mut(&self.id.0) { + ses.data.dot_take(path) + } else { + None + } + } + + pub fn replace(&self, path : &str, new : N) -> Option { + let mut wg = self.store.inner.write(); + if let Some(ses) = wg.get_mut(&self.id.0) { + ses.data.dot_replace(path, new) + } else { + None + } + } + + pub fn set(&self, path : &str, value : T) { + let mut wg = self.store.inner.write(); + if let Some(ses) = wg.get_mut(&self.id.0) { + ses.data.dot_set(path, value); + } else { + let mut map = Map::new(); + map.dot_set(path, value); + wg.insert(self.id.0.clone(), SessionInstance { + data : map, + }); + } + } + + pub fn remove(&self, path : &str) { + let mut wg = self.store.inner.write(); + if let Some(ses) = wg.get_mut(&self.id.0) { + ses.data.dot_remove(path); + } + } +} + +/// Fairing struct +struct SessionFairing; + +impl Fairing for SessionFairing { + fn info(&self) -> Info { + Info { + name: "Session Fairing", + kind: fairing::Kind::Attach | fairing::Kind::Response + } + } + + fn on_attach(&self, rocket: Rocket) -> Result { + Ok(rocket.manage(SessionStore::default())) + } + + fn on_response<'r>(&self, request: &'r Request, response: &mut Response) { + let session = request.local_cache(|| { + SessionID("".to_string()) + }); + + if !session.0.is_empty() { + response.adjoin_header(Cookie::build(SESSION_ID, session.0.clone()).finish()); + } + } +} diff --git a/templates/index.html.tera b/templates/index.html.tera index 7358593..85d0ea3 100644 --- a/templates/index.html.tera +++ b/templates/index.html.tera @@ -11,6 +11,8 @@ {%- endblock %} {% block content -%} +COUNT {{count}} +