Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 679a4ad322 |
@@ -68,7 +68,9 @@ jobs:
|
||||
env:
|
||||
ROOT_DIRECTORY: "/tmp"
|
||||
DATABASE_URL: "postgres://${{ secrets.POSTGRES_USER }}:${{ secrets.POSTGRES_PASSWORD }}@localhost:5432/${{ secrets.POSTGRES_DB }}"
|
||||
run: cargo test --verbose --
|
||||
run: |
|
||||
cat .env.sample | head -1 > .env
|
||||
cargo test --verbose --
|
||||
|
||||
- name: Run clippy
|
||||
run: cargo clippy -- -D warnings
|
||||
|
||||
Generated
+183
-6
@@ -17,12 +17,27 @@ version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
|
||||
[[package]]
|
||||
name = "atoi"
|
||||
version = "2.0.0"
|
||||
@@ -93,6 +108,29 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-extra"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45bf463831f5131b7d3c756525b305d40f1185b688565648a92e1392ca35713d"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-core",
|
||||
"bytes",
|
||||
"cookie",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.75"
|
||||
@@ -108,6 +146,12 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
@@ -222,6 +266,17 @@ dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"time",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
@@ -588,8 +643,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -762,19 +819,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "icarus"
|
||||
version = "0.1.100"
|
||||
version = "0.1.101"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-extra",
|
||||
"base64 0.21.7",
|
||||
"common-multipart-rfc7578",
|
||||
"futures",
|
||||
"icarus_envy",
|
||||
"icarus_meta",
|
||||
"icarus_models",
|
||||
"josekit",
|
||||
"jsonwebtoken",
|
||||
"mime_guess",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"tempfile",
|
||||
"thiserror 1.0.69",
|
||||
"time",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
@@ -804,9 +866,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "icarus_models"
|
||||
version = "0.5.1"
|
||||
source = "git+ssh://git@git.kundeng.us/phoenix/icarus_models.git?tag=v0.5.1-devel-1c5de9dc26-111#1c5de9dc26099ac5f21e1dc7a1f7d0dbb892b34b"
|
||||
version = "0.5.2"
|
||||
source = "git+ssh://git@git.kundeng.us/phoenix/icarus_models.git?tag=v0.5.2-devel-d3251f935e-111#d3251f935e76caa110727203d910ee0683a668a0"
|
||||
dependencies = [
|
||||
"josekit",
|
||||
"rand 0.9.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -937,6 +1000,23 @@ version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "josekit"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a808e078330e6af222eb0044b71d4b1ff981bfef43e7bc8133a88234e0c86a0c"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.22.1",
|
||||
"flate2",
|
||||
"openssl",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
@@ -947,6 +1027,21 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonwebtoken"
|
||||
version = "9.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"js-sys",
|
||||
"pem",
|
||||
"ring",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"simple_asn1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
@@ -1134,6 +1229,16 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint-dig"
|
||||
version = "0.8.4"
|
||||
@@ -1296,6 +1401,16 @@ version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pem"
|
||||
version = "3.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "0.7.0"
|
||||
@@ -1466,6 +1581,49 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom 0.2.16",
|
||||
"libc",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.9.8"
|
||||
@@ -1581,6 +1739,7 @@ version = "1.0.140"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
@@ -1665,6 +1824,18 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simple_asn1"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"thiserror 2.0.12",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.10"
|
||||
@@ -1728,7 +1899,7 @@ version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"crc",
|
||||
"crossbeam-queue",
|
||||
@@ -1804,7 +1975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64",
|
||||
"base64 0.22.1",
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
@@ -1848,7 +2019,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64",
|
||||
"base64 0.22.1",
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"crc",
|
||||
@@ -2279,6 +2450,12 @@ version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
|
||||
+8
-3
@@ -1,25 +1,30 @@
|
||||
[package]
|
||||
name = "icarus"
|
||||
version = "0.1.100"
|
||||
version = "0.1.101"
|
||||
edition = "2024"
|
||||
rust-version = "1.88"
|
||||
|
||||
[dependencies]
|
||||
axum = { version = "0.8.4", features = ["multipart"] }
|
||||
axum-extra = { version = "0.10.1", features = ["cookie"] }
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = { version = "1.0.140" }
|
||||
tower = { version = "0.5.2", features = ["full"] }
|
||||
tokio = { version = "1.45.1", features = ["full"] }
|
||||
tokio-util = { version = "0.7.15", features = ["io"] }
|
||||
tower-http = { version = "0.6.6", features = ["timeout"] }
|
||||
tower-http = { version = "0.6.6", features = ["cors", "timeout"] }
|
||||
tracing-subscriber = "0.3.19"
|
||||
futures = { version = "0.3.31" }
|
||||
mime_guess = { version = "2.0.5" }
|
||||
uuid = { version = "1.17.0", features = ["v4", "serde"] }
|
||||
sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-native-tls", "time", "uuid"] }
|
||||
time = { version = "0.3.41", features = ["formatting", "macros", "parsing", "serde"] }
|
||||
thiserror = "1.0"
|
||||
base64 = "0.21"
|
||||
jsonwebtoken = { version = "9.3.1" }
|
||||
josekit = { version = "0.10.1" }
|
||||
icarus_meta = { git = "ssh://git@git.kundeng.us/phoenix/icarus_meta.git", tag = "v0.3.0-devel-f4b71de969-680" }
|
||||
icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.5.1-devel-1c5de9dc26-111" }
|
||||
icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.5.2-devel-d3251f935e-111" }
|
||||
icarus_envy = { git = "ssh://git@git.kundeng.us/phoenix/icarus_envy.git", tag = "v0.3.0-devel-d73fba9899-006" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
// use std::collections::BTreeMap;
|
||||
// use std::sync::Arc;
|
||||
|
||||
use axum::{
|
||||
Json,
|
||||
http::{Request, StatusCode},
|
||||
middleware::Next,
|
||||
response::IntoResponse,
|
||||
};
|
||||
use axum_extra::extract::cookie::CookieJar;
|
||||
use jsonwebtoken::{DecodingKey, Validation, decode};
|
||||
use serde::{Deserialize, Serialize};
|
||||
// use serde_json::{json, Value};
|
||||
use thiserror::Error;
|
||||
// use time::OffsetDateTime;
|
||||
|
||||
fn deserialize_i64_from_f64<'de, D>(deserializer: D) -> Result<i64, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let val = f64::deserialize(deserializer)?;
|
||||
// Handle NaN and infinity cases
|
||||
if val.is_nan() || val.is_infinite() {
|
||||
return Err(serde::de::Error::custom("invalid float value"));
|
||||
}
|
||||
// Round to nearest integer and convert
|
||||
let rounded = val.round();
|
||||
// Check if the rounded value can fit in i64
|
||||
if rounded < (i64::MIN as f64) || rounded > (i64::MAX as f64) {
|
||||
return Err(serde::de::Error::custom("float out of i64 range"));
|
||||
}
|
||||
Ok(rounded as i64)
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct UserClaims {
|
||||
pub iss: String,
|
||||
pub aud: String, // Audience
|
||||
pub sub: String, // Subject (user ID)
|
||||
#[serde(deserialize_with = "deserialize_i64_from_f64")]
|
||||
pub exp: i64, // Expiration time (UTC timestamp)
|
||||
#[serde(deserialize_with = "deserialize_i64_from_f64")]
|
||||
pub iat: i64, // Issued at (UTC timestamp)
|
||||
// pub azp: String,
|
||||
// pub gty: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub roles: Option<Vec<String>>, // Optional roles
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum JwtError {
|
||||
#[error("Token creation failed")]
|
||||
TokenCreation,
|
||||
#[error("Token verification failed")]
|
||||
TokenVerification,
|
||||
#[error("Invalid token")]
|
||||
InvalidToken,
|
||||
#[error("Token expired")]
|
||||
ExpiredToken,
|
||||
#[error("Invalid key")]
|
||||
InvalidKey,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct ErrorResponse {
|
||||
pub status: &'static str,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
pub async fn auth<B>(
|
||||
cookie_jar: CookieJar,
|
||||
req: Request<axum::body::Body>,
|
||||
next: Next,
|
||||
) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
|
||||
println!("Cookie: {cookie_jar:?}");
|
||||
|
||||
let token = cookie_jar
|
||||
.get("token")
|
||||
.map(|cookie| cookie.value().to_string())
|
||||
.or_else(|| {
|
||||
req.headers()
|
||||
.get(axum::http::header::AUTHORIZATION)
|
||||
.and_then(|auth_header| auth_header.to_str().ok())
|
||||
.and_then(|auth_value| {
|
||||
println!("Auth value: {auth_value:?}");
|
||||
auth_value.strip_prefix("Bearer ").map(String::from)
|
||||
})
|
||||
});
|
||||
|
||||
let token = token.ok_or_else(|| {
|
||||
let json_error = ErrorResponse {
|
||||
status: "fail",
|
||||
message: "You are not logged in, please provide token".to_string(),
|
||||
};
|
||||
(StatusCode::UNAUTHORIZED, Json(json_error))
|
||||
})?;
|
||||
|
||||
let secret_key = icarus_envy::environment::get_secret_main_key().await;
|
||||
|
||||
let mut validation = Validation::new(jsonwebtoken::Algorithm::HS256);
|
||||
validation.set_audience(&["icarus"]); // Must match exactly what's in the token
|
||||
let claims = decode::<UserClaims>(
|
||||
&token,
|
||||
// TODO: Replace with code to get secret from env
|
||||
&DecodingKey::from_secret(secret_key.as_ref()),
|
||||
&validation,
|
||||
)
|
||||
.map_err(|err| {
|
||||
eprintln!("Error: {err:?}");
|
||||
let json_error = ErrorResponse {
|
||||
status: "fail",
|
||||
message: "Invalid token - Error decoding claims".to_string(),
|
||||
};
|
||||
(StatusCode::UNAUTHORIZED, Json(json_error))
|
||||
})?
|
||||
.claims;
|
||||
|
||||
println!("Claims: {claims:?}");
|
||||
|
||||
Ok(next.run(req).await)
|
||||
}
|
||||
+159
-22
@@ -1,3 +1,4 @@
|
||||
pub mod auth;
|
||||
pub mod callers;
|
||||
|
||||
pub mod db {
|
||||
@@ -48,96 +49,146 @@ pub mod init {
|
||||
use std::time::Duration;
|
||||
use tower_http::timeout::TimeoutLayer;
|
||||
|
||||
use axum::http::{
|
||||
HeaderValue, Method,
|
||||
header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE},
|
||||
};
|
||||
|
||||
pub async fn routes() -> axum::Router {
|
||||
axum::Router::new()
|
||||
.route(crate::ROOT, get(crate::root))
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUESONG,
|
||||
post(crate::callers::song::endpoint::queue_song),
|
||||
post(crate::callers::song::endpoint::queue_song).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUESONG,
|
||||
patch(crate::callers::song::endpoint::update_song_queue_status),
|
||||
patch(crate::callers::song::endpoint::update_song_queue_status).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUESONGLINKUSERID,
|
||||
patch(crate::callers::song::endpoint::link_user_id),
|
||||
patch(crate::callers::song::endpoint::link_user_id).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUESONGDATA,
|
||||
get(crate::callers::song::endpoint::download_flac),
|
||||
get(crate::callers::song::endpoint::download_flac).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::NEXTQUEUESONG,
|
||||
get(crate::callers::song::endpoint::fetch_queue_song),
|
||||
get(crate::callers::song::endpoint::fetch_queue_song).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUESONGUPDATE,
|
||||
patch(crate::callers::song::endpoint::update_song_queue),
|
||||
patch(crate::callers::song::endpoint::update_song_queue).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUESONGDATAWIPE,
|
||||
patch(crate::callers::song::endpoint::wipe_data_from_song_queue),
|
||||
patch(crate::callers::song::endpoint::wipe_data_from_song_queue).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUEMETADATA,
|
||||
post(crate::callers::metadata::endpoint::queue_metadata),
|
||||
post(crate::callers::metadata::endpoint::queue_metadata).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUEMETADATA,
|
||||
get(crate::callers::metadata::endpoint::fetch_metadata),
|
||||
get(crate::callers::metadata::endpoint::fetch_metadata).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUECOVERART,
|
||||
post(crate::callers::coverart::endpoint::queue),
|
||||
post(crate::callers::coverart::endpoint::queue).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUECOVERARTDATA,
|
||||
get(crate::callers::coverart::endpoint::fetch_coverart_with_data),
|
||||
get(crate::callers::coverart::endpoint::fetch_coverart_with_data).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUECOVERART,
|
||||
get(crate::callers::coverart::endpoint::fetch_coverart_no_data),
|
||||
get(crate::callers::coverart::endpoint::fetch_coverart_no_data).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUECOVERARTLINK,
|
||||
patch(crate::callers::coverart::endpoint::link),
|
||||
patch(crate::callers::coverart::endpoint::link).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUECOVERARTDATAWIPE,
|
||||
patch(crate::callers::coverart::endpoint::wipe_data_from_coverart_queue),
|
||||
patch(crate::callers::coverart::endpoint::wipe_data_from_coverart_queue)
|
||||
.route_layer(axum::middleware::from_fn(
|
||||
crate::auth::auth::<axum::body::Body>,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::CREATESONG,
|
||||
post(crate::callers::song::endpoint::create_metadata),
|
||||
post(crate::callers::song::endpoint::create_metadata).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::CREATECOVERART,
|
||||
post(crate::callers::coverart::endpoint::create_coverart),
|
||||
post(crate::callers::coverart::endpoint::create_coverart).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::GETSONGS,
|
||||
get(crate::callers::song::endpoint::get_songs),
|
||||
get(crate::callers::song::endpoint::get_songs).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::GETCOVERART,
|
||||
get(crate::callers::coverart::endpoint::get_coverart),
|
||||
get(crate::callers::coverart::endpoint::get_coverart).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::DOWNLOADCOVERART,
|
||||
get(crate::callers::coverart::endpoint::download_coverart),
|
||||
get(crate::callers::coverart::endpoint::download_coverart).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::STREAMSONG,
|
||||
get(crate::callers::song::endpoint::stream_song),
|
||||
get(crate::callers::song::endpoint::stream_song).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::DOWNLOADSONG,
|
||||
get(crate::callers::song::endpoint::download_song),
|
||||
get(crate::callers::song::endpoint::download_song).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::DELETESONG,
|
||||
delete(crate::callers::song::endpoint::delete_song),
|
||||
delete(crate::callers::song::endpoint::delete_song).route_layer(
|
||||
axum::middleware::from_fn(crate::auth::auth::<axum::body::Body>),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -148,11 +199,18 @@ pub mod init {
|
||||
// TODO: Look into handling this. Seems redundant to run migrations multiple times
|
||||
crate::db::migrations(&pool).await;
|
||||
|
||||
let cors = tower_http::cors::CorsLayer::new()
|
||||
.allow_origin("http://localhost:3000".parse::<HeaderValue>().unwrap())
|
||||
.allow_methods([Method::GET, Method::POST, Method::PATCH, Method::DELETE])
|
||||
.allow_credentials(true)
|
||||
.allow_headers([AUTHORIZATION, ACCEPT, CONTENT_TYPE]);
|
||||
|
||||
routes()
|
||||
.await
|
||||
.layer(axum::Extension(pool))
|
||||
.layer(axum::extract::DefaultBodyLimit::max(1024 * 1024 * 1024))
|
||||
.layer(TimeoutLayer::new(Duration::from_secs(300)))
|
||||
.layer(cors)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,6 +333,36 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn token_fields() -> (String, String, String) {
|
||||
(
|
||||
String::from("What a twist!"),
|
||||
String::from("icarus_test"),
|
||||
String::from("icarus"),
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn test_token() -> Result<String, josekit::JoseError> {
|
||||
let key: String = icarus_envy::environment::get_secret_main_key().await;
|
||||
let (message, issuer, audience) = token_fields();
|
||||
|
||||
match icarus_models::token::create_token(&key, &message, &issuer, &audience) {
|
||||
Ok((access_token, _some_time)) => Ok(access_token),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn bearer_auth() -> String {
|
||||
let token = match test_token().await {
|
||||
Ok(access_token) => access_token,
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {err:?}");
|
||||
String::new()
|
||||
}
|
||||
};
|
||||
|
||||
format!("Bearer {token}")
|
||||
}
|
||||
|
||||
// TODO: Put the *_req() functions in their own module
|
||||
async fn song_queue_req(
|
||||
app: &axum::Router,
|
||||
@@ -290,6 +378,7 @@ mod tests {
|
||||
.method(axum::http::Method::POST)
|
||||
.uri(crate::callers::endpoints::QUEUESONG)
|
||||
.header(axum::http::header::CONTENT_TYPE, content_type)
|
||||
.header(axum::http::header::AUTHORIZATION, bearer_auth().await)
|
||||
.body(axum::body::Body::from_stream(body))
|
||||
.unwrap();
|
||||
app.clone().oneshot(req).await
|
||||
@@ -309,6 +398,7 @@ mod tests {
|
||||
.method(axum::http::Method::PATCH)
|
||||
.uri(crate::callers::endpoints::QUEUESONGLINKUSERID)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.header(axum::http::header::AUTHORIZATION, bearer_auth().await)
|
||||
.body(axum::body::Body::from(payload.to_string()))
|
||||
.unwrap();
|
||||
|
||||
@@ -322,6 +412,7 @@ mod tests {
|
||||
.method(axum::http::Method::GET)
|
||||
.uri(crate::callers::endpoints::NEXTQUEUESONG)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.header(axum::http::header::AUTHORIZATION, bearer_auth().await)
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap();
|
||||
app.clone().oneshot(fetch_req).await
|
||||
@@ -337,6 +428,7 @@ mod tests {
|
||||
.method(axum::http::Method::GET)
|
||||
.uri(uri)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.header(axum::http::header::AUTHORIZATION, bearer_auth().await)
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap();
|
||||
|
||||
@@ -355,6 +447,7 @@ mod tests {
|
||||
.method(axum::http::Method::GET)
|
||||
.uri(uri)
|
||||
.header(axum::http::header::CONTENT_TYPE, "audio/flac")
|
||||
.header(axum::http::header::AUTHORIZATION, bearer_auth().await)
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap();
|
||||
|
||||
@@ -375,6 +468,7 @@ mod tests {
|
||||
.method(axum::http::Method::POST)
|
||||
.uri(crate::callers::endpoints::QUEUECOVERART)
|
||||
.header(axum::http::header::CONTENT_TYPE, content_type)
|
||||
.header(axum::http::header::AUTHORIZATION, bearer_auth().await)
|
||||
.body(axum::body::Body::from_stream(body))
|
||||
.unwrap();
|
||||
|
||||
@@ -392,6 +486,7 @@ mod tests {
|
||||
.method(axum::http::Method::POST)
|
||||
.uri(crate::callers::endpoints::QUEUEMETADATA)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.header(axum::http::header::AUTHORIZATION, bearer_auth().await)
|
||||
.body(axum::body::Body::from(payload.to_string()))
|
||||
.unwrap();
|
||||
|
||||
@@ -412,6 +507,7 @@ mod tests {
|
||||
.method(axum::http::Method::PATCH)
|
||||
.uri(crate::callers::endpoints::QUEUECOVERARTLINK)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.header(axum::http::header::AUTHORIZATION, bearer_auth().await)
|
||||
.body(axum::body::Body::from(payload.to_string()))
|
||||
.unwrap();
|
||||
|
||||
@@ -431,6 +527,7 @@ mod tests {
|
||||
.method(axum::http::Method::POST)
|
||||
.uri(crate::callers::endpoints::CREATECOVERART)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.header(axum::http::header::AUTHORIZATION, bearer_auth().await)
|
||||
.body(axum::body::Body::from(payload.to_string()))
|
||||
.unwrap();
|
||||
app.clone().oneshot(req).await
|
||||
@@ -447,6 +544,7 @@ mod tests {
|
||||
.method(axum::http::Method::POST)
|
||||
.uri(crate::callers::endpoints::CREATESONG)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.header(axum::http::header::AUTHORIZATION, bearer_auth().await)
|
||||
.body(axum::body::Body::from(payload.to_string()))
|
||||
.unwrap();
|
||||
|
||||
@@ -466,6 +564,7 @@ mod tests {
|
||||
.method(axum::http::Method::PATCH)
|
||||
.uri(crate::callers::endpoints::QUEUESONG)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.header(axum::http::header::AUTHORIZATION, bearer_auth().await)
|
||||
.body(axum::body::Body::from(payload.to_string()))
|
||||
.unwrap();
|
||||
|
||||
@@ -486,6 +585,7 @@ mod tests {
|
||||
.method(axum::http::Method::GET)
|
||||
.uri(uri)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.header(axum::http::header::AUTHORIZATION, bearer_auth().await)
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap();
|
||||
|
||||
@@ -950,6 +1050,10 @@ mod tests {
|
||||
.method(axum::http::Method::PATCH)
|
||||
.uri(uri)
|
||||
.header(axum::http::header::CONTENT_TYPE, content_type)
|
||||
.header(
|
||||
axum::http::header::AUTHORIZATION,
|
||||
bearer_auth().await,
|
||||
)
|
||||
.body(axum::body::Body::from_stream(body))
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -1412,6 +1516,10 @@ mod tests {
|
||||
.method(axum::http::Method::GET)
|
||||
.uri(uri)
|
||||
.header(axum::http::header::CONTENT_TYPE, "image/jpeg")
|
||||
.header(
|
||||
axum::http::header::AUTHORIZATION,
|
||||
bearer_auth().await,
|
||||
)
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -1680,6 +1788,7 @@ mod tests {
|
||||
.method(axum::http::Method::PATCH)
|
||||
.uri(crate::callers::endpoints::QUEUESONGDATAWIPE)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.header(axum::http::header::AUTHORIZATION, bearer_auth().await)
|
||||
.body(axum::body::Body::from(payload.to_string()))
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -1800,6 +1909,10 @@ mod tests {
|
||||
axum::http::header::CONTENT_TYPE,
|
||||
"application/json",
|
||||
)
|
||||
.header(
|
||||
axum::http::header::AUTHORIZATION,
|
||||
bearer_auth().await,
|
||||
)
|
||||
.body(axum::body::Body::from(payload.to_string()))
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -1873,6 +1986,10 @@ mod tests {
|
||||
.method(axum::http::Method::GET)
|
||||
.uri(uri)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.header(
|
||||
axum::http::header::AUTHORIZATION,
|
||||
super::bearer_auth().await,
|
||||
)
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -1926,6 +2043,10 @@ mod tests {
|
||||
.method(axum::http::Method::GET)
|
||||
.uri(uri)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.header(
|
||||
axum::http::header::AUTHORIZATION,
|
||||
super::bearer_auth().await,
|
||||
)
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -2011,6 +2132,10 @@ mod tests {
|
||||
axum::http::Request::builder()
|
||||
.method(axum::http::Method::GET)
|
||||
.uri(&uri)
|
||||
.header(
|
||||
axum::http::header::AUTHORIZATION,
|
||||
super::bearer_auth().await,
|
||||
)
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -2066,6 +2191,10 @@ mod tests {
|
||||
axum::http::Request::builder()
|
||||
.method(axum::http::Method::GET)
|
||||
.uri(&uri)
|
||||
.header(
|
||||
axum::http::header::AUTHORIZATION,
|
||||
super::bearer_auth().await,
|
||||
)
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -2122,6 +2251,10 @@ mod tests {
|
||||
axum::http::Request::builder()
|
||||
.method(axum::http::Method::GET)
|
||||
.uri(&uri)
|
||||
.header(
|
||||
axum::http::header::AUTHORIZATION,
|
||||
super::bearer_auth().await,
|
||||
)
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -2257,6 +2390,10 @@ mod tests {
|
||||
axum::http::Request::builder()
|
||||
.method(axum::http::Method::DELETE)
|
||||
.uri(&uri)
|
||||
.header(
|
||||
axum::http::header::AUTHORIZATION,
|
||||
super::bearer_auth().await,
|
||||
)
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user