From 67244e63b398091fe5e0614ada946ac1f6596151 Mon Sep 17 00:00:00 2001 From: Lyssieth Date: Sun, 8 Oct 2023 23:11:59 +0300 Subject: [PATCH] feat: basic authentication. Gotta improve it, but right now this can ping. Theoretically any client should be able to connect. --- ...cbf7dc463eea0579afacc0267f0f8c33640d3.json | 38 +++++++++++++++++++ .vscode/settings.json | 11 ++++++ Cargo.lock | 7 ++++ Cargo.toml | 1 + migrations/0001_create-user.sql | 8 ++++ src/rest/ping.rs | 28 ++++++++++++-- src/user.rs | 24 ++++++++++-- 7 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 .sqlx/query-fbf4d83d9836cf85d01059e679bcbf7dc463eea0579afacc0267f0f8c33640d3.json create mode 100644 .vscode/settings.json diff --git a/.sqlx/query-fbf4d83d9836cf85d01059e679bcbf7dc463eea0579afacc0267f0f8c33640d3.json b/.sqlx/query-fbf4d83d9836cf85d01059e679bcbf7dc463eea0579afacc0267f0f8c33640d3.json new file mode 100644 index 0000000..73ed5af --- /dev/null +++ b/.sqlx/query-fbf4d83d9836cf85d01059e679bcbf7dc463eea0579afacc0267f0f8c33640d3.json @@ -0,0 +1,38 @@ +{ + "db_name": "SQLite", + "query": "SELECT * FROM users WHERE name = ?", + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int64" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "password", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "is_admin", + "ordinal": 3, + "type_info": "Bool" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false, + false + ] + }, + "hash": "fbf4d83d9836cf85d01059e679bcbf7dc463eea0579afacc0267f0f8c33640d3" +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9c88f1c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "sqltools.useNodeRuntime": true, + "sqltools.connections": [ + { + "previewLimit": 50, + "driver": "SQLite", + "name": "rave-users", + "database": "${workspaceFolder:rave}/users.db" + } + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 8902839..ca299f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1003,6 +1003,12 @@ dependencies = [ "digest", ] +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + [[package]] name = "memchr" version = "2.6.4" @@ -1398,6 +1404,7 @@ version = "0.1.0" dependencies = [ "cfg-if", "color-eyre", + "md5", "poem", "quick-xml", "serde", diff --git a/Cargo.toml b/Cargo.toml index 01af75d..6d4bf86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ publish = ["crates-io"] [dependencies] cfg-if = "1.0.0" color-eyre = "0.6.2" +md5 = "0.7.0" poem = { version = "1.3.58", features = [ "compression", "cookie", diff --git a/migrations/0001_create-user.sql b/migrations/0001_create-user.sql index 8ddc1d3..581d7c5 100644 --- a/migrations/0001_create-user.sql +++ b/migrations/0001_create-user.sql @@ -1 +1,9 @@ -- Add migration script here +CREATE TABLE users ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + password TEXT NOT NULL, + is_admin BOOLEAN NOT NULL DEFAULT FALSE +); +INSERT INTO users (name, password, is_admin) +VALUES ('admin', 'admin', TRUE); \ No newline at end of file diff --git a/src/rest/ping.rs b/src/rest/ping.rs index 6c77623..6b2aeda 100644 --- a/src/rest/ping.rs +++ b/src/rest/ping.rs @@ -1,8 +1,28 @@ -use crate::{authentication::Authentication, subsonic::SubsonicResponse}; +use poem::web::Data; +use sqlx::SqlitePool; + +use crate::{ + authentication::Authentication, + subsonic::{self, SubsonicResponse}, + user, +}; #[poem::handler] -pub fn ping(auth: Authentication) -> SubsonicResponse { - dbg!(auth); +pub async fn ping(Data(pool): Data<&SqlitePool>, auth: Authentication) -> SubsonicResponse { + let user = user::get_user(pool, &auth.username).await; - SubsonicResponse::new_empty() + match user { + Ok(Some(u)) => { + if u.verify(&auth.token, &auth.salt) { + SubsonicResponse::new_empty() + } else { + SubsonicResponse::new_error(subsonic::Error::WrongUsernameOrPassword(None)) + } + } + Ok(None) => SubsonicResponse::new_error(subsonic::Error::WrongUsernameOrPassword(None)), + Err(e) => { + tracing::error!("Error getting user: {}", e); + SubsonicResponse::new_error(subsonic::Error::WrongUsernameOrPassword(None)) + } + } } diff --git a/src/user.rs b/src/user.rs index 5adb718..71b1706 100644 --- a/src/user.rs +++ b/src/user.rs @@ -1,11 +1,29 @@ +use color_eyre::Result; use serde::{Deserialize, Serialize}; +use sqlx::SqlitePool; #[derive(Debug, Clone, Deserialize, Serialize)] pub struct User { - pub id: i32, - pub created_at: time::OffsetDateTime, + pub id: i64, pub name: String, /// I hate this. It's stored in plaintext. Why? - pub password: String, + password: String, pub is_admin: bool, } + +impl User { + pub fn verify(&self, hashed_password: &str, salt: &str) -> bool { + let ours = md5::compute(format!("{}{}", self.password, salt)); + let ours = format!("{ours:x}"); + + ours == hashed_password + } +} + +pub async fn get_user(pool: &SqlitePool, name: &str) -> Result> { + Ok( + sqlx::query_as!(User, "SELECT * FROM users WHERE name = ?", name) + .fetch_optional(pool) + .await?, + ) +}