From 1f897deb33886631883d8d6ae51aec38cfd9375e Mon Sep 17 00:00:00 2001 From: Radical Date: Wed, 30 Apr 2025 11:10:02 +0000 Subject: [PATCH 1/4] chore: add config.toml to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ab951f8..7cd509b 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ Cargo.lock # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ +/config.toml From 0f1824b366124736e2b9a6ba2bddb969ff693cc4 Mon Sep 17 00:00:00 2001 From: Radical Date: Wed, 30 Apr 2025 11:10:25 +0000 Subject: [PATCH 2/4] fix: query actual number of accounts --- src/api/v1/stats.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/api/v1/stats.rs b/src/api/v1/stats.rs index f013abf..62c3527 100644 --- a/src/api/v1/stats.rs +++ b/src/api/v1/stats.rs @@ -17,9 +17,16 @@ struct Response { #[get("/stats")] pub async fn res(data: web::Data) -> impl Responder { + let accounts; + if let Ok(users) = sqlx::query("SELECT uuid FROM users").fetch_all(&data.pool).await { + accounts = users.len(); + } else { + return HttpResponse::InternalServerError().finish() + } + let response = Response { // TODO: Get number of accounts from db - accounts: 0, + accounts, uptime: SystemTime::now() .duration_since(data.start_time) .expect("Seriously why dont you have time??") From 799a1ff49e94296b719a6b1cc8f69320cd6cd344 Mon Sep 17 00:00:00 2001 From: Radical Date: Wed, 30 Apr 2025 11:11:19 +0000 Subject: [PATCH 3/4] fix: use raw_sql instead of .execute --- src/main.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index f25a34a..e0a82ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,15 +26,22 @@ async fn main() -> Result<(), Error> { TODO: Figure out if a table should be used here and if not then what. Also figure out if these should be different types from what they currently are and if we should add more "constraints" */ - pool.execute(r#"CREATE TABLE IF NOT EXISTS users ( - uuid uuid UNIQUE NOT NULL, - username varchar(32) UNIQUE NOT NULL, - display_name varchar(64), - password varchar(512) NOT NULL, - email varchar(100) UNIQUE NOT NULL, - email_verified integer NOT NULL DEFAULT '0', - PRIMARY KEY (uuid) - )"#).await?; + sqlx::raw_sql(r#" + CREATE TABLE IF NOT EXISTS users ( + uuid uuid PRIMARY KEY UNIQUE NOT NULL, + username varchar(32) UNIQUE NOT NULL, + display_name varchar(64), + password varchar(512) NOT NULL, + email varchar(100) UNIQUE NOT NULL, + email_verified boolean NOT NULL DEFAULT FALSE + ); + CREATE TABLE IF NOT EXISTS instance_permissions ( + uuid uuid REFERENCES users(uuid), + administrator boolean NOT NULL DEFAULT FALSE + ) + "#) + .execute(&pool) + .await?; let data = Data { pool, From bda9f85b86a07a9acb91392e869662e073d0e38d Mon Sep 17 00:00:00 2001 From: Radical Date: Wed, 30 Apr 2025 11:12:01 +0000 Subject: [PATCH 4/4] feat: query user creation instead of using .execute on pool This should increase security of the operation a ton, need to test if an escape is still possible --- src/api/v1/register.rs | 72 ++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/src/api/v1/register.rs b/src/api/v1/register.rs index bf79819..93bf019 100644 --- a/src/api/v1/register.rs +++ b/src/api/v1/register.rs @@ -93,43 +93,41 @@ pub async fn res(mut payload: web::Payload, data: web::Data) -> Result { - HttpResponse::Ok().json( - Response { - access_token: "bogus".to_string(), - user_id: "bogus".to_string(), - expires_in: 1, - refresh_token: "bogus".to_string(), + // TODO: Check security of this implementation + Ok(match sqlx::query(&format!("INSERT INTO users VALUES ( '{}', $1, NULL, $2, $3, false )", uuid)) + .bind(account_information.identifier) + // FIXME: Password has no security currently, either from a client or server perspective + .bind(account_information.password) + .bind(account_information.email) + .execute(&data.pool) + .await { + Ok(_out) => { + HttpResponse::Ok().json( + Response { + access_token: "bogus".to_string(), + user_id: "bogus".to_string(), + expires_in: 1, + refresh_token: "bogus".to_string(), + } + ) + }, + Err(error) => { + let err_msg = error.as_database_error().unwrap().message(); + + match err_msg { + err_msg if err_msg.contains("unique") && err_msg.contains("username_key") => HttpResponse::Forbidden().json(ResponseError { + gorb_id_available: false, + ..Default::default() + }), + err_msg if err_msg.contains("unique") && err_msg.contains("email_key") => HttpResponse::Forbidden().json(ResponseError { + email_available: false, + ..Default::default() + }), + _ => { + eprintln!("{}", err_msg); + HttpResponse::InternalServerError().finish() + } } - ) - }, - Err(error) => { - let err_msg = error.as_database_error().unwrap().message(); - - match err_msg { - err_msg if err_msg.contains("unique") && err_msg.contains("username_key") => HttpResponse::Forbidden().json(ResponseError { - gorb_id_available: false, - ..Default::default() - }), - err_msg if err_msg.contains("unique") && err_msg.contains("email_key") => HttpResponse::Forbidden().json(ResponseError { - email_available: false, - ..Default::default() - }), - _ => HttpResponse::Forbidden().json(ResponseError { - ..Default::default() - }) - } - }, + }, }) }