Files
rustdesk-server/src/api/mod.rs
T
mike 475da0e950
build / build-linux-amd64 (push) Successful in 1m50s
Implement signed API communication to improve security
2026-05-22 13:05:50 +02:00

123 lines
4.5 KiB
Rust

//! HTTP management API mounted in-process alongside hbbs's rendezvous
//! listeners. The router is wired in via `src/rendezvous_server.rs`'s outer
//! `tokio::select!`. M1 covers auth + heartbeat + sysinfo; later milestones
//! add address book, audit, OIDC, etc.
pub mod ab;
pub mod admin;
pub mod audit;
pub mod auth;
pub mod device_auth;
pub mod devices_cli;
pub mod email;
pub mod error;
pub mod groups;
pub mod heartbeat;
pub mod http_proxy;
pub mod middleware;
pub mod oidc;
pub mod pagination;
pub mod peers;
pub mod plugin_sign;
pub mod record;
pub mod state;
pub mod strategy;
pub mod sysinfo;
pub mod twofa;
pub mod unattended;
pub mod users;
pub use state::AppState;
use axum::extract::Extension;
use axum::routing::{delete, get, post, put};
use axum::Router;
use hbb_common::{log, ResultType};
use std::net::SocketAddr;
use std::sync::Arc;
pub fn router(state: Arc<AppState>) -> Router {
let app = Router::new()
// M1: auth + heartbeat + sysinfo
.route(
"/api/login-options",
get(auth::login_options).head(auth::login_options_head),
)
.route("/api/login", post(auth::login))
.route("/api/currentUser", post(auth::current_user))
.route("/api/logout", post(auth::logout))
.route("/api/heartbeat", post(heartbeat::heartbeat))
.route("/api/sysinfo_ver", post(sysinfo::sysinfo_ver))
.route("/api/sysinfo", post(sysinfo::sysinfo))
.route(
"/api/unattended-password",
post(unattended::unattended_password),
)
// M2: address book — modern (shared + personal)
.route("/api/ab/settings", post(ab::settings::settings))
.route("/api/ab/personal", post(ab::profiles::personal))
.route(
"/api/ab/shared/profiles",
post(ab::profiles::shared_profiles),
)
.route("/api/ab/peers", post(ab::peers::list))
.route("/api/ab/tags/:guid", post(ab::tags::list))
.route("/api/ab/peer/add/:guid", post(ab::peers::add))
.route("/api/ab/peer/update/:guid", put(ab::peers::update))
.route("/api/ab/peer/:guid", delete(ab::peers::delete))
.route("/api/ab/tag/add/:guid", post(ab::tags::add))
.route("/api/ab/tag/rename/:guid", put(ab::tags::rename))
.route("/api/ab/tag/update/:guid", put(ab::tags::update))
.route("/api/ab/tag/:guid", delete(ab::tags::delete))
// M2: address book — legacy single-blob fallback
.route(
"/api/ab",
get(ab::legacy::get).post(ab::legacy::put),
)
// M2: group / users / peers panel
.route(
"/api/device-group/accessible",
get(groups::accessible),
)
.route("/api/users", get(users::list))
.route("/api/peers", get(peers::list))
.route("/api/peers/:id/managed", put(peers::set_managed))
// M3: audit
.route("/api/audit/conn", post(audit::conn::conn))
.route("/api/audit/file", post(audit::file::file))
.route("/api/audit/alarm", post(audit::alarm::alarm))
.route("/api/audit", put(audit::note::note))
// M3: session recording upload
.route("/api/record", post(record::record))
// M4: TOTP enrollment (admin-only)
.route("/api/2fa/enroll", post(twofa::enroll))
.route("/api/2fa/unenroll", post(twofa::unenroll))
// M4: rustdesk --assign target
.route("/api/devices/cli", post(devices_cli::assign))
// M4: plugin signing (no auth — protocol-level)
.route("/lic/web/api/plugin-sign", post(plugin_sign::plugin_sign))
// M4: OIDC device-flow login
.route("/api/oidc/auth", post(oidc::auth::auth))
.route("/api/oidc/auth-query", get(oidc::poll::auth_query))
.route("/oidc/callback", get(oidc::callback::callback));
// M5: admin dashboard (HTMX + embedded HTML). Merged BEFORE the
// Extension layer so the merged router carries the shared state.
let app = match admin::build(state.clone()) {
Some(admin_router) => app.merge(admin_router),
None => app,
};
app.layer(Extension(state))
}
pub async fn serve(addr: SocketAddr, state: Arc<AppState>) -> ResultType<()> {
log::info!("HTTP API listening on {}", addr);
let app = router(state);
// Share the same router with the rendezvous-TCP HttpProxyRequest path so
// both transports route through the exact same handlers.
http_proxy::install_router(app.clone());
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await?;
Ok(())
}