-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Webclient is able to let user login and saves session string in cookies.
- Loading branch information
1 parent
1a24fe8
commit c27677f
Showing
6 changed files
with
223 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,88 +1,208 @@ | ||
extern crate iron; | ||
#[macro_use] | ||
extern crate nickel; | ||
extern crate plugin; | ||
extern crate typemap; | ||
extern crate hyper; | ||
extern crate uosql; | ||
extern crate rustc_serialize; | ||
extern crate cookie; | ||
extern crate url; | ||
|
||
use iron::prelude::*; | ||
use iron::status; | ||
use uosql::Connection; | ||
use std::io::Read; | ||
use uosql::Error; | ||
use std::collections::HashMap; | ||
use std::collections::hash_map::Entry; | ||
use std::ops::DerefMut; | ||
use std::sync::{Arc, Mutex}; | ||
use plugin::Extensible; | ||
use hyper::header::{Cookie, SetCookie}; | ||
use nickel::{Nickel, HttpRouter}; | ||
use cookie::Cookie as CookiePair; | ||
use hyper::method::Method; | ||
use url::form_urlencoded as urlencode; | ||
|
||
// Dummy key for typemap | ||
struct ConnKey; | ||
impl typemap::Key for ConnKey { | ||
type Value = Arc<Mutex<Connection>>; | ||
} | ||
|
||
#[derive(Debug)] | ||
struct Login { | ||
user : String, | ||
password: String | ||
} | ||
|
||
/// Web based client | ||
fn main() { | ||
|
||
// Key Value pairs: User + connections | ||
// Every user has one connection | ||
let map: HashMap<String, Connection> = HashMap::new(); | ||
let ptr = Arc::new(Mutex::new(map)); | ||
let mut server = Nickel::new(); | ||
let map: HashMap<String, Arc<Mutex<Connection>>>= HashMap::new(); | ||
let map = Arc::new(Mutex::new(map)); | ||
let map2 = map.clone(); | ||
|
||
// Cookie managing | ||
server.utilize(middleware! { |req, res| | ||
|
||
// If login data has been posted, continue | ||
if req.origin.method == Method::Post { | ||
return Ok(nickel::Action::Continue(res)); | ||
} | ||
|
||
// Look for session string in Cookies | ||
let sess = match req.origin.headers.get::<Cookie>() { | ||
// If no Cookie found, go to Login | ||
None => { | ||
let m = HashMap::<i8, i8>::new(); | ||
return res.render("src/webclient/templates/login.tpl", &m); | ||
} | ||
// If there is a Cookie, eat it | ||
// (or find the matching UosqlDB-Cookie and extract session string) | ||
Some(cs) => { | ||
if let Some(sess) = cs.to_cookie_jar(&[1u8]).find("UosqlDB") { | ||
sess.value | ||
// There is a cookie, but it is not ours :'( | ||
// Return to Login | ||
} else { | ||
let m = HashMap::<i8, i8>::new(); | ||
return res.render("src/webclient/templates/login.tpl", &m); | ||
} | ||
}, | ||
}; | ||
|
||
// We have a session string and look for the matching connection in | ||
// our Session-Connection map | ||
let guard = map.lock().unwrap(); | ||
match guard.get(&sess) { | ||
// No matching session: Old cookie | ||
None => { | ||
let mut data = HashMap::new(); | ||
data.insert("err_msg", "Invalid Session"); | ||
return res.render("src/webclient/templates/login.tpl", &data); | ||
} | ||
// There is a connection, we are logged in, we can enter the site! | ||
Some(con) => { | ||
req.extensions_mut().insert::<ConnKey>(con.clone()); | ||
return Ok(nickel::Action::Continue(res)); | ||
} | ||
} | ||
}); | ||
|
||
// Login managing | ||
server.post("/login", middleware! { |req, mut res| | ||
|
||
// Read the post data | ||
let mut login_data = String::new(); | ||
let read = req.origin.read_to_string(&mut login_data).unwrap(); | ||
|
||
// Not sufficiently filled in, return to Login with error msg | ||
if read < 15 { | ||
let mut data = HashMap::new(); | ||
data.insert("err_msg", "No data given"); | ||
return res.render("src/webclient/templates/login.tpl", &data); | ||
} | ||
|
||
// Extract login data from Post string | ||
let pairs = urlencode::parse(login_data.as_bytes()); | ||
let username = pairs.iter().find(|e| e.0 == "user").map(|e| e.1.clone()); | ||
let password = pairs.iter().find(|e| e.0 == "password").map(|e| e.1.clone()); | ||
|
||
// If eihter username or password are empty, return to Login page | ||
if username.is_none() || password.is_none() { | ||
let mut data = HashMap::new(); | ||
data.insert("err_msg", "Not all required fields given"); | ||
return res.render("src/webclient/templates/login.tpl", &data); | ||
} | ||
|
||
// build Login struct | ||
let login = Login { | ||
user: username.unwrap(), | ||
password: password.unwrap() | ||
}; | ||
|
||
// Generate new session string | ||
let sess_str = login.user.clone(); // Dummy | ||
|
||
let mut chain = Chain::new(move |_: &mut Request| { | ||
let own = ptr.clone(); | ||
// Locked until guard dies | ||
let mut guard = own.lock().unwrap(); | ||
// Try connect to db server | ||
// Insert connection and session string into hashmap | ||
let mut guard = map2.lock().unwrap(); | ||
|
||
//==================== TODO Read user data input somehow ==========================// | ||
// Get login data | ||
let username = "Peter".to_string(); | ||
// DUMMY DATA | ||
let connection = "127.0.0.1".to_string(); | ||
let port = 4242; | ||
let password = "Bob".to_string(); | ||
|
||
// Get connection of user or build new connection and insert it into | ||
// hashmap | ||
let con = match guard.deref_mut().entry(username.clone()) { | ||
Entry::Occupied(o) => o.into_mut(), | ||
// create new connections | ||
match guard.deref_mut().entry(sess_str.clone()) { | ||
Entry::Occupied(_) => {}, | ||
Entry::Vacant(v) => { | ||
let cres = Connection::connect(connection, port, | ||
username, password); | ||
login.user.clone(), login.password.clone()); | ||
match cres { | ||
Err(e) => { | ||
match e { | ||
let errstr = match e { | ||
// Connection error handling | ||
// TO DO: Wait for Display/Debug | ||
Error::AddrParse(_) => { | ||
return Ok(Response::with((iron::status::Ok, | ||
format!("Could not connect to specified server.")))) | ||
"Could not connect to specified server." | ||
}, | ||
Error::Io(_) => { | ||
return Ok(Response::with((iron::status::Ok, | ||
format!("Connection failure. Try again later.")))) | ||
"Connection failure. Try again later." | ||
}, | ||
Error::Decode(_) => { | ||
return Ok(Response::with((iron::status::Ok, | ||
format!("Could not read data from server.")))) | ||
"Could not readfsdfd data from server." | ||
}, | ||
Error::Encode(_) => { | ||
return Ok(Response::with((iron::status::Ok, | ||
format!("Could not send data to server.")))) | ||
"Could not send data to server." | ||
}, | ||
Error::UnexpectedPkg(e) => { | ||
return Ok(Response::with((iron::status::Ok, | ||
format!("{}", e.to_string())))) | ||
Error::UnexpectedPkg(_) => { | ||
"Unexpected Package." | ||
}, | ||
Error::Auth(e) => { | ||
return Ok(Response::with((iron::status::Ok, | ||
format!("{}", e.to_string())))) | ||
Error::Auth(_) => { | ||
"Authentication failed." | ||
}, | ||
} | ||
}; | ||
let mut data = HashMap::new(); | ||
data.insert("err", errstr); | ||
return res.render("src/webclient/templates/error.tpl", &data); | ||
} | ||
Ok(c) => v.insert(c), | ||
Ok(c) => { | ||
v.insert(Arc::new(Mutex::new(c))); | ||
}, | ||
} | ||
} | ||
}; | ||
|
||
// Msg to print to web | ||
let msg = format!("Connected (version {}) to {}:{}\n{}\n", | ||
con.get_version(), con.get_ip(), | ||
con.get_port(), con.get_message()); | ||
// Set a Cookie with the session string as its value | ||
// sess_str is set to a value here, so we can safely unwrap | ||
let keks = CookiePair::new("UosqlDB".to_owned(), sess_str.clone()); | ||
res.headers_mut().set(SetCookie(vec![keks])); | ||
|
||
Ok(Response::with((iron::status::Ok, msg))) | ||
// Redirect to the greeting page | ||
*res.status_mut() = nickel::status::StatusCode::Found; | ||
res.headers_mut().set_raw("location", vec![b"/".to_vec()]); | ||
return res.send(""); | ||
}); | ||
// Build webclient on localhost 3000 | ||
Iron::new(chain).http("localhost:3000").unwrap(); | ||
} | ||
|
||
/* | ||
Get data input from user via webclient and | ||
process it | ||
// Greeting page | ||
server.get("/", middleware! { |req, response| | ||
|
||
// Look for connection | ||
let con = req.extensions().get::<ConnKey>().unwrap().lock().unwrap(); | ||
|
||
*/ | ||
// Current display with short welcome message | ||
let version = con.get_version().to_string(); | ||
let port = con.get_port().to_string(); | ||
let mut data = HashMap::new(); | ||
|
||
data.insert("name", con.get_username()); | ||
data.insert("version", &version); | ||
data.insert("bind", con.get_ip()); | ||
data.insert("port", &port); | ||
data.insert("msg", con.get_message()); | ||
return response.render("src/webclient/templates/hello.tpl", &data); | ||
}); | ||
|
||
|
||
server.listen("127.0.0.1:6767"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<html> | ||
<body> | ||
<h1> | ||
Error: {{ err }} | ||
</h1> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<html> | ||
<body style = "background-color:lightgrey"> | ||
<form style = "text-align:right"> | ||
<button type="button" id = "logout"> Logout </button> | ||
</form> | ||
<h1 style = "text-align:center"> | ||
Hello {{ name }}! | ||
</h1> | ||
<h4 style = "text-align:center; font-family:courier"> | ||
Connected (version : {{ version }}) to {{ bind }} : {{ port }} <br> | ||
{{ msg }} | ||
</h4> | ||
|
||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<html> | ||
<body style = "background-color: lightgrey"> | ||
<h1 style = "text-align:center"> | ||
Login | ||
</h1> | ||
<p style="text-align:center"> | ||
{{ err_msg }} | ||
</p> | ||
<p> | ||
<form style = "text-align:center" method = "post" action="/login"> | ||
<label for ="user"> Username:</label> | ||
<input type = "text" name="user" id="user" required><br> | ||
<label for ="password"> Password:</label> | ||
<input type = "password" name="password" id="password" required><br> | ||
<input type = "submit" value="Login"> | ||
</form> | ||
</p> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<html> | ||
<body> | ||
<h1> | ||
Success! | ||
</h1> | ||
</body> | ||
</html> |