routes.rs
156 lignes · 6511 octets
use axum::{ Router, routing::{delete, get, post, put}, }; use sea_orm::DatabaseConnection; use tower_http::services::ServeDir; use crate::handlers::settings::{preferences, profile, security}; use crate::handlers::{ admin_handler, error_page, health, home_handler, login_handler, root_handler, totp_handler, user_handler, }; /// Build the **browser** family of UI routes (SSR, session-cookie driven). /// /// These routes are meant to be mounted on the CSRF-protected channel of the /// application builder (`with_ui` / `merge_browser_routes`). It covers the /// landing page, public pages (login, password reset…), authenticated UI /// pages (profile, settings), the admin panel, and the static asset service. /// /// The machine API (`/api/v1/*`) is intentionally *not* included here; mount /// it separately via [`api_routes`] on the machine channel. pub fn browser_routes() -> Router<DatabaseConnection> { let public_routes = Router::new() .route("/login", get(login_handler::login_page)) .route( "/resend-verification", get(login_handler::resend_verification_page), ) .route("/forgot-password", get(login_handler::forgot_password_page)) .route("/reset-password", get(login_handler::reset_password_page)) .route( "/confirm-password-change", get(security::confirm_password_change), ) .route("/health", get(health::health_check)) .route("/login/2fa", get(login_handler::login_2fa_page)); let ui_routes = Router::new() .route("/home", get(home_handler::home)) .route("/profile", get(profile::get_profile_page)) .route("/profile", put(profile::update_profile)) .route("/settings/password", get(security::get_password_page)) .route("/settings/password", put(security::change_password)) .route( "/settings/password/pending", delete(security::cancel_pending_password_change), ) .route("/settings/sessions", get(security::get_sessions_page)) .route("/settings/sessions/{id}", delete(security::revoke_session)) .route( "/settings/preferences", get(preferences::get_preferences_page), ) .route( "/settings/preferences", put(preferences::update_preferences), ) .route("/settings/security", get(totp_handler::security_page)) .route( "/settings/security/totp/enable", post(totp_handler::enable_totp), ) .route( "/settings/security/totp/verify", post(totp_handler::verify_totp), ) .route( "/settings/security/totp/disable", post(totp_handler::disable_totp), ) .route( "/settings/security/backup-codes", post(totp_handler::regenerate_backup_codes), ); let admin_routes = Router::new() .route("/admin", get(admin_handler::admin_dashboard)) .route("/admin/users", get(admin_handler::list_users)) .route("/admin/users/create", get(admin_handler::create_user_form)) .route("/admin/users", post(admin_handler::create_user)) .route("/admin/users/{id}", get(admin_handler::edit_user_form)) .route("/admin/users/{id}", put(admin_handler::update_user)) .route("/admin/users/{id}", delete(admin_handler::delete_user)) .route( "/admin/users/{id}/reset-password", post(admin_handler::reset_user_password), ) .route( "/admin/users/{id}/reset-password-email", post(admin_handler::admin_reset_password_by_email), ) .route("/admin/roles", get(admin_handler::list_roles)) .route("/admin/roles/create", get(admin_handler::create_role_form)) .route("/admin/roles", post(admin_handler::create_role)) .route("/admin/roles/{id}", get(admin_handler::edit_role_form)) .route("/admin/roles/{id}", put(admin_handler::update_role)) .route("/admin/roles/{id}", delete(admin_handler::delete_role)) .route("/admin/settings", get(admin_handler::get_app_settings)) .route("/admin/settings", put(admin_handler::update_app_settings)) .route("/admin/errors", get(admin_handler::admin_errors)) .route("/admin/logs", get(admin_handler::admin_logs)) .route( "/admin/users/{id}/reset-totp", post(admin_handler::reset_user_totp), ); let static_dir = std::env::var("RUSTWARDEN_STATIC_DIR").unwrap_or_else(|_| "static".to_string()); tracing::info!("Serving static files from: {}", static_dir); let static_service = ServeDir::new(&static_dir); Router::new() .route("/", get(root_handler::root_redirect)) .merge(public_routes) .merge(ui_routes) .merge(admin_routes) .nest_service("/static", static_service) .fallback(error_page::not_found) } /// Build the **machine** family of API routes (`/api/v1/*`). /// /// These are JSON endpoints authenticated by `Authorization: Bearer` (or /// pre-session for login/register) and are *not* CSRF-vulnerable. Mount them /// on the machine channel of the application builder /// (`merge_machine_routes`), never behind the CSRF layer. pub fn api_routes() -> Router<DatabaseConnection> { // Auth endpoints are provided canonically by the framework core // (`rustwarden_core::auth::auth_api_routes`); mount that set and add the // UI crate's own user-management API on top. let user_routes = Router::new() .route("/api/v1/users", post(user_handler::create_user)) .route("/api/v1/users", get(user_handler::list_users)); Router::new() .merge(rustwarden_core::auth::auth_api_routes()) .merge(user_routes) } /// Create the main application router for Rustwarden. /// /// Combines [`browser_routes`] and [`api_routes`] into a single router. This /// puts `/api/v1/*` and the SSR UI in one tree; prefer mounting the two /// families on their dedicated channels (`with_ui` + `merge_machine_routes`) /// so the CSRF layer covers the browser family only. pub fn create_router() -> Router<DatabaseConnection> { browser_routes().merge(api_routes()) } /// Returns a minimal router with only the health-check route, used in tests. #[allow(dead_code)] pub fn create_test_router() -> Router { Router::new().route("/health", get(health::health_check)) }
GitRust