diff --git a/devolutions-gateway/src/http/controllers/mod.rs b/devolutions-gateway/src/http/controllers/mod.rs index b325f6b1c..2a54fdd98 100644 --- a/devolutions-gateway/src/http/controllers/mod.rs +++ b/devolutions-gateway/src/http/controllers/mod.rs @@ -6,6 +6,7 @@ pub mod heartbeat; pub mod http_bridge; pub mod jrl; pub mod kdc_proxy; +pub mod recordings; pub mod session; pub mod sessions; pub mod sogar_token; diff --git a/devolutions-gateway/src/http/controllers/recordings.rs b/devolutions-gateway/src/http/controllers/recordings.rs new file mode 100644 index 000000000..e6cd7709f --- /dev/null +++ b/devolutions-gateway/src/http/controllers/recordings.rs @@ -0,0 +1,62 @@ +use crate::config::ConfHandle; +use crate::http::guards::access::{AccessGuard, TokenType}; +use crate::http::HttpErrorStatus; +use crate::token::AccessScope; +use saphir::body::json::Json; +use saphir::controller::Controller; +use saphir::http::Method; +use saphir::macros::controller; +use saphir::request::Request; +use std::fs; +use std::path::Path; +use uuid::Uuid; + +pub struct RecordingsController { + pub conf_handle: ConfHandle, +} + +#[controller(name = "jet/jrec/list")] +impl RecordingsController { + #[get("/")] + #[guard(AccessGuard, init_expr = r#"TokenType::Scope(AccessScope::RecordingsRead)"#)] + async fn get_recordings(&self) -> Result>, HttpErrorStatus> { + get_recordings(&self.conf_handle).await + } +} + +fn list_uuid_dirs(dir_path: &Path) -> Vec { + fs::read_dir(dir_path) + .unwrap() + .filter_map(|entry| { + let path = entry.unwrap().path(); + if path.is_dir() { + path.file_name() + .and_then(|name| Uuid::parse_str(name.to_str().unwrap()).ok()) + .map(|uuid| uuid.to_string()) + } else { + None + } + }) + .collect() +} + +/// Lists recordings +#[cfg_attr(feature = "openapi", utoipa::path( + get, + operation_id = "GetRecordings", + tag = "Recordings", + path = "/jet/jrec/list", + responses( + (status = 200, description = "Recordings for this Gateway", body = Recording), + (status = 400, description = "Bad request"), + (status = 401, description = "Invalid or missing authorization token"), + (status = 403, description = "Insufficient permissions"), + ), + security(("scope_token" = ["gateway.recordings.read"])), +))] +pub(crate) async fn get_recordings(conf_handle: &ConfHandle) -> Result>, HttpErrorStatus> { + let conf = conf_handle.get_conf(); + let recording_path = conf.recording_path.to_owned(); + let dirs = list_uuid_dirs(recording_path.as_std_path()); + Ok(Json(dirs)) +} diff --git a/devolutions-gateway/src/http/http_server.rs b/devolutions-gateway/src/http/http_server.rs index 8143f5fa2..459816539 100644 --- a/devolutions-gateway/src/http/http_server.rs +++ b/devolutions-gateway/src/http/http_server.rs @@ -7,6 +7,7 @@ use crate::http::controllers::heartbeat::HeartbeatController; use crate::http::controllers::http_bridge::HttpBridgeController; use crate::http::controllers::jrl::JrlController; use crate::http::controllers::kdc_proxy::KdcProxyController; +use crate::http::controllers::recordings::RecordingsController; use crate::http::controllers::session::SessionController; use crate::http::controllers::sessions::{LegacySessionsController, SessionsController}; use crate::http::middlewares::auth::AuthMiddleware; @@ -80,6 +81,10 @@ pub fn configure_http_server( }; let legacy_sessions_controller = LegacySessionsController { sessions }; + let recordings_controller = RecordingsController { + conf_handle: conf_handle.clone(), + }; + // sogar stuff // NOTE: disabled for now // let conf = conf_handle.get_conf(); @@ -96,6 +101,7 @@ pub fn configure_http_server( .controller(jet) .controller(session_controller) .controller(sessions_controller) + .controller(recordings_controller) // .controller(sogar) // .controller(sogar_token) .controller(legacy_health) diff --git a/devolutions-gateway/src/token.rs b/devolutions-gateway/src/token.rs index 003507cd1..3ae22024b 100644 --- a/devolutions-gateway/src/token.rs +++ b/devolutions-gateway/src/token.rs @@ -450,6 +450,8 @@ pub enum AccessScope { ConfigWrite, #[serde(rename = "gateway.heartbeat.read")] HeartbeatRead, + #[serde(rename = "gateway.recordings.read")] + RecordingsRead, } #[derive(Clone, Deserialize)]