Utoipa adds auth requirements

This commit is contained in:
Antoine Gersant 2025-01-15 19:53:55 -08:00
parent 2d92ac03ef
commit 9707f4a96d
3 changed files with 182 additions and 6 deletions
src/server

View file

@ -7,7 +7,6 @@ use tower_http::{
normalize_path::{NormalizePath, NormalizePathLayer},
services::ServeDir,
};
use utoipa::OpenApi;
use utoipa_axum::router::OpenApiRouter;
use utoipa_scalar::{Scalar, Servable};
@ -25,7 +24,7 @@ pub fn make_router(app: App) -> NormalizePath<Router> {
.fallback_service(ServeDir::new(&app.web_dir_path))
.layer(CompressionLayer::new());
let (open_api_router, open_api) = OpenApiRouter::with_openapi(doc::ApiDoc::openapi())
let (open_api_router, open_api) = OpenApiRouter::with_openapi(doc::open_api())
.nest("/api", api::router())
.split_for_parts();

View file

@ -113,6 +113,10 @@ async fn get_initial_setup(
get,
path = "/settings",
tag = "Configuration",
security(
("auth_token" = []),
("auth_query_param" = []),
),
responses(
(status = 200, body = dto::Settings),
),
@ -141,6 +145,10 @@ async fn get_settings(
put,
path = "/settings",
tag = "Configuration",
security(
("auth_token" = []),
("auth_query_param" = []),
),
request_body = dto::NewSettings,
)]
async fn put_settings(
@ -172,6 +180,10 @@ async fn put_settings(
get,
path = "/mount_dirs",
tag = "Configuration",
security(
("auth_token" = []),
("auth_query_param" = []),
),
responses(
(status = 200, body = Vec<dto::MountDir>),
),
@ -189,6 +201,10 @@ async fn get_mount_dirs(
put,
path = "/mount_dirs",
tag = "Configuration",
security(
("auth_token" = []),
("auth_query_param" = []),
),
request_body = Vec<dto::MountDir>,
)]
async fn put_mount_dirs(
@ -236,6 +252,10 @@ async fn post_auth(
get,
path = "/users",
tag = "User Management",
security(
("auth_token" = []),
("auth_query_param" = []),
),
responses(
(status = 200, body = Vec<dto::User>),
),
@ -253,6 +273,10 @@ async fn get_users(
post,
path = "/user",
tag = "User Management",
security(
("auth_token" = []),
("auth_query_param" = []),
),
request_body = dto::NewUser,
responses(
(status = 200),
@ -275,6 +299,10 @@ async fn post_user(
put,
path = "/user/{name}",
tag = "User Management",
security(
("auth_token" = []),
("auth_query_param" = []),
),
request_body = dto::UserUpdate,
responses(
(status = 200),
@ -309,6 +337,10 @@ async fn put_user(
delete,
path = "/user/{name}",
tag = "User Management",
security(
("auth_token" = []),
("auth_query_param" = []),
),
responses(
(status = 200),
(status = 404),
@ -329,7 +361,15 @@ async fn delete_user(
Ok(())
}
#[utoipa::path(post, path = "/trigger_index", tag = "Configuration")]
#[utoipa::path(
post,
path = "/trigger_index",
tag = "Configuration",
security(
("auth_token" = []),
("auth_query_param" = []),
),
)]
async fn post_trigger_index(
_admin_rights: AdminRights,
State(scanner): State<scanner::Scanner>,
@ -342,6 +382,10 @@ async fn post_trigger_index(
get,
path = "/index_status",
tag = "Configuration",
security(
("auth_token" = []),
("auth_query_param" = []),
),
responses(
(status = 200, body = dto::IndexStatus),
)
@ -423,6 +467,10 @@ fn albums_to_response(albums: Vec<index::Album>, api_version: APIMajorVersion) -
get,
path = "/browse",
tag = "File Browser",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(
("Accept-Version" = Option<i32>, Header, minimum = 7, maximum = 8)
),
@ -446,6 +494,10 @@ async fn get_browse_root(
get,
path = "/browse/{*path}",
tag = "File Browser",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(
("Accept-Version" = Option<i32>, Header, minimum = 7, maximum = 8),
("path", allow_reserved),
@ -471,6 +523,10 @@ async fn get_browse(
get,
path = "/flatten",
tag = "File Browser",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(
("Accept-Version" = Option<i32>, Header, minimum = 7, maximum = 8),
),
@ -495,6 +551,10 @@ async fn get_flatten_root(
get,
path = "/flatten/{*path}",
tag = "File Browser",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(
("Accept-Version" = Option<i32>, Header, minimum = 7, maximum = 8),
("path", allow_reserved),
@ -521,6 +581,10 @@ async fn get_flatten(
get,
path = "/albums",
tag = "Collection",
security(
("auth_token" = []),
("auth_query_param" = []),
),
responses(
(status = 200, body = Vec<dto::AlbumHeader>),
)
@ -544,6 +608,10 @@ async fn get_albums(
get,
path = "/artists",
tag = "Collection",
security(
("auth_token" = []),
("auth_query_param" = []),
),
responses(
(status = 200, body = Vec<dto::ArtistHeader>),
)
@ -567,6 +635,10 @@ async fn get_artists(
get,
path = "/artists/{artist}",
tag = "Collection",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(("artist",)),
responses(
(status = 200, body = dto::Artist),
@ -584,6 +656,10 @@ async fn get_artist(
get,
path = "/artists/{artists}/albums/{album}",
tag = "Collection",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(
("artists",),
("album",),
@ -608,6 +684,10 @@ async fn get_album(
post, // post because of https://github.com/whatwg/fetch/issues/551
path = "/songs",
tag = "Collection",
security(
("auth_token" = []),
("auth_query_param" = []),
),
request_body = dto::GetSongsBulkInput,
responses(
(status = 200, body = dto::GetSongsBulkOutput),
@ -639,6 +719,10 @@ async fn get_songs(
get,
path = "/peaks/{*path}",
tag = "Media",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(("path", allow_reserved)),
responses(
(status = 200, body = [u8]),
@ -659,6 +743,10 @@ async fn get_peaks(
get,
path = "/albums/random",
tag = "Collection",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(
("Accept-Version" = Option<i32>, Header, minimum = 7, maximum = 8),
dto::GetRandomAlbumsParameters,
@ -689,6 +777,10 @@ async fn get_random_albums(
get,
path = "/albums/recent",
tag = "Collection",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(
("Accept-Version" = Option<i32>, Header, minimum = 7, maximum = 8),
dto::GetRecentAlbumsParameters
@ -716,6 +808,10 @@ async fn get_recent_albums(
get,
path = "/genres",
tag = "Collection",
security(
("auth_token" = []),
("auth_query_param" = []),
),
responses(
(status = 200, body = Vec<dto::GenreHeader>),
)
@ -738,6 +834,10 @@ async fn get_genres(
get,
path = "/genres/{genre}",
tag = "Collection",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(("genre",)),
responses(
(status = 200, body = Vec<dto::Genre>),
@ -755,6 +855,10 @@ async fn get_genre(
get,
path = "/genres/{genre}/albums",
tag = "Collection",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(("genre",)),
responses(
(status = 200, body = Vec<dto::AlbumHeader>),
@ -779,6 +883,10 @@ async fn get_genre_albums(
get,
path = "/genres/{genre}/artists",
tag = "Collection",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(("genre",)),
responses(
(status = 200, body = Vec<dto::ArtistHeader>),
@ -803,6 +911,10 @@ async fn get_genre_artists(
get,
path = "/genres/{genre}/songs",
tag = "Collection",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(("genre",)),
responses(
(status = 200, body = dto::SongList),
@ -829,6 +941,10 @@ async fn get_genre_songs(
get,
path = "/search/{*query}",
tag = "Collection",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(
("Accept-Version" = Option<i32>, Header, minimum = 7, maximum = 8),
("query", allow_reserved),
@ -874,6 +990,10 @@ async fn get_search(
get,
path = "/playlists",
tag = "Playlists",
security(
("auth_token" = []),
("auth_query_param" = []),
),
responses(
(status = 200, body = Vec<dto::PlaylistHeader>),
)
@ -892,6 +1012,10 @@ async fn get_playlists(
put,
path = "/playlist/{name}",
tag = "Playlists",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(("name",)),
request_body = dto::SavePlaylistInput,
)]
@ -918,6 +1042,10 @@ async fn put_playlist(
get,
path = "/playlist/{name}",
tag = "Playlists",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(
("Accept-Version" = Option<i32>, Header, minimum = 7, maximum = 8),
("name",),
@ -955,6 +1083,10 @@ async fn get_playlist(
delete,
path = "/playlist/{name}",
tag = "Playlists",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(("name",)),
)]
async fn delete_playlist(
@ -972,6 +1104,10 @@ async fn delete_playlist(
get,
path = "/audio/{*path}",
tag = "Media",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(("path", allow_reserved)),
responses(
(status = 206, body = [u8]),
@ -1002,6 +1138,10 @@ async fn get_audio(
get,
path = "/thumbnail/{*path}",
tag = "Media",
security(
("auth_token" = []),
("auth_query_param" = []),
),
params(
("path", allow_reserved),
dto::ThumbnailOptions

View file

@ -1,4 +1,41 @@
use utoipa::OpenApi;
use utoipa::openapi::{
security::{ApiKey, ApiKeyValue, HttpAuthScheme, HttpBuilder, SecurityScheme},
ComponentsBuilder, ContactBuilder, InfoBuilder, License, OpenApi, OpenApiBuilder,
};
#[derive(OpenApi)]
pub struct ApiDoc;
pub fn open_api() -> OpenApi {
let auth_token_description = "Authentication token acquired from the `/auth` endpoint";
OpenApiBuilder::new()
.info(
InfoBuilder::new()
.title(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION"))
.license(Some(License::new("MIT")))
.contact(Some(
ContactBuilder::new().name(Some("Antoine Gersant")).build(),
))
.build(),
)
.components(Some(
ComponentsBuilder::new()
.security_scheme(
"auth_header",
SecurityScheme::Http(
HttpBuilder::new()
.scheme(HttpAuthScheme::Bearer)
.description(Some(auth_token_description))
.build(),
),
)
.security_scheme(
"auth_query_param",
SecurityScheme::ApiKey(ApiKey::Query(ApiKeyValue::with_description(
"auth_token",
auth_token_description,
))),
)
.build(),
))
.build()
}