various: simplify code; work on security and performance
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I9a5114addcab5fbff430ab2b919b83466a6a6964
This commit is contained in:
parent
016841b200
commit
c4adc4e3e0
75 changed files with 12921 additions and 358 deletions
|
|
@ -40,6 +40,9 @@ pub fn create_router(state: AppState) -> Router {
|
|||
config: login_governor,
|
||||
});
|
||||
|
||||
// Public routes (no auth required)
|
||||
let public_routes = Router::new().route("/s/{token}", get(routes::social::access_shared_media));
|
||||
|
||||
// Read-only routes: any authenticated user (Viewer+)
|
||||
let viewer_routes = Router::new()
|
||||
.route("/health", get(routes::health::health))
|
||||
|
|
@ -87,7 +90,82 @@ pub fn create_router(state: AppState) -> Router {
|
|||
.route("/webhooks", get(routes::webhooks::list_webhooks))
|
||||
// Auth endpoints (self-service) — login handled separately with stricter rate limit
|
||||
.route("/auth/logout", post(routes::auth::logout))
|
||||
.route("/auth/me", get(routes::auth::me));
|
||||
.route("/auth/me", get(routes::auth::me))
|
||||
// Social: ratings & comments (read)
|
||||
.route(
|
||||
"/media/{id}/ratings",
|
||||
get(routes::social::get_media_ratings),
|
||||
)
|
||||
.route(
|
||||
"/media/{id}/comments",
|
||||
get(routes::social::get_media_comments),
|
||||
)
|
||||
// Favorites (read)
|
||||
.route("/favorites", get(routes::social::list_favorites))
|
||||
// Playlists (read)
|
||||
.route("/playlists", get(routes::playlists::list_playlists))
|
||||
.route("/playlists/{id}", get(routes::playlists::get_playlist))
|
||||
.route("/playlists/{id}/items", get(routes::playlists::list_items))
|
||||
.route(
|
||||
"/playlists/{id}/shuffle",
|
||||
post(routes::playlists::shuffle_playlist),
|
||||
)
|
||||
// Analytics (read)
|
||||
.route(
|
||||
"/analytics/most-viewed",
|
||||
get(routes::analytics::get_most_viewed),
|
||||
)
|
||||
.route(
|
||||
"/analytics/recently-viewed",
|
||||
get(routes::analytics::get_recently_viewed),
|
||||
)
|
||||
.route("/analytics/events", post(routes::analytics::record_event))
|
||||
.route(
|
||||
"/media/{id}/progress",
|
||||
get(routes::analytics::get_watch_progress),
|
||||
)
|
||||
.route(
|
||||
"/media/{id}/progress",
|
||||
post(routes::analytics::update_watch_progress),
|
||||
)
|
||||
// Subtitles (read)
|
||||
.route(
|
||||
"/media/{id}/subtitles",
|
||||
get(routes::subtitles::list_subtitles),
|
||||
)
|
||||
.route(
|
||||
"/media/{media_id}/subtitles/{subtitle_id}/content",
|
||||
get(routes::subtitles::get_subtitle_content),
|
||||
)
|
||||
// Enrichment (read)
|
||||
.route(
|
||||
"/media/{id}/external-metadata",
|
||||
get(routes::enrichment::get_external_metadata),
|
||||
)
|
||||
// Transcode (read)
|
||||
.route("/transcode/{id}", get(routes::transcode::get_session))
|
||||
.route("/transcode", get(routes::transcode::list_sessions))
|
||||
// Streaming
|
||||
.route(
|
||||
"/media/{id}/stream/hls/master.m3u8",
|
||||
get(routes::streaming::hls_master_playlist),
|
||||
)
|
||||
.route(
|
||||
"/media/{id}/stream/hls/{profile}/playlist.m3u8",
|
||||
get(routes::streaming::hls_variant_playlist),
|
||||
)
|
||||
.route(
|
||||
"/media/{id}/stream/hls/{profile}/{segment}",
|
||||
get(routes::streaming::hls_segment),
|
||||
)
|
||||
.route(
|
||||
"/media/{id}/stream/dash/manifest.mpd",
|
||||
get(routes::streaming::dash_manifest),
|
||||
)
|
||||
.route(
|
||||
"/media/{id}/stream/dash/{profile}/{segment}",
|
||||
get(routes::streaming::dash_segment),
|
||||
);
|
||||
|
||||
// Write routes: Editor+ required
|
||||
let editor_routes = Router::new()
|
||||
|
|
@ -190,6 +268,58 @@ pub fn create_router(state: AppState) -> Router {
|
|||
)
|
||||
// Webhooks
|
||||
.route("/webhooks/test", post(routes::webhooks::test_webhook))
|
||||
// Social: ratings & comments (write)
|
||||
.route("/media/{id}/ratings", post(routes::social::rate_media))
|
||||
.route("/media/{id}/comments", post(routes::social::add_comment))
|
||||
// Favorites (write)
|
||||
.route("/favorites", post(routes::social::add_favorite))
|
||||
.route(
|
||||
"/favorites/{media_id}",
|
||||
delete(routes::social::remove_favorite),
|
||||
)
|
||||
// Share links
|
||||
.route("/share", post(routes::social::create_share_link))
|
||||
// Playlists (write)
|
||||
.route("/playlists", post(routes::playlists::create_playlist))
|
||||
.route("/playlists/{id}", patch(routes::playlists::update_playlist))
|
||||
.route(
|
||||
"/playlists/{id}",
|
||||
delete(routes::playlists::delete_playlist),
|
||||
)
|
||||
.route("/playlists/{id}/items", post(routes::playlists::add_item))
|
||||
.route(
|
||||
"/playlists/{id}/items/{media_id}",
|
||||
delete(routes::playlists::remove_item),
|
||||
)
|
||||
.route(
|
||||
"/playlists/{id}/reorder",
|
||||
post(routes::playlists::reorder_item),
|
||||
)
|
||||
// Subtitles (write)
|
||||
.route(
|
||||
"/media/{id}/subtitles",
|
||||
post(routes::subtitles::add_subtitle),
|
||||
)
|
||||
.route(
|
||||
"/subtitles/{id}",
|
||||
delete(routes::subtitles::delete_subtitle),
|
||||
)
|
||||
.route(
|
||||
"/subtitles/{id}/offset",
|
||||
patch(routes::subtitles::update_offset),
|
||||
)
|
||||
// Enrichment (write)
|
||||
.route(
|
||||
"/media/{id}/enrich",
|
||||
post(routes::enrichment::trigger_enrichment),
|
||||
)
|
||||
.route("/jobs/enrich", post(routes::enrichment::batch_enrich))
|
||||
// Transcode (write)
|
||||
.route(
|
||||
"/media/{id}/transcode",
|
||||
post(routes::transcode::start_transcode),
|
||||
)
|
||||
.route("/transcode/{id}", delete(routes::transcode::cancel_session))
|
||||
.layer(middleware::from_fn(auth::require_editor));
|
||||
|
||||
// Admin-only routes: destructive/config operations
|
||||
|
|
@ -203,14 +333,33 @@ pub fn create_router(state: AppState) -> Router {
|
|||
.route("/config/ui", put(routes::config::update_ui_config))
|
||||
.route("/database/vacuum", post(routes::database::vacuum_database))
|
||||
.route("/database/clear", post(routes::database::clear_database))
|
||||
// Plugin management
|
||||
.route("/plugins", get(routes::plugins::list_plugins))
|
||||
.route("/plugins/{id}", get(routes::plugins::get_plugin))
|
||||
.route("/plugins/install", post(routes::plugins::install_plugin))
|
||||
.route("/plugins/{id}", delete(routes::plugins::uninstall_plugin))
|
||||
.route("/plugins/{id}/toggle", post(routes::plugins::toggle_plugin))
|
||||
.route("/plugins/{id}/reload", post(routes::plugins::reload_plugin))
|
||||
// User management
|
||||
.route("/users", get(routes::users::list_users))
|
||||
.route("/users", post(routes::users::create_user))
|
||||
.route("/users/{id}", get(routes::users::get_user))
|
||||
.route("/users/{id}", patch(routes::users::update_user))
|
||||
.route("/users/{id}", delete(routes::users::delete_user))
|
||||
.route(
|
||||
"/users/{id}/libraries",
|
||||
get(routes::users::get_user_libraries),
|
||||
)
|
||||
.route(
|
||||
"/users/{id}/libraries",
|
||||
post(routes::users::grant_library_access),
|
||||
)
|
||||
.route(
|
||||
"/users/{id}/libraries",
|
||||
delete(routes::users::revoke_library_access),
|
||||
)
|
||||
.layer(middleware::from_fn(auth::require_admin));
|
||||
|
||||
let api = Router::new()
|
||||
.merge(login_route)
|
||||
.merge(viewer_routes)
|
||||
.merge(editor_routes)
|
||||
.merge(admin_routes);
|
||||
|
||||
// CORS: allow same-origin by default, plus the desktop UI origin
|
||||
let cors = CorsLayer::new()
|
||||
.allow_origin([
|
||||
|
|
@ -228,13 +377,25 @@ pub fn create_router(state: AppState) -> Router {
|
|||
.allow_headers([header::CONTENT_TYPE, header::AUTHORIZATION])
|
||||
.allow_credentials(true);
|
||||
|
||||
Router::new()
|
||||
.nest("/api/v1", api)
|
||||
.layer(DefaultBodyLimit::max(10 * 1024 * 1024))
|
||||
// Create protected routes with auth middleware
|
||||
let protected_api = Router::new()
|
||||
.merge(viewer_routes)
|
||||
.merge(editor_routes)
|
||||
.merge(admin_routes)
|
||||
.layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
auth::require_auth,
|
||||
))
|
||||
));
|
||||
|
||||
// Combine protected and public routes
|
||||
let full_api = Router::new()
|
||||
.merge(login_route)
|
||||
.merge(public_routes)
|
||||
.merge(protected_api);
|
||||
|
||||
Router::new()
|
||||
.nest("/api/v1", full_api)
|
||||
.layer(DefaultBodyLimit::max(10 * 1024 * 1024))
|
||||
.layer(GovernorLayer {
|
||||
config: global_governor,
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue