From b28008bc97a7fbc9d4e7b6eac2c06d8e91e1fb16 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 23 Nov 2019 16:10:04 -0500 Subject: start working on the login flow --- teleterm/src/web.rs | 19 ++++++++ teleterm/src/web/disk_session.rs | 99 ++++++++++++++++++++++++++++++++++++++++ teleterm/src/web/list.rs | 13 ++++++ teleterm/src/web/login.rs | 26 +++++++++++ teleterm/src/web/watch.rs | 13 ++++++ 5 files changed, 170 insertions(+) create mode 100644 teleterm/src/web/disk_session.rs create mode 100644 teleterm/src/web/login.rs (limited to 'teleterm/src') diff --git a/teleterm/src/web.rs b/teleterm/src/web.rs index 992b79d..07ece12 100644 --- a/teleterm/src/web.rs +++ b/teleterm/src/web.rs @@ -1,4 +1,6 @@ +mod disk_session; mod list; +mod login; mod view; mod watch; mod ws; @@ -15,6 +17,11 @@ struct Config { public_address: String, } +#[derive(Default, serde::Deserialize, serde::Serialize)] +struct SessionData { + username: Option, +} + pub struct Server { server: Box + Send>, } @@ -54,6 +61,14 @@ fn router(data: &Config) -> impl gotham::handler::NewHandler { .add(gotham::middleware::state::StateMiddleware::new( data.clone(), )) + .add( + gotham::middleware::session::NewSessionMiddleware::new( + disk_session::DiskSession, + ) + .insecure() + .with_cookie_name("teleterm") + .with_session_type::(), + ) .build(), ); gotham::router::builder::build_router(chain, pipeline, |route| { @@ -75,6 +90,10 @@ fn router(data: &Config) -> impl gotham::handler::NewHandler { .get("/watch") .with_query_string_extractor::() .to(watch::run); + route + .get("/login") + .with_query_string_extractor::() + .to(login::run); }) } diff --git a/teleterm/src/web/disk_session.rs b/teleterm/src/web/disk_session.rs new file mode 100644 index 0000000..423bcd0 --- /dev/null +++ b/teleterm/src/web/disk_session.rs @@ -0,0 +1,99 @@ +use crate::prelude::*; + +use std::io::Write as _; + +#[derive(Clone)] +pub struct DiskSession; + +impl DiskSession { + fn file_for_id( + &self, + identifier: &gotham::middleware::session::SessionIdentifier, + should_exist: bool, + ) -> Option { + let name = format!("web-{}", identifier.value); + crate::dirs::Dirs::new().data_file(&name, should_exist) + } +} + +impl gotham::middleware::session::NewBackend for DiskSession { + type Instance = Self; + + fn new_backend(&self) -> std::io::Result { + Ok(Self) + } +} + +impl gotham::middleware::session::Backend for DiskSession { + fn persist_session( + &self, + identifier: gotham::middleware::session::SessionIdentifier, + content: &[u8], + ) -> std::result::Result<(), gotham::middleware::session::SessionError> + { + let filename = self.file_for_id(&identifier, false).unwrap(); + let mut file = std::fs::File::create(filename).map_err(|e| { + gotham::middleware::session::SessionError::Backend(format!( + "{}", + e + )) + })?; + file.write_all(content).map_err(|e| { + gotham::middleware::session::SessionError::Backend(format!( + "{}", + e + )) + })?; + file.sync_all().map_err(|e| { + gotham::middleware::session::SessionError::Backend(format!( + "{}", + e + )) + })?; + Ok(()) + } + + fn read_session( + &self, + identifier: gotham::middleware::session::SessionIdentifier, + ) -> Box< + dyn futures::Future< + Item = Option>, + Error = gotham::middleware::session::SessionError, + > + Send, + > { + if let Some(filename) = self.file_for_id(&identifier, true) { + Box::new( + tokio::fs::File::open(filename) + .and_then(|file| { + let buf = vec![]; + tokio::io::read_to_end(file, buf) + }) + .map(|(_, v)| Some(v)) + .map_err(|e| { + gotham::middleware::session::SessionError::Backend( + format!("{}", e), + ) + }), + ) + } else { + Box::new(futures::future::ok(None)) + } + } + + fn drop_session( + &self, + identifier: gotham::middleware::session::SessionIdentifier, + ) -> std::result::Result<(), gotham::middleware::session::SessionError> + { + if let Some(filename) = self.file_for_id(&identifier, true) { + std::fs::remove_file(filename).map_err(|e| { + gotham::middleware::session::SessionError::Backend(format!( + "{}", + e + )) + })?; + } + Ok(()) + } +} diff --git a/teleterm/src/web/list.rs b/teleterm/src/web/list.rs index 9c1bcc6..0906f82 100644 --- a/teleterm/src/web/list.rs +++ b/teleterm/src/web/list.rs @@ -5,6 +5,19 @@ use gotham::state::FromState as _; pub fn run( state: gotham::state::State, ) -> (gotham::state::State, hyper::Response) { + let session = gotham::middleware::session::SessionData::< + crate::web::SessionData, + >::borrow_from(&state); + if session.username.is_none() { + return ( + state, + hyper::Response::builder() + .status(hyper::StatusCode::FORBIDDEN) + .body(hyper::Body::empty()) + .unwrap(), + ); + } + let config = crate::web::Config::borrow_from(&state); let (_, address) = config.server_address; diff --git a/teleterm/src/web/login.rs b/teleterm/src/web/login.rs new file mode 100644 index 0000000..a678b95 --- /dev/null +++ b/teleterm/src/web/login.rs @@ -0,0 +1,26 @@ +use gotham::state::FromState as _; + +#[derive( + serde::Deserialize, + gotham_derive::StateData, + gotham_derive::StaticResponseExtender, +)] +pub struct QueryParams { + username: Option, +} + +pub fn run( + mut state: gotham::state::State, +) -> (gotham::state::State, hyper::Response) { + let username = { + let query_params = QueryParams::borrow_from(&state); + query_params.username.clone() + }; + let session = gotham::middleware::session::SessionData::< + crate::web::SessionData, + >::borrow_mut_from(&mut state); + + session.username = username; + + (state, hyper::Response::new(hyper::Body::from("{}"))) +} diff --git a/teleterm/src/web/watch.rs b/teleterm/src/web/watch.rs index 720e9f8..74a59dd 100644 --- a/teleterm/src/web/watch.rs +++ b/teleterm/src/web/watch.rs @@ -15,6 +15,19 @@ pub struct QueryParams { pub fn run( mut state: gotham::state::State, ) -> (gotham::state::State, hyper::Response) { + let session = gotham::middleware::session::SessionData::< + crate::web::SessionData, + >::borrow_from(&state); + if session.username.is_none() { + return ( + state, + hyper::Response::builder() + .status(hyper::StatusCode::FORBIDDEN) + .body(hyper::Body::empty()) + .unwrap(), + ); + } + let body = hyper::Body::take_from(&mut state); let headers = hyper::HeaderMap::take_from(&mut state); let config = crate::web::Config::borrow_from(&state); -- cgit v1.2.3-54-g00ecf