From fec653ac7d5208ab5e6e57e90f1f1e89343a191f Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Tue, 26 Nov 2019 12:04:11 -0500 Subject: make plain logins also hit the server this also provides a foundation for how to handle oauth logins --- teleterm/src/web/login.rs | 134 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 5 deletions(-) diff --git a/teleterm/src/web/login.rs b/teleterm/src/web/login.rs index 876cebe..9c1d869 100644 --- a/teleterm/src/web/login.rs +++ b/teleterm/src/web/login.rs @@ -1,3 +1,5 @@ +use crate::prelude::*; + use gotham::state::FromState as _; #[derive( @@ -21,19 +23,141 @@ pub fn run( let query_params = QueryParams::borrow_from(&state); query_params.username.clone() }; + let username = if let Some(username) = username { + username + } else { + return ( + state, + hyper::Response::builder() + .status(hyper::StatusCode::BAD_REQUEST) + .body(hyper::Body::empty()) + .unwrap(), + ); + }; + + let config = crate::web::Config::borrow_from(&state); + + let (_, address) = config.server_address; + let connector: crate::client::Connector<_> = Box::new(move || { + Box::new( + tokio::net::tcp::TcpStream::connect(&address) + .context(crate::error::Connect { address }), + ) + }); + let auth = crate::protocol::Auth::plain(&username); + let client = crate::client::Client::raw("teleterm-web", connector, &auth); + + let (w_login, r_login) = tokio::sync::oneshot::channel(); + + tokio::spawn( + Client::new(client, auth, w_login) + // XXX if this happens, we might not have sent anything on the + // channel, and so the wait might block forever + .map_err(|e| log::error!("error logging in: {}", e)), + ); + let session = gotham::middleware::session::SessionData::< crate::web::SessionData, >::borrow_mut_from(&mut state); - session.login = username.clone().map(|username| super::LoginState { - username: username.clone(), - auth: crate::protocol::Auth::plain(&username), - }); + match r_login.wait().unwrap() { + Ok(login) => { + session.login = Some(login); + } + Err(e) => { + session.login = None; + log::error!("error logging in: {}", e); + return ( + state, + hyper::Response::builder() + .status(hyper::StatusCode::INTERNAL_SERVER_ERROR) + .body(hyper::Body::empty()) + .unwrap(), + ); + } + } ( state, hyper::Response::new(hyper::Body::from( - serde_json::to_string(&Response { username }).unwrap(), + serde_json::to_string(&Response { + username: Some(username), + }) + .unwrap(), )), ) } + +pub(crate) struct Client< + S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static, +> { + client: crate::client::Client, + auth: crate::protocol::Auth, + w_login: Option>>, +} + +impl + Client +{ + pub(crate) fn new( + client: crate::client::Client, + auth: crate::protocol::Auth, + w_login: tokio::sync::oneshot::Sender>, + ) -> Self { + Self { + client, + auth, + w_login: Some(w_login), + } + } +} + +impl + Client +{ + const POLL_FNS: + &'static [&'static dyn for<'a> Fn( + &'a mut Self, + ) + -> component_future::Poll< + (), + Error, + >] = &[&Self::poll_client]; + + fn poll_client(&mut self) -> component_future::Poll<(), Error> { + let res = + match component_future::try_ready!(self.client.poll()).unwrap() { + crate::client::Event::ServerMessage(msg) => match msg { + crate::protocol::Message::Disconnected => { + Err(Error::ServerDisconnected) + } + crate::protocol::Message::Error { msg } => { + Err(Error::Server { message: msg }) + } + crate::protocol::Message::LoggedIn { username } => { + Ok(super::LoginState { + auth: self.auth.clone(), + username, + }) + } + _ => { + return Ok(component_future::Async::DidWork); + } + }, + _ => unreachable!(), + }; + self.w_login.take().unwrap().send(res).unwrap(); + Ok(component_future::Async::Ready(())) + } +} + +impl + futures::Future for Client +{ + type Item = (); + type Error = Error; + + fn poll(&mut self) -> futures::Poll { + component_future::poll_future(self, Self::POLL_FNS) + } +} -- cgit v1.2.3