diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/data.rs | 31 | ||||
| -rw-r--r-- | src/data/templates/base.hbs | 1 | ||||
| -rw-r--r-- | src/error.rs | 10 | ||||
| -rw-r--r-- | src/lib.rs | 2 | ||||
| -rw-r--r-- | src/main.rs | 23 | ||||
| -rw-r--r-- | src/server.rs | 58 | 
6 files changed, 106 insertions, 19 deletions
| diff --git a/src/data.rs b/src/data.rs index 5674f92..a5d7afb 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,5 +1,6 @@  use rusqlite::Connection;  use error::{Result, LinoError}; +use rand::{OsRng, Rng};  #[derive(Serialize, Debug, Clone)]  pub struct Quote { @@ -31,8 +32,27 @@ pub fn init(c: &Connection) -> Result<()> {            score INTEGER NOT NULL,            FOREIGN KEY(quote_id) REFERENCES quotes(id)          ); + +        CREATE TABLE IF NOT EXISTS keys ( +          id TEXT PRIMARY KEY, +          value BLOB NOT NULL +        );      "#,      )?; + +    let key = { +        let mut v = vec![0u8; 32]; +        (OsRng::new()?).fill_bytes(v.as_mut()); +        v +    }; +    c.execute( +        r#" +               INSERT OR IGNORE INTO keys (id, value) VALUES +               ('session', ?1); +        "#, +        &[&key], +    )?; +      Ok(())  } @@ -56,6 +76,17 @@ pub fn populate_test_db(c: &Connection) -> Result<()> {      Ok(())  } +pub fn get_key(c: &Connection, id: &str) -> Result<Vec<u8>> { +    let key = c.query_row( +        r#" +               SELECT value FROM keys WHERE id = ?1 +        "#, +        &[&id], +        |row| row.get(0), +    )?; +    Ok(key) +} +  pub fn new_quote(c: &Connection, date: &str, author: &str, content: &str) -> Result<()> {      c.execute(          r#" diff --git a/src/data/templates/base.hbs b/src/data/templates/base.hbs index d548965..db7bb9e 100644 --- a/src/data/templates/base.hbs +++ b/src/data/templates/base.hbs @@ -67,6 +67,7 @@  <p>linoquotes v.3 © 2004-2017 Kjetil Ørbekk, Erlend Hamberg, Vidar Holen, John H. Anthony.  <p>Source code at <a href="https://git.orbekk.com/linoquotes-gamma.git">https://git.orbekk.com/linoquotes-gamma.git</a>.  <p>The quotes on this page are copyright their respective owners and submitters.</p> +<p>Your user id: {{user_id}}.  </center>    </body> diff --git a/src/error.rs b/src/error.rs index 41b4e64..1005564 100644 --- a/src/error.rs +++ b/src/error.rs @@ -9,6 +9,7 @@ use iron::modifiers::Header;  #[derive(Debug)]  pub enum LinoError {      DbError(rusqlite::Error), +    IoError(std::io::Error),      NotFound(String),      BadRequest(String),  } @@ -19,6 +20,7 @@ impl fmt::Display for LinoError {      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {          match *self {              LinoError::DbError(ref err) => err.fmt(f), +            LinoError::IoError(ref err) => err.fmt(f),              LinoError::NotFound(ref x) => write!(f, "Could not find {}", x),              LinoError::BadRequest(ref x) => write!(f, "Bad request: {}", x),          } @@ -29,6 +31,7 @@ impl std::error::Error for LinoError {      fn description(&self) -> &str {          match *self {              LinoError::DbError(ref err) => err.description(), +            LinoError::IoError(ref err) => err.description(),              LinoError::NotFound(_) => "not found",              LinoError::BadRequest(_) => "bad request",          } @@ -37,6 +40,7 @@ impl std::error::Error for LinoError {      fn cause(&self) -> Option<&std::error::Error> {          match *self {              LinoError::DbError(ref err) => Some(err), +            LinoError::IoError(ref err) => Some(err),              LinoError::NotFound(_) => None,              LinoError::BadRequest(_) => None,          } @@ -49,6 +53,12 @@ impl From<rusqlite::Error> for LinoError {      }  } +impl From<std::io::Error> for LinoError { +    fn from(err: std::io::Error) -> LinoError { +        LinoError::IoError(err) +    } +} +  impl From<LinoError> for IronError {      fn from(err: LinoError) -> IronError {          let code = match err { @@ -13,6 +13,8 @@ extern crate persistent;  extern crate params;  extern crate chrono;  extern crate logger; +extern crate rand; +extern crate iron_sessionstorage;  pub mod server;  pub mod data; diff --git a/src/main.rs b/src/main.rs index 026f610..e687255 100644 --- a/src/main.rs +++ b/src/main.rs @@ -62,17 +62,18 @@ fn main() {          linoquotes_gamma::data::populate_test_db(&state.connection).unwrap();      } -    for i in 1..1000 { -        linoquotes_gamma::data::new_quote( -            &state.connection, -            "2017-07-10", -            "orbekk", -            &format!("another test {}", i), -        ).unwrap(); -        let qid = state.connection.last_insert_rowid(); -        info!("Last inserted quote: {}", qid); -        linoquotes_gamma::data::approve_quote(&state.connection, qid).unwrap(); -    } +    // for i in 1..1000 { +    //     linoquotes_gamma::data::new_quote( +    //         &state.connection, +    //         "2017-07-10", +    //         "orbekk", +    //         &format!("another test {}", i), +    //     ).unwrap(); +    //     let qid = state.connection.last_insert_rowid(); +    //     info!("Last inserted quote: {}", qid); +    //     linoquotes_gamma::data::approve_quote(&state.connection, qid).unwrap(); +    // } +    info!("Starting...");      linoquotes_gamma::server::serve(state, port);  } diff --git a/src/server.rs b/src/server.rs index 4816c33..54beb34 100644 --- a/src/server.rs +++ b/src/server.rs @@ -8,11 +8,14 @@ use rusqlite::Connection;  use std::collections::BTreeMap;  use persistent::Write;  use handlebars_iron::handlebars::to_json; -use serde_json::Map; +use serde_json;  use params;  use error::LinoError;  use chrono;  use logger::Logger; +use iron_sessionstorage::{self, SessionStorage, SessionRequestExt}; +use iron_sessionstorage::backends::SignedCookieBackend; +use rand::{OsRng, Rng};  #[derive(Debug)]  pub struct State { @@ -22,6 +25,41 @@ impl iron::typemap::Key for State {      type Value = State;  } +#[derive(Debug, Clone, Serialize)] +struct UserId(u64); +impl iron_sessionstorage::Value for UserId { +    fn get_key() -> &'static str { +        "user_id" +    } +    fn into_raw(self) -> String { +        format!("{}", self.0) +    } +    fn from_raw(value: String) -> Option<Self> { +        value.parse().ok().map(|i| UserId(i)) +    } +} + +fn user_id(r: &mut Request) -> IronResult<UserId> { +    if let Some(user_id) = r.session().get::<UserId>()? { +        return Ok(user_id); +    } + +    let mut rng = OsRng::new().map_err(|e| { +        // This is ugly, but I don't know how to annotate the expression. +        let e: LinoError = From::from(e); +        e +    })?; +    let user_id = UserId(rng.next_u64()); +    r.session().set(user_id.clone())?; +    Ok(user_id) +} + +fn make_result(r: &mut Request) -> IronResult<serde_json::Map<String, serde_json::value::Value>> { +    let mut result = serde_json::Map::new(); +    result.insert("user_id".to_string(), to_json(&user_id(r)?)); +    Ok(result) +} +  fn get_param(r: &mut Request, param: &str) -> IronResult<String> {      let map = itry!(r.get_ref::<params::Params>());      match map.get(param) { @@ -67,7 +105,7 @@ fn make_renderer() -> HandlebarsEngine {  }  fn quotes(r: &mut Request) -> IronResult<Response> { -    let mut result = Map::new(); +    let mut result = make_result(r)?;      let quote_id = get_param(r, "id").ok().and_then(          |id| id.parse::<i64>().ok(),      ); @@ -90,9 +128,9 @@ fn quotes(r: &mut Request) -> IronResult<Response> {      )))  } -fn add_get(_r: &mut Request) -> IronResult<Response> { +fn add_get(r: &mut Request) -> IronResult<Response> {      let date = chrono::offset::Local::now().format("%Y-%m-%d").to_string(); -    let mut result = Map::new(); +    let mut result = make_result(r)?;      result.insert("date".to_string(), to_json(&date));      Ok(Response::with((          status::Ok, @@ -102,6 +140,7 @@ fn add_get(_r: &mut Request) -> IronResult<Response> {  }  fn add_post(r: &mut Request) -> IronResult<Response> { +    let result = make_result(r)?;      let nick = get_param(r, "nick")?;      let date = get_param(r, "date")?;      let quote = get_param(r, "quote")?; @@ -127,12 +166,12 @@ fn add_post(r: &mut Request) -> IronResult<Response> {      Ok(Response::with((          status::Ok,          Header(ContentType::html()), -        Template::new("add_post", Map::new()), +        Template::new("add_post", result)      )))  }  fn approve(r: &mut Request) -> IronResult<Response> { -    let mut result = Map::new(); +    let mut result = make_result(r)?;      let quote_id = get_param(r, "id").ok().and_then(          |id| id.parse::<i64>().ok(),      ); @@ -185,7 +224,7 @@ pub fn vote(r: &mut Request) -> IronResult<Response> {          data::get_quote(&state.connection, quote_id)?      }; -    let mut result = Map::new(); +    let mut result = make_result(r)?;      result.insert("quote".to_string(), to_json("e));      Ok(Response::with(( @@ -206,13 +245,16 @@ pub fn serve(state: State, port: u16) {          approve: get "/approve.jsp" => approve,          vote: get "/vote" => vote,      ); -    let (logger_before, logger_after) = Logger::new(None);      let mut chain = Chain::new(router); +    let (logger_before, logger_after) = Logger::new(None);      chain.link_before(logger_before); +    let key = data::get_key(&state.connection, "session").expect("session key"); +    chain.link_around(SessionStorage::new(SignedCookieBackend::new(key)));      chain.link_after(make_renderer());      chain.link(Write::<State>::both(state));      chain.link_after(logger_after); +      let bind_address = format!("{}:{}", "::", port);      let _server = Iron::new(chain).http(bind_address.as_str());      info!("Serving on {}", bind_address); | 
