summaryrefslogtreecommitdiff
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
parentd458c767da041d17781c5f2da25372af69a5d3aa (diff)
app: Introduce subcommands for serve and create user.
(Doesn't yet create users)
-rw-r--r--Cargo.lock22
-rw-r--r--Cargo.toml1
-rw-r--r--src/auth/mod.rs24
-rw-r--r--src/bin/main.rs68
-rw-r--r--src/db.rs5
5 files changed, 96 insertions, 24 deletions
diff --git a/Cargo.lock b/Cargo.lock
index bd8c576..75c52d5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -11,6 +11,7 @@ dependencies = [
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"router 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rpassword 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"sqlite 0.23.4 (registry+https://github.com/rust-lang/crates.io-index)",
"staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -416,6 +417,17 @@ dependencies = [
]
[[package]]
+name = "rpassword"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "rust-crypto"
version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -509,6 +521,14 @@ dependencies = [
]
[[package]]
+name = "termios"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "thread-id"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -695,6 +715,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
"checksum route-recognizer 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3255338088df8146ba63d60a9b8e3556f1146ce2973bc05a75181a42ce2256"
"checksum router 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9b1797ff166029cb632237bb5542696e54961b4cf75a324c6f05c9cf0584e4e"
+"checksum rpassword 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "72556b202b5b38d0b69b0fdced60cf92dec7e37640c98eb9d7baf5bd86dc8e1a"
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
"checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
@@ -707,6 +728,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31493480e073d52522a94cdf56269dd8eb05f99549effd1826b0271690608878"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
+"checksum termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d9cf598a6d7ce700a4e6a9199da127e6819a61e64b68609683cc9a01b5683a"
"checksum thread-id 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8df7875b676fddfadffd96deea3b1124e5ede707d4884248931077518cf1f773"
"checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7"
"checksum time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd7ccbf969a892bf83f1e441126968a07a3941c24ff522a26af9f9f4585d1a3"
diff --git a/Cargo.toml b/Cargo.toml
index 2109fef..10e98fd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,3 +16,4 @@ sqlite = "*"
rust-crypto = "*"
base64 = "*"
clap = "*"
+rpassword = "*"
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();
}