Skip to content

Commit

Permalink
feat(dgw): initial implementation of /jet/jrec/list (#412)
Browse files Browse the repository at this point in the history
My first shot at implementing session recording listing using a scope token.
It's just half the work, here's what I don't like about it:

- not enough error handling (probably panics if directory is empty)
- scope token cannot be reused, not sure how to make it reusable
- result is a vector of strings, maybe we'd like a vector of objects
- result is not sorted, file creation time sorting would be best
  • Loading branch information
awakecoding authored Apr 26, 2023
1 parent 372d92d commit 332c86f
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 0 deletions.
1 change: 1 addition & 0 deletions devolutions-gateway/src/http/controllers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
62 changes: 62 additions & 0 deletions devolutions-gateway/src/http/controllers/recordings.rs
Original file line number Diff line number Diff line change
@@ -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<Json<Vec<String>>, HttpErrorStatus> {
get_recordings(&self.conf_handle).await
}
}

fn list_uuid_dirs(dir_path: &Path) -> Vec<String> {
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<Json<Vec<String>>, 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))
}
6 changes: 6 additions & 0 deletions devolutions-gateway/src/http/http_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions devolutions-gateway/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,8 @@ pub enum AccessScope {
ConfigWrite,
#[serde(rename = "gateway.heartbeat.read")]
HeartbeatRead,
#[serde(rename = "gateway.recordings.read")]
RecordingsRead,
}

#[derive(Clone, Deserialize)]
Expand Down

0 comments on commit 332c86f

Please sign in to comment.