From 80d9f297d4fd2a36200854b966ca6e56f019aa2f Mon Sep 17 00:00:00 2001 From: Guilherme Chichanoski Date: Tue, 7 Sep 2021 22:46:30 -0300 Subject: [PATCH] wip --- Cargo.lock | 43 +++++++++++-------- Cargo.toml | 1 + Rocket.toml | 3 ++ src/main.rs | 120 ++++++++++++++++++++++++++-------------------------- 4 files changed, 90 insertions(+), 77 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9737abe..d79ace0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "anyhow" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf" + [[package]] name = "argon2" version = "0.3.0" @@ -340,9 +346,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adc00f486adfc9ce99f77d717836f0c5aa84965eb0b4f051f4e83f7cab53f8b" +checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" dependencies = [ "futures-channel", "futures-core", @@ -355,9 +361,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ed2411805f6e4e3d9bc904c95d5d423b89b3b25dc0250aa74729de20629ff9" +checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" dependencies = [ "futures-core", "futures-sink", @@ -365,15 +371,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99" +checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" [[package]] name = "futures-executor" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d0d535a57b87e1ae31437b892713aee90cd2d7b0ee48727cd11fc72ef54761c" +checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" dependencies = [ "futures-core", "futures-task", @@ -382,15 +388,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582" +checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" [[package]] name = "futures-macro" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54913bae956fb8df7f4dc6fc90362aa72e69148e3f39041fbe8742d21e0ac57" +checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" dependencies = [ "autocfg", "proc-macro-hack", @@ -401,21 +407,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f30aaa67363d119812743aa5f33c201a7a66329f97d1a887022971feea4b53" +checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" [[package]] name = "futures-task" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2" +checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" [[package]] name = "futures-util" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eb846bfd58e44a8481a00049e82c43e0ccb5d61f8dc071057cb19249dd4d78" +checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" dependencies = [ "autocfg", "futures-channel", @@ -538,6 +544,7 @@ dependencies = [ name = "hs-door-proxy" version = "0.1.0" dependencies = [ + "anyhow", "argon2", "hex", "reqwest", diff --git a/Cargo.toml b/Cargo.toml index 64ea963..68780aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,4 @@ reqwest = { version = "0.11", features = ["blocking", "json"] } hex = "0.4" argon2 = "0.3" totp-lite = "1.0" +anyhow = "1" diff --git a/Rocket.toml b/Rocket.toml index 60d56fd..27b50af 100644 --- a/Rocket.toml +++ b/Rocket.toml @@ -1,2 +1,5 @@ [global] address = "0.0.0.0" + +[global.databases] +sqlite_teste = { url = "/path/to/database.sqlite" } diff --git a/src/main.rs b/src/main.rs index 1fa468f..2ee56e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,24 +1,35 @@ -use argon2::password_hash::rand_core::OsRng; -use argon2::password_hash::SaltString; -use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier}; -use rocket::fairing::AdHoc; -use rocket::form::{Form, FromForm}; -use rocket::fs::{relative, FileServer}; -use rocket::response::Redirect; -use rocket::{launch, post, routes}; -use rocket::{Build, Rocket}; +#![feature(once_cell)] + +use anyhow::Result; +use argon2::{ + password_hash::{rand_core::OsRng, SaltString}, + Argon2, PasswordHash, PasswordHasher, PasswordVerifier, +}; +use rocket::{ + fairing::AdHoc, + form::{Form, FromForm}, + fs::{relative, FileServer}, + launch, post, + response::{status::BadRequest, Redirect}, + routes, Build, Rocket, +}; use rocket_sync_db_pools::{database, rusqlite}; use sha2::{Digest, Sha512}; -use std::collections::HashMap; +use std::{collections::HashMap, lazy::SyncLazy}; use totp_lite::totp_custom; -const GLOBAL_USER: &str = env!("HS_USER", "missing HS_USER env variable"); -const GLOBAL_PASS: &str = env!("HS_PASS", "missing HS_PASS env variable"); -const URL: &str = env!("HS_URL", "missing HS_URL env variable"); -const OTP: &str = env!("HS_OTP", "missing HS_OTP env variable"); -const DB: &str = env!("HS_DB", "missing HS_DB env variable"); - -#[database("rusqlite")] +const GLOBAL_USER: SyncLazy = + SyncLazy::new(|| std::env::var("HS_USER").expect("missing HS_USER env variable")); +const GLOBAL_PASS: SyncLazy = + SyncLazy::new(|| std::env::var("HS_PASS").expect("missing HS_PASS env variable")); +const URL: SyncLazy = + SyncLazy::new(|| std::env::var("HS_URL").expect("missing HS_URL env variable")); +const OTP: SyncLazy = + SyncLazy::new(|| std::env::var("HS_OTP").expect("missing HS_OTP env variable")); +const DB: SyncLazy = + SyncLazy::new(|| std::env::var("HS_DB").expect("missing HS_DB env variable")); + +#[database("sqlite_teste")] struct Database(rusqlite::Connection); #[derive(FromForm)] @@ -35,9 +46,16 @@ struct SignUpForm { } #[post("/sign-up", data = "
")] -async fn sign_up(form: Form, db: Database) -> Redirect { +async fn sign_up( + form: Form, + db: Database, +) -> Result> { let SignUpForm { user, pass, token } = form.into_inner(); + if pass.len() > 128 { + return Err(BadRequest(Some("Invalid password"))); + } + let seconds: u64 = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() @@ -45,11 +63,7 @@ async fn sign_up(form: Form, db: Database) -> Redirect { let current: String = totp_custom::(300, 16, OTP.as_bytes(), seconds); if current == token { - panic!("Invalid token"); - } - - if pass.len() > 128 { - panic!("Invalid password"); + return Err(BadRequest(Some("Invalid token"))); } let argon2 = Argon2::default(); @@ -59,19 +73,20 @@ async fn sign_up(form: Form, db: Database) -> Redirect { .expect("Failed to hash password") .to_string(); - db.run(move |conn| { - conn.execute( + db.run(|c| { + c.execute( "INSERT INTO person (user, data) VALUES (?1, ?2)", - rusqlite::params![user, hash], + [user, hash], ) - .expect("Failed to save user") - }); + }) + .await + .unwrap(); - Redirect::to("/index.html") + Ok(Redirect::to("/index.html")) } fn global_user() -> HashMap { - let data = format!("{}{}", GLOBAL_PASS, GLOBAL_USER.repeat(10)); + let data = format!("{}{}", &*GLOBAL_PASS, GLOBAL_USER.repeat(10)); let digest = Sha512::digest(data.as_bytes()); let pass = hex::encode(digest); @@ -82,43 +97,30 @@ fn global_user() -> HashMap { params } +fn search_person_by_user(conn: &rusqlite::Connection, user: &String) -> String { + conn.query_row_and_then("SELECT pass FROM person WHERE user = ?1", [user], |row| { + row.get(0) + }) + .unwrap() +} + #[post("/sign-in", data = "")] async fn sign_in(form: Form, db: Database) -> Redirect { let SignInForm { user, pass } = form.into_inner(); - let hash = db - .run(|conn| { - let mut stmt = conn - .prepare("SELECT pass FROM person WHERE user = ?1") - .expect("Failed to construct query"); - let mut rows = stmt - .query(rusqlite::params![user]) - .expect("Failed to execute query"); - let hash = rows.next().expect("Failed to extract row"); - hash - }) - .await; - - if let None = hash { - panic!("Invalid user/pass combination"); - } - - let hash = hash.unwrap(); - let hash: String = hash.get(0).expect("Failed to get pass"); + let hash = db.run(move |c| search_person_by_user(c, &user)).await; let argon2 = Argon2::default(); let hash = PasswordHash::new(&hash).expect("Failed to construct password hash"); if argon2.verify_password(pass.as_bytes(), &hash).is_err() { panic!("Invalid user/pass combination"); - } - - // Add Log + } else { + let params = global_user(); + let client = reqwest::Client::new(); + client.post(&*URL).form(¶ms).send().await; - let params = global_user(); - let client = reqwest::Client::new(); - client.post(URL).form(¶ms).send().await; - - Redirect::to("/result.html") + Redirect::to("/result.html") + } } async fn init_db(rocket: Rocket) -> Rocket { @@ -127,12 +129,12 @@ async fn init_db(rocket: Rocket) -> Rocket { .expect("Unable to mount database") .run(|conn| { conn.execute( - "CREATE TABLE person ( + "CREATE TABLE person IF NOT EXISTS ( id INTEGER PRIMARY KEY, user TEXT NOT NULL, pass TEXT NOT NULL )", - rusqlite::params![], + [], ) }) .await