diff options
author | Kjetil Orbekk <kjetil.orbekk@gmail.com> | 2017-06-17 14:47:35 -0400 |
---|---|---|
committer | Kjetil Orbekk <kjetil.orbekk@gmail.com> | 2017-06-17 14:47:35 -0400 |
commit | 30d40fea83f4d9e06e14f260c23a31020bd39509 (patch) | |
tree | 12d0972235342129342db8fbc79888b480f628da /src | |
parent | d458c767da041d17781c5f2da25372af69a5d3aa (diff) |
app: Introduce subcommands for serve and create user.
(Doesn't yet create users)
Diffstat (limited to 'src')
-rw-r--r-- | src/auth/mod.rs | 24 | ||||
-rw-r--r-- | src/bin/main.rs | 68 | ||||
-rw-r--r-- | src/db.rs | 5 |
3 files changed, 73 insertions, 24 deletions
diff --git a/src/auth/mod.rs b/src/auth/mod.rs index f3db525..728c246 100644 --- a/src/auth/mod.rs +++ b/src/auth/mod.rs @@ -2,22 +2,28 @@ extern crate base64; use crypto::bcrypt_pbkdf::bcrypt_pbkdf; -// TODO: Replace salt with a random string. +#[derive(Debug, PartialEq, Eq)] +pub struct HashedPassword { + salt: String, + enc: String, +} + // TODO: Configurable number of iterations. -pub fn encode(pw: &str) -> String { - let salt = "hello"; +pub fn encode(salt: &str, pw: &str) -> HashedPassword { let mut enc = vec!(0; 32); let encrypted = bcrypt_pbkdf(pw.as_bytes(), salt.as_bytes(), 10, &mut enc); - format!("${}${}${}", "sdv1", - base64::encode(salt.as_bytes()), base64::encode(&enc)) + HashedPassword { + salt: salt.to_string(), + enc: base64::encode(&enc) + } } -pub fn validate(pw: &str, enc: &str) -> bool { +pub fn validate(pw: &str, enc: &HashedPassword) -> bool { // let cs = enc.split('$'); // println("{:?}", cs.len()); // let enc_pw = cs[3]; - encode(pw) == enc + encode(enc.salt.as_str(), pw) == *enc } #[cfg(test)] @@ -25,7 +31,7 @@ mod tests { use super::*; #[test] fn it_validates() { - assert_eq!(false, validate("123", "123")); - assert_eq!(true, validate("123", &encode("123"))); + assert_eq!(false, validate("hello", "123", "123")); + assert_eq!(true, validate("hello", "123", &encode("hello", "123"))); } } diff --git a/src/bin/main.rs b/src/bin/main.rs index 36d6c00..a4d489d 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -7,28 +7,72 @@ extern crate env_logger; #[macro_use] extern crate clap; extern crate sqlite; +extern crate rpassword; + +use rpassword::read_password; +use std::io::{self, Write}; +use systemhttp::auth; + +use clap::{App, AppSettings, Arg, SubCommand}; fn main() { - let matches = clap_app!( - systemhttpd => - (version: "0.1") - (author: "Kjetil Ørbekk") - (about: "A systemd web frontend") - (@arg PORT: -p --port +takes_value "Port to serve on") - (@arg DB_FILE: --db_file +required +takes_value - "Path to sqlite database")) + let matches = App::new("systemhttpd") + .version("0.1") + .author("Kjetil Ørbekk") + .about("Systemd web frontend") + .setting(AppSettings::SubcommandRequired) + .arg(Arg::with_name("port") + .short("p") + .long("port") + .takes_value(true) + .help("Port to serve on")) + .arg(Arg::with_name("db_file") + .long("db_file") + .takes_value(true) + .help("Path to sqlite database")) + .subcommand(SubCommand::with_name("serve") + .about("Start the systemhttpd server")) + .subcommand(SubCommand::with_name("create_admin_user") + .about("Add an admin user to the db")) .get_matches(); - let port = matches.value_of("PORT").unwrap_or("8080") + let port = matches.value_of("port").unwrap_or("8080") .parse::<u16>().expect("port number"); - let db_file = matches.value_of("DB_FILE").unwrap(); + let db_file = matches.value_of("db_file").unwrap(); env_logger::init().unwrap(); let mut conn = sqlite::Connection::open(db_file) .expect(format!("opening sqlite database at {}", db_file).as_str()); systemhttp::db::init(&mut conn); - let _server = systemhttp::server::serve(port).unwrap(); - println!("Serving on {}", port); + let mut serve = || { + let _server = systemhttp::server::serve(port).unwrap(); + println!("Serving on {}", port); + }; + + let create_admin_user = || { + println!("Create admin user"); + print!("Username: "); + io::stdout().flush(); + let mut user = String::new(); + io::stdin().read_line(&mut user).unwrap(); + let password = rpassword::prompt_password_stdout("Password: ").unwrap(); + let confirmation = + rpassword::prompt_password_stdout("Repeat password: ").unwrap(); + + if password != confirmation { + println!("\nPasswords don't match"); + return + } + println!("\nCreating user {} with password (hashed) {:?}", + user, auth::encode("test_salt", password.as_str())); + }; + + match matches.subcommand_name() { + Some("serve") => serve(), + Some("create_admin_user") => create_admin_user(), + x => panic!("Don't know about subcommand: {:?}", x) + } + } @@ -12,9 +12,8 @@ pub fn init(conn: &mut Connection) -> Result<()> { info!("Initializing db..."); conn.execute(" BEGIN; - CREATE TABLE users (username TEXT, - salt TEXT, - passwd TEXT); + CREATE TABLE IF NOT EXISTS users + (username TEXT, salt TEXT, passwd TEXT); COMMIT; ").unwrap(); } |