feat: Add tracing and md5 dependency

Adds the `tracing` and `md5` crates to the project, enabling enhanced
logging and cryptographic hashing capabilities. Includes `TraceLayer`
for HTTP request tracing and configures `tracing-subscriber` with
`EnvFilter`.
This commit is contained in:
vaibhav
2026-02-22 02:44:58 +05:30
parent cae0136aaf
commit c862669b08
7 changed files with 334 additions and 53 deletions

139
Cargo.lock generated
View File

@@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
@@ -62,15 +71,15 @@ dependencies = [
[[package]]
name = "bitflags"
version = "2.10.0"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
[[package]]
name = "bumpalo"
version = "3.19.1"
version = "3.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
[[package]]
name = "bytes"
@@ -80,9 +89,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
[[package]]
name = "cc"
version = "1.2.55"
version = "1.2.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29"
checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -131,9 +140,9 @@ dependencies = [
[[package]]
name = "deranged"
version = "0.5.5"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
checksum = "2163a0e204a148662b6b6816d4b5d5668a5f2f8df498ccbd5cd0e864e78fecba"
dependencies = [
"powerfmt",
]
@@ -245,35 +254,35 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.31"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
version = "0.3.31"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
[[package]]
name = "futures-task"
version = "0.3.31"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
[[package]]
name = "futures-util"
version = "0.3.31"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
"futures-core",
"futures-task",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
@@ -386,9 +395,9 @@ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "js-sys"
version = "0.3.85"
version = "0.3.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
checksum = "93f0862381daaec758576dcc22eb7bbf4d7efd67328553f3b45a412a51a3fb21"
dependencies = [
"once_cell",
"wasm-bindgen",
@@ -402,9 +411,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.181"
version = "0.2.182"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5"
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
[[package]]
name = "libsqlite3-sys"
@@ -431,12 +440,27 @@ version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "matchers"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
dependencies = [
"regex-automata",
]
[[package]]
name = "matchit"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
[[package]]
name = "md5"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0"
[[package]]
name = "memchr"
version = "2.8.0"
@@ -572,6 +596,23 @@ dependencies = [
"bitflags",
]
[[package]]
name = "regex-automata"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
[[package]]
name = "rsqlite-vfs"
version = "0.1.0"
@@ -700,6 +741,12 @@ dependencies = [
"libc",
]
[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "smallvec"
version = "1.15.1"
@@ -723,9 +770,11 @@ dependencies = [
"axum",
"diesel",
"dotenvy",
"md5",
"serde",
"serde_json",
"tokio",
"tower-http",
"tracing-subscriber",
]
@@ -749,9 +798,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.114"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
@@ -868,6 +917,22 @@ dependencies = [
"tracing",
]
[[package]]
name = "tower-http"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
dependencies = [
"bitflags",
"bytes",
"http",
"http-body",
"pin-project-lite",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
@@ -918,19 +983,23 @@ version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
"regex-automata",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
]
[[package]]
name = "unicode-ident"
version = "1.0.23"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "valuable"
@@ -952,9 +1021,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasm-bindgen"
version = "0.2.108"
version = "0.2.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
checksum = "1de241cdc66a9d91bd84f097039eb140cdc6eec47e0cdbaf9d932a1dd6c35866"
dependencies = [
"cfg-if",
"once_cell",
@@ -965,9 +1034,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.108"
version = "0.2.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
checksum = "e12fdf6649048f2e3de6d7d5ff3ced779cdedee0e0baffd7dff5cdfa3abc8a52"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -975,9 +1044,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.108"
version = "0.2.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
checksum = "0e63d1795c565ac3462334c1e396fd46dbf481c40f51f5072c310717bc4fb309"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -988,9 +1057,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.108"
version = "0.2.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
checksum = "e9f9cdac23a5ce71f6bf9f8824898a501e511892791ea2a0c6b8568c68b9cb53"
dependencies = [
"unicode-ident",
]
@@ -1086,6 +1155,6 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "zmij"
version = "1.0.20"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"

View File

@@ -13,4 +13,6 @@ axum = "0.8.8"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"
tokio = { version = "1.49.0", features = ["full"] }
tracing-subscriber = "0.3.22"
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
md5 = "0.8.0"
tower-http = {version = "0.6.8", features = ["trace"]}

View File

@@ -3,10 +3,11 @@ mod routes;
mod schema;
mod state;
mod types;
use std::env;
use axum::Router;
use dotenvy::dotenv;
use std::env;
use tower_http::trace::TraceLayer;
use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
use crate::routes::system_router::system_routers;
use crate::routes::user_management_router::user_management_routs;
@@ -18,9 +19,16 @@ async fn main() {
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let state = AppState::new(&database_url)
.unwrap_or_else(|_| panic!("Error creating pool for {}", database_url));
tracing_subscriber::fmt::init();
tracing_subscriber::registry()
.with(
EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "tower_http=debug,axum=debug".into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
let app = Router::new()
.nest("/rest", system_routers().merge(user_management_routs()))
.layer(TraceLayer::new_for_http())
.with_state(state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3311").await.unwrap();

View File

@@ -1,17 +1,51 @@
use crate::state::AppState;
use crate::schema::users;
use crate::types::types::OpenSubSonicResponses;
use crate::{state::AppState, types::types::OpenSubsonicAuth};
use axum::extract::State;
use axum::{Json, Router, http::StatusCode, routing::get};
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
pub fn system_routers() -> Router<AppState> {
Router::new().route(
"/getOpenSubsonicExtensions",
get(get_opensubsonic_extentions).post(get_opensubsonic_extentions),
Router::new()
.route(
"/getOpenSubsonicExtensions.view",
get(get_opensubsonic_extensions).post(get_opensubsonic_extensions),
)
.route("/ping.view", get(ping).post(ping))
.route("/license.view", get(license).post(license))
}
async fn license(
State(db_con): State<AppState>,
user: OpenSubsonicAuth,
) -> (StatusCode, Json<OpenSubSonicResponses>) {
let conn = &mut db_con.pool.get().unwrap();
let result = users::table
.select(users::email)
.filter(users::username.eq(user.username))
.first::<String>(conn);
match result {
Ok(e) => (
StatusCode::OK,
Json(OpenSubSonicResponses::license_response(Some(e))),
),
Err(_) => (
StatusCode::OK,
Json(OpenSubSonicResponses::license_response(None)),
),
}
}
async fn ping(_user: OpenSubsonicAuth) -> (StatusCode, Json<OpenSubSonicResponses>) {
(
StatusCode::OK,
Json(OpenSubSonicResponses::open_subsonic_response()),
)
}
async fn get_opensubsonic_extentions() -> (StatusCode, Json<OpenSubSonicResponses>) {
async fn get_opensubsonic_extensions() -> (StatusCode, Json<OpenSubSonicResponses>) {
(
StatusCode::OK,
Json(OpenSubSonicResponses::open_subsonic_extentions()),
Json(OpenSubSonicResponses::open_subsonic_extensions()),
)
}

View File

@@ -13,8 +13,7 @@ use axum::{
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl, insert_into};
pub fn user_management_routs() -> Router<AppState> {
let userm_routs = Router::new().route("/createUser.view", get(create_user).post(create_user));
return userm_routs;
Router::new().route("/createUser.view", get(create_user).post(create_user))
}
fn check_if_user_exist(user_name: &String, db_con: &AppState) -> bool {
@@ -38,7 +37,9 @@ async fn create_user(
} else {
return (
StatusCode::BAD_REQUEST,
Json(OpenSubSonicResponses::open_subsonic_response()),
Json(OpenSubSonicResponses::open_subsonic_response_error(
OpenSubsonicErrorCode::MissingParameter,
)),
);
};
if check_if_user_exist(&params.username, &db_con) {

View File

@@ -10,3 +10,14 @@ pub struct OpenSubSonicExtension {
pub struct OpenSubSonicExtensions {
pub openSubsonicExtensions: Vec<OpenSubSonicExtension>,
}
#[derive(Serialize, Deserialize)]
pub struct LicenseBody {
pub valid: bool,
pub email: Option<String>,
}
#[derive(Serialize, Deserialize)]
pub struct LicenseResponse {
pub license: LicenseBody,
}

View File

@@ -1,6 +1,17 @@
use axum::{
Json, RequestPartsExt,
extract::{FromRequestParts, Query, RawForm},
http::{StatusCode, request::Parts},
middleware::{from_extractor, from_extractor_with_state},
};
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
use serde::{Deserialize, Serialize};
use crate::types::system::{OpenSubSonicExtension, OpenSubSonicExtensions};
use crate::{
schema::users,
state::AppState,
types::system::{LicenseBody, LicenseResponse, OpenSubSonicExtension, OpenSubSonicExtensions},
};
#[derive(Debug, Clone, Copy)]
pub enum OpenSubsonicErrorCode {
@@ -47,6 +58,118 @@ impl OpenSubsonicErrorCode {
}
}
#[derive(Deserialize)]
pub struct OpenSubsonicBaseQuery {
pub u: String,
pub p: Option<String>,
pub t: Option<String>,
pub s: Option<String>,
pub apiKey: Option<String>,
pub v: String,
pub c: String,
pub f: String,
}
#[derive(Deserialize)]
pub struct OpenSubsonicAuth {
pub username: String,
pub client: String,
pub version: String,
pub format: String,
}
impl FromRequestParts<AppState> for OpenSubsonicAuth {
type Rejection = (StatusCode, Json<OpenSubSonicResponses>);
async fn from_request_parts(
parts: &mut Parts,
state: &AppState,
) -> Result<Self, Self::Rejection> {
// ---- 1. Parse query safely ----
let Query(query) = Query::<OpenSubsonicBaseQuery>::from_request_parts(parts, state)
.await
.map_err(|_| {
(
StatusCode::BAD_REQUEST,
Json(OpenSubSonicResponses::open_subsonic_response_error(
OpenSubsonicErrorCode::MissingParameter,
)),
)
})?;
// ---- 2. Require token + salt ----
let (token, salt) = match (query.t.as_ref(), query.s.as_ref()) {
(Some(t), Some(s)) => (t, s),
_ => {
return Err((
StatusCode::BAD_REQUEST,
Json(OpenSubSonicResponses::open_subsonic_response_error(
OpenSubsonicErrorCode::AuthMechanismNotSupported,
)),
));
}
};
// ---- 3. DB lookup (blocking -> spawn_blocking) ----
let username = query.u.clone();
let pool = state.pool.clone();
let password = tokio::task::spawn_blocking(
move || -> Result<String, (StatusCode, Json<OpenSubSonicResponses>)> {
let mut conn = pool.get().map_err(|_| {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(OpenSubSonicResponses::open_subsonic_response_error(
OpenSubsonicErrorCode::Generic,
)),
)
})?;
users::table
.select(users::password)
.filter(users::username.eq(username))
.first::<String>(&mut conn)
.map_err(|_| {
(
StatusCode::UNAUTHORIZED,
Json(OpenSubSonicResponses::open_subsonic_response_error(
OpenSubsonicErrorCode::WrongUsernameOrPassword,
)),
)
})
},
)
.await
.map_err(|_| {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(OpenSubSonicResponses::open_subsonic_response_error(
OpenSubsonicErrorCode::Generic,
)),
)
})??;
// ---- 4. verify token ----
let expected_token = format!("{:x}", md5::compute(format!("{}{}", password, salt)));
if &expected_token != token {
return Err((
StatusCode::UNAUTHORIZED,
Json(OpenSubSonicResponses::open_subsonic_response_error(
OpenSubsonicErrorCode::NotAuthorized,
)),
));
}
Ok(OpenSubsonicAuth {
username: query.u,
client: query.c,
version: query.v,
format: query.f,
})
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BaseResponse<T> {
@@ -62,11 +185,17 @@ pub struct BaseResponse<T> {
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ErrorResponse {
struct ErrorResponseBody {
code: u8,
message: String,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ErrorResponse {
error: ErrorResponseBody,
}
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
pub enum OpenSubSonicResponses {
@@ -83,6 +212,10 @@ pub enum OpenSubSonicResponses {
subsonic_response: BaseResponse<OpenSubSonicExtensions>,
// openSubSonicExtensions: Vec<OpenSubSonicExtension>,
},
License {
#[serde(rename = "subsonic-response")]
subsonic_response: BaseResponse<LicenseResponse>,
},
}
impl OpenSubSonicResponses {
@@ -97,6 +230,27 @@ impl OpenSubSonicResponses {
}
}
pub fn license_response(email: Option<String>) -> Self {
match email {
Some(_) => Self::License {
subsonic_response: Self::base_response(Some(LicenseResponse {
license: LicenseBody {
valid: true,
email: email,
},
})),
},
None => Self::License {
subsonic_response: Self::base_response(Some(LicenseResponse {
license: LicenseBody {
valid: true,
email: None,
},
})),
},
}
}
pub fn open_subsonic_response_error(error_code: OpenSubsonicErrorCode) -> Self {
Self::OpenSubSonicResponseError {
subsonic_response: BaseResponse {
@@ -106,8 +260,10 @@ impl OpenSubSonicResponses {
server_version: "1.16.1".to_string(),
open_subsonic: true,
data: Some(ErrorResponse {
error: ErrorResponseBody {
code: error_code as u8,
message: error_code.description().to_string(),
},
}),
},
}
@@ -119,7 +275,7 @@ impl OpenSubSonicResponses {
}
}
pub fn open_subsonic_extentions() -> Self {
pub fn open_subsonic_extensions() -> Self {
let mut extension: Vec<OpenSubSonicExtension> = Vec::new();
extension.push(OpenSubSonicExtension {
name: "apiKeyAuthentication".to_string(),