commit 578100100e68128692799b3af89d966b89942ef4 Author: vanten-s Date: Sun Aug 27 17:16:10 2023 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4dea8d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +.env +db/ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..d39297a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,464 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "backend" +version = "0.1.0" +dependencies = [ + "diesel", + "digest", + "dotenv", + "rand 0.8.5", + "rust-crypto", + "time 0.3.27", +] + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "deranged" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" + +[[package]] +name = "diesel" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a532c1f99a0f596f6960a60d1e119e91582b24b39e2d83a190e61262c3ef0c" +dependencies = [ + "bitflags", + "byteorder", + "diesel_derives", + "mysqlclient-sys", + "percent-encoding", + "time 0.3.27", + "url", +] + +[[package]] +name = "diesel_derives" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74398b79d81e52e130d991afeed9c86034bb1b7735f46d2f5bf7deb261d80303" +dependencies = [ + "diesel_table_macro_syntax", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "diesel_table_macro_syntax" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" +dependencies = [ + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "mysqlclient-sys" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f61b381528ba293005c42a409dd73d034508e273bf90481f17ec2e964a6e969b" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" +dependencies = [ + "gcc", + "libc", + "rand 0.3.23", + "rustc-serialize", + "time 0.1.45", +] + +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" + +[[package]] +name = "serde" +version = "1.0.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31" + +[[package]] +name = "syn" +version = "2.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb39ee79a6d8de55f48f2293a830e040392f1c5f16e336bdd1788cd0aadce07" +dependencies = [ + "deranged", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "733d258752e9303d392b94b75230d07b0b9c489350c69b851fc6c065fde3e8f9" +dependencies = [ + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3c8d48e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "backend" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +diesel = { version = "2.1.0", features = ["mysql", "time"] } +digest = "0.10.7" +dotenv = "0.15.0" +rand = "0.8.5" +rust-crypto = "0.2.36" +time = "0.3.27" diff --git a/diesel.toml b/diesel.toml new file mode 100644 index 0000000..c028f4a --- /dev/null +++ b/diesel.toml @@ -0,0 +1,9 @@ +# For documentation on how to configure this file, +# see https://diesel.rs/guides/configuring-diesel-cli + +[print_schema] +file = "src/schema.rs" +custom_type_derives = ["diesel::query_builder::QueryId"] + +[migrations_directory] +dir = "migrations" diff --git a/migrations/.keep b/migrations/.keep new file mode 100644 index 0000000..e69de29 diff --git a/migrations/2023-08-23-112227_users/down.sql b/migrations/2023-08-23-112227_users/down.sql new file mode 100644 index 0000000..dc3714b --- /dev/null +++ b/migrations/2023-08-23-112227_users/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +DROP TABLE users; diff --git a/migrations/2023-08-23-112227_users/up.sql b/migrations/2023-08-23-112227_users/up.sql new file mode 100644 index 0000000..196bb24 --- /dev/null +++ b/migrations/2023-08-23-112227_users/up.sql @@ -0,0 +1,12 @@ +-- Your SQL goes here +CREATE TABLE users ( + id BIGINT AUTO_INCREMENT NOT NULL, + username VARCHAR(20) NOT NULL, + email VARCHAR(255) NOT NULL, + salt VARCHAR(255) NOT NULL, + pass VARCHAR(64) NOT NULL, + joined DATE NOT NULL, + PRIMARY KEY(id), + UNIQUE(username), + UNIQUE(email) +); diff --git a/migrations/2023-08-23-142552_channels/down.sql b/migrations/2023-08-23-142552_channels/down.sql new file mode 100644 index 0000000..f5b9988 --- /dev/null +++ b/migrations/2023-08-23-142552_channels/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +DROP TABLE channels; diff --git a/migrations/2023-08-23-142552_channels/up.sql b/migrations/2023-08-23-142552_channels/up.sql new file mode 100644 index 0000000..f9c344c --- /dev/null +++ b/migrations/2023-08-23-142552_channels/up.sql @@ -0,0 +1,8 @@ +-- Your SQL goes here +CREATE TABLE channels ( + id BIGINT NOT NULL AUTO_INCREMENT, + user BIGINT NOT NULL, + name VARCHAR(255) NOT NULL, + Bio text, + PRIMARY KEY(id) +) diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..479c73e --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,142 @@ +#[macro_use] +extern crate diesel; +extern crate dotenv; + +pub mod model; +pub mod schema; + +use diesel::prelude::*; +use diesel::result::{DatabaseErrorKind, Error}; + +use dotenv::dotenv; +use std::env; + +use self::model::*; + +use time::OffsetDateTime; + +use crypto::digest::Digest; +use crypto::sha2::Sha256; +use rand::{thread_rng, Rng}; + +pub enum UserCreationStatus { + Success, + UserExists, + QueryError(Error), + DatabaseError(DatabaseErrorKind), +} + +pub enum UserSelectionStatus { + Success(T), + UserDoesntExist, + QueryError(Error), + DatabaseError(DatabaseErrorKind) +} + +pub fn create_connection() -> MysqlConnection { + dotenv().ok(); + + let database_url = env::var("DATABASE_URL").expect("Database URL Not Defined"); + MysqlConnection::establish(&database_url).unwrap() +} + +pub fn get_id_from_email(user_email: String, connection: &mut MysqlConnection) -> UserSelectionStatus { + use schema::users::dsl::*; + + let users_matching_email = match users + .filter(email.eq(user_email)) + .limit(1) + .select(User::as_select()) + .load(connection) { + Ok(v) => v, + Err(_e) => vec![] + }; + + let user = match users_matching_email.get(0) { + Some(v) => v, + None => return UserSelectionStatus::UserDoesntExist + }; + + UserSelectionStatus::Success(user.id) +} + +pub fn check_password( + user_id: i64, + password: String, + connection: &mut MysqlConnection, +) -> UserSelectionStatus { + + use self::schema::users::dsl::*; + + let users_matching = match users + .filter(id.eq(user_id)) + .limit(1) + .select(User::as_select()) + .load(connection) { + Ok(v) => v, + Err(_e) => vec![] + }; + + let user = match users_matching.get(0) { + Some(v) => v, + None => return UserSelectionStatus::UserDoesntExist + }; + + let mut hasher = Sha256::new(); + hasher.input_str(&(password + &user.salt)); + + let hashed = hasher.result_str(); + + UserSelectionStatus::Success(user.pass == hashed) +} + +pub fn add_user( + username: String, + email: String, + password: String, + connection: &mut MysqlConnection, +) -> UserCreationStatus { + use schema::users::dsl::users; + + let joined = OffsetDateTime::now_utc().date(); + + let salt: String = { + const CHARSET: &[u8] = b"abcdef0123456789"; + + let mut rng = thread_rng(); + let salt: String = (0..64) + .map(|_| { + let idx = rng.gen_range(0..CHARSET.len()); + CHARSET[idx] as char + }) + .collect(); + salt + }; + + let mut hasher = Sha256::new(); + hasher.input_str(&(password + &salt)); + + let pass = hasher.result_str(); + + let new_user = model::NewUser { + username, + email, + salt, + pass, + joined, + }; + + match diesel::insert_into(users) + .values(&new_user) + .execute(connection) + { + Ok(_) => UserCreationStatus::Success, + Err(e) => match e { + Error::DatabaseError(database_error_kind, _) => match database_error_kind { + DatabaseErrorKind::UniqueViolation => UserCreationStatus::UserExists, + _ => UserCreationStatus::DatabaseError(database_error_kind), + }, + _ => UserCreationStatus::QueryError(e), + }, + } +} diff --git a/src/model.rs b/src/model.rs new file mode 100644 index 0000000..da8738e --- /dev/null +++ b/src/model.rs @@ -0,0 +1,23 @@ +use time::Date; + +#[derive(Queryable, Selectable)] +#[diesel(table_name = crate::schema::users)] +#[diesel(check_for_backend(diesel::mysql::Mysql))] +pub struct User { + pub id: i64, + pub username: String, + pub email: String, + pub salt: String, + pub pass: String, + pub joined: Date, +} + +#[derive(Insertable)] +#[diesel(table_name = crate::schema::users)] +pub struct NewUser { + pub username: String, + pub email: String, + pub salt: String, + pub pass: String, + pub joined: Date, +} diff --git a/src/schema.rs b/src/schema.rs new file mode 100644 index 0000000..c0442b0 --- /dev/null +++ b/src/schema.rs @@ -0,0 +1,28 @@ +// @generated automatically by Diesel CLI. + +diesel::table! { + channels (id) { + id -> Bigint, + user -> Bigint, + #[max_length = 255] + name -> Varchar, + Bio -> Nullable, + } +} + +diesel::table! { + users (id) { + id -> Bigint, + #[max_length = 20] + username -> Varchar, + #[max_length = 255] + email -> Varchar, + #[max_length = 255] + salt -> Varchar, + #[max_length = 64] + pass -> Varchar, + joined -> Date, + } +} + +diesel::allow_tables_to_appear_in_same_query!(channels, users,);