diff --git a/Cargo.lock b/Cargo.lock index bffd7dc..35b3f37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -579,6 +579,7 @@ checksum = "ccf1bedf64cdb9643204a36dd15b19a6ce8e7aa7f7b105868e9f1fad5ffa7d12" dependencies = [ "diesel_derives", "libsqlite3-sys", + "r2d2", "time", ] diff --git a/Cargo.toml b/Cargo.toml index 4006562..da3b0c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ axum = { version = "0.8.0", features = ["macros"] } axum-extra = { version = "0.10.0", features = ["cookie"] } chrono = { version = "0.4.39", features = ["serde"] } clap = { version = "4.5.26", features = ["derive", "env"] } -diesel = { version = "2.2.6", features = ["sqlite", "returning_clauses_for_sqlite_3_35"] } +diesel = { version = "2.2.6", features = ["sqlite", "returning_clauses_for_sqlite_3_35", "r2d2"] } r2d2 = "0.8.10" r2d2_sqlite = "0.25.0" rand = "0.8.5" diff --git a/migrations/2025-01-13-114912_create_plants/up.sql b/migrations/2025-01-13-114912_create_plants/up.sql index 254f3c3..538066c 100644 --- a/migrations/2025-01-13-114912_create_plants/up.sql +++ b/migrations/2025-01-13-114912_create_plants/up.sql @@ -1,5 +1,5 @@ create table plants ( - id integer primary key not null, + id bigint primary key not null, name text not null, species text not null, description text not null diff --git a/migrations/2025-01-13-115415_create_comments/up.sql b/migrations/2025-01-13-115415_create_comments/up.sql index dd425c1..e4f8983 100644 --- a/migrations/2025-01-13-115415_create_comments/up.sql +++ b/migrations/2025-01-13-115415_create_comments/up.sql @@ -1,5 +1,7 @@ create table comments ( - id integer primary key not null, - plant_id integer references plants (id), + id bigint primary key not null, + plant_id bigint not null + references plants (id) + on delete cascade, comment text not null ); diff --git a/migrations/2025-01-13-115505_create_events/up.sql b/migrations/2025-01-13-115505_create_events/up.sql index a66a9a3..b4db1e3 100644 --- a/migrations/2025-01-13-115505_create_events/up.sql +++ b/migrations/2025-01-13-115505_create_events/up.sql @@ -1,6 +1,6 @@ create table events ( - id integer primary key not null, - plant_id integer not null + id bigint primary key not null, + plant_id bigint not null references plants (id) on delete cascade, event_type text not null, diff --git a/migrations/2025-01-13-115534_add_auth/up.sql b/migrations/2025-01-13-115534_add_auth/up.sql index 1b12ece..d0e1259 100644 --- a/migrations/2025-01-13-115534_add_auth/up.sql +++ b/migrations/2025-01-13-115534_add_auth/up.sql @@ -1,13 +1,13 @@ create table users ( - id integer primary key not null, + id bigint primary key not null, username text unique not null, password_hash text not null, admin boolean not null ); create table sessions ( - id integer primary key not null, - user_id integer not null + id bigint primary key not null, + user_id bigint not null references users (id) on delete cascade, unique (id, user_id) diff --git a/src/db/mod.rs b/src/db/mod.rs index 7264722..19a05b5 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,5 +1,6 @@ mod comment; mod event; +mod models; mod plant; mod schema; mod session; diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs new file mode 100644 index 0000000..0eba110 --- /dev/null +++ b/src/db/models/mod.rs @@ -0,0 +1 @@ +mod user; diff --git a/src/db/models/user.rs b/src/db/models/user.rs new file mode 100644 index 0000000..1423e4e --- /dev/null +++ b/src/db/models/user.rs @@ -0,0 +1,75 @@ +use argon2::{ + password_hash::{rand_core::OsRng, SaltString}, + Argon2, PasswordHash, PasswordHasher, PasswordVerifier, +}; +use diesel::prelude::*; +use serde::{Deserialize, Serialize}; + +use crate::db::schema::*; + +#[derive(Serialize, Deserialize, Clone, Queryable, Selectable)] +#[diesel(table_name = users)] +#[diesel(check_for_backend(diesel::sqlite::Sqlite))] +pub struct User { + pub id: i64, + pub username: String, + pub password_hash: String, + pub admin: bool, +} + +#[derive(Deserialize, Insertable)] +#[diesel(table_name = users)] +#[diesel(check_for_backend(diesel::sqlite::Sqlite))] +pub struct NewUser { + pub username: String, + pub password_hash: String, + pub admin: bool, +} + +fn hash_password(password: impl AsRef) -> String { + let salt = SaltString::generate(&mut OsRng); + let argon2 = Argon2::default(); + + argon2 + .hash_password(password.as_ref().as_bytes(), &salt) + .unwrap() + .to_string() +} + +impl NewUser { + pub fn new(username: String, password: String, admin: bool) -> Self { + Self { + username, + password_hash: hash_password(&password), + admin, + } + } + + pub fn insert(self, conn: &mut SqliteConnection) -> QueryResult { + diesel::insert_into(users::table) + .values(self) + .returning(User::as_returning()) + .get_result(conn) + } +} + +impl User { + pub fn by_username( + conn: &mut SqliteConnection, + username: impl AsRef, + ) -> QueryResult> { + users::dsl::users + .select(User::as_select()) + .filter(users::username.eq(username.as_ref())) + .first(conn) + .optional() + } + + pub fn verify_password(&self, password: impl AsRef) -> bool { + let password_hash = PasswordHash::new(&self.password_hash).unwrap(); + + Argon2::default() + .verify_password(password.as_ref().as_bytes(), &password_hash) + .is_ok() + } +} diff --git a/src/db/schema.rs b/src/db/schema.rs index 16a0448..7bd1846 100644 --- a/src/db/schema.rs +++ b/src/db/schema.rs @@ -2,16 +2,16 @@ diesel::table! { comments (id) { - id -> Integer, - plant_id -> Nullable, + id -> BigInt, + plant_id -> BigInt, comment -> Text, } } diesel::table! { events (id) { - id -> Integer, - plant_id -> Integer, + id -> BigInt, + plant_id -> BigInt, event_type -> Text, date -> Text, description -> Text, @@ -20,7 +20,7 @@ diesel::table! { diesel::table! { plants (id) { - id -> Integer, + id -> BigInt, name -> Text, species -> Text, description -> Text, @@ -29,14 +29,14 @@ diesel::table! { diesel::table! { sessions (id) { - id -> Integer, - user_id -> Integer, + id -> BigInt, + user_id -> BigInt, } } diesel::table! { users (id) { - id -> Integer, + id -> BigInt, username -> Text, password_hash -> Text, admin -> Bool,