From 304f82baa4edb19128aac9453c9f19d0dc7b4c3b Mon Sep 17 00:00:00 2001 From: Patrick Michl Date: Thu, 28 Apr 2022 21:55:52 +0200 Subject: [PATCH] fix errors, move password hashing into User add sqlx offline checks --- .drone.yml | 2 + Cargo.lock | 7 + Cargo.toml | 4 +- sqlx-data.json | 195 ++++++++++++++++++++++ src/api/client_server/auth.rs | 12 +- src/api/client_server/errors/api_error.rs | 2 +- src/models/users.rs | 10 +- 7 files changed, 219 insertions(+), 13 deletions(-) create mode 100644 sqlx-data.json diff --git a/.drone.yml b/.drone.yml index 5bcfd2a..8f0fe56 100644 --- a/.drone.yml +++ b/.drone.yml @@ -5,5 +5,7 @@ name: check steps: - name: cargo check image: rust:latest + environment: + SQLX_OFFLINE: 'true' commands: - cargo check \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ebf3dfd..839e597 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -252,6 +252,9 @@ name = "either" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +dependencies = [ + "serde", +] [[package]] name = "event-listener" @@ -1078,6 +1081,7 @@ dependencies = [ "paste", "percent-encoding", "rustls", + "serde", "sha2", "smallvec", "sqlformat", @@ -1099,9 +1103,12 @@ dependencies = [ "dotenv", "either", "heck", + "hex", "once_cell", "proc-macro2", "quote", + "serde", + "serde_json", "sha2", "sqlx-core", "sqlx-rt", diff --git a/Cargo.toml b/Cargo.toml index 4615aad..8893ad6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,8 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } serde = {version = "1.0", features = ["derive"] } tower-http = { version = "0.2", features = ["cors", "trace"]} -sqlx = { version = "0.5", features = ["sqlite", "macros", "runtime-tokio-rustls"] } +sqlx = { version = "0.5", features = ["sqlite", "macros", "runtime-tokio-rustls", "offline"] } anyhow = "1.0" thiserror = "1.0" -argon2 = "0.4" +argon2 = { version = "0.4", features = ["std"] } rand_core = { version = "0.6", features = ["std"] } \ No newline at end of file diff --git a/sqlx-data.json b/sqlx-data.json new file mode 100644 index 0000000..11f0b85 --- /dev/null +++ b/sqlx-data.json @@ -0,0 +1,195 @@ +{ + "db": "SQLite", + "22e18063d81e86afceca0e0c74c9070a8b21a406cba7cf7c01a966a869a9dad8": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "user_id", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "display_name", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "password", + "ordinal": 3, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + false, + false + ], + "parameters": { + "Right": 1 + } + }, + "query": "select id, user_id, display_name, password from users where user_id = ?" + }, + "58d27b1d424297504f1da2e3b9b4020121251c1155fbf5dc870dafbef97659f3": { + "describe": { + "columns": [ + { + "name": "user_id", + "ordinal": 0, + "type_info": "Text" + } + ], + "nullable": [ + false + ], + "parameters": { + "Right": 1 + } + }, + "query": "select user_id from users where user_id = ?" + }, + "87395ffa7fe0382080056bdf67805044fbe89770ef366b4553d9797059034e44": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "user_id", + "ordinal": 1, + "type_info": "Int64" + }, + { + "name": "device_id", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "display_name", + "ordinal": 3, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + false, + false + ], + "parameters": { + "Right": 3 + } + }, + "query": "insert into devices(user_id, device_id, display_name) values(?, ?, ?) returning id, user_id, device_id, display_name" + }, + "9a092e024bfe2854631e0572880f761125a2261a973b46d721db2e1401ce9aec": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "user_id", + "ordinal": 1, + "type_info": "Int64" + }, + { + "name": "device_id", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "display_name", + "ordinal": 3, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + false, + false + ], + "parameters": { + "Right": 1 + } + }, + "query": "select id, user_id, device_id, display_name from devices where user_id = ?" + }, + "bb4e2386cf2987aa86f2c4dcac1159687b7220c770542bf52485e7e16f9ce987": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "user_id", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "display_name", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "password", + "ordinal": 3, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + false, + false + ], + "parameters": { + "Right": 3 + } + }, + "query": "insert into users(user_id, display_name, password) values (?, ?, ?) returning id, user_id, display_name, password" + }, + "cd7c9d3ae02f9553d4b7c4e8d98f63c6f556ac230a339683fe25025592812033": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "device_id", + "ordinal": 1, + "type_info": "Int64" + }, + { + "name": "value", + "ordinal": 2, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + false + ], + "parameters": { + "Right": 2 + } + }, + "query": "insert into sessions(device_id, value) values(?, ?) returning id, device_id, value" + } +} \ No newline at end of file diff --git a/src/api/client_server/auth.rs b/src/api/client_server/auth.rs index 06fea9e..32bc589 100644 --- a/src/api/client_server/auth.rs +++ b/src/api/client_server/auth.rs @@ -33,8 +33,8 @@ pub fn routes() -> axum::Router { } #[tracing::instrument] -async fn get_login() -> Json { - Json(Flows::new()) +async fn get_login() -> Result, ApiError> { + Ok(Json(Flows::new())) } #[tracing::instrument(skip_all)] @@ -81,18 +81,12 @@ async fn post_register( .then(|| ()) .ok_or(RegistrationError::UserIdTaken)?; - let salt = SaltString::generate(OsRng); - let argon2 = Argon2::default(); - let pw_hash = argon2 - .hash_password(auth_data.password().as_bytes(), &salt)? - .to_string(); - let display_name = match body.initial_device_display_name() { Some(display_name) => display_name.as_ref(), None => "Random displayname", }; - let user = User::create(&db, &user_id, &user_id.to_string(), &pw_hash).await?; + let user = User::create(&db, &user_id, &user_id.to_string(), auth_data.password()).await?; let device = Device::create(&db, &user, "test", display_name).await?; (user, device) diff --git a/src/api/client_server/errors/api_error.rs b/src/api/client_server/errors/api_error.rs index 1d920c8..4b02b74 100644 --- a/src/api/client_server/errors/api_error.rs +++ b/src/api/client_server/errors/api_error.rs @@ -45,7 +45,7 @@ pub enum ApiError { DBError(#[from] sqlx::Error), #[error("Generic Error")] - Generic(anyhow::Error), + Generic(anyhow::Error) } impl From for ApiError { diff --git a/src/models/users.rs b/src/models/users.rs index 332051d..d1680e0 100644 --- a/src/models/users.rs +++ b/src/models/users.rs @@ -1,3 +1,5 @@ +use argon2::{password_hash::SaltString, Argon2, PasswordHasher}; +use rand_core::OsRng; use sqlx::SqlitePool; use crate::types::user_id::UserId; @@ -25,7 +27,13 @@ impl User { display_name: &str, password: &str, ) -> anyhow::Result { - Ok(sqlx::query_as!(Self, "insert into users(user_id, display_name, password) values (?, ?, ?) returning id, user_id, display_name, password", user_id, display_name, password).fetch_one(conn).await?) + let salt = SaltString::generate(OsRng); + let argon2 = Argon2::default(); + let pw_hash = argon2 + .hash_password(password.as_bytes(), &salt)? + .to_string(); + + Ok(sqlx::query_as!(Self, "insert into users(user_id, display_name, password) values (?, ?, ?) returning id, user_id, display_name, password", user_id, display_name, pw_hash).fetch_one(conn).await?) } pub async fn by_user_id(conn: &SqlitePool, user_id: &UserId) -> anyhow::Result {