summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKjetil Orbekk <kjetil.orbekk@gmail.com>2017-06-17 14:47:35 -0400
committerKjetil Orbekk <kjetil.orbekk@gmail.com>2017-06-17 14:47:35 -0400
commit30d40fea83f4d9e06e14f260c23a31020bd39509 (patch)
tree12d0972235342129342db8fbc79888b480f628da /src
parentd458c767da041d17781c5f2da25372af69a5d3aa (diff)
app: Introduce subcommands for serve and create user.
(Doesn't yet create users)
Diffstat (limited to 'src')
-rw-r--r--src/auth/mod.rs24
-rw-r--r--src/bin/main.rs68
-rw-r--r--src/db.rs5
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)
+ }
+
}
diff --git a/src/db.rs b/src/db.rs
index 678e603..dea9924 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -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();
}