From ac01c0309423caa39d01ab6e641d7be842e159ab Mon Sep 17 00:00:00 2001 From: Jack Mechem Date: Mon, 30 Mar 2026 19:53:55 -0700 Subject: [PATCH] Permissions, shutdown route --- flake.nix | 3 ++- result | 1 + src/main.rs | 1 + src/routes/system.rs | 27 +++++++++++++++++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 120000 result diff --git a/flake.nix b/flake.nix index eff09fe..8f2bc53 100644 --- a/flake.nix +++ b/flake.nix @@ -107,7 +107,8 @@ security.polkit.extraConfig = '' polkit.addRule(function(action, subject) { if ((action.id == "org.freedesktop.systemd1.manage-units" || - action.id == "org.freedesktop.login1.reboot") && + action.id == "org.freedesktop.login1.reboot" || + action.id == "org.freedesktop.login1.power-off") && subject.user == "server-dash-api") { return polkit.Result.YES; } diff --git a/result b/result new file mode 120000 index 0000000..1f45119 --- /dev/null +++ b/result @@ -0,0 +1 @@ +/nix/store/24v5zn615rqab56z2i1vhi27mdisv0l1-server-dash-api-0.1.0 \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index d81c9c3..a4195ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,6 +28,7 @@ async fn main() { get(routes::services::service_logs), ) .route("/system/reboot", post(routes::system::system_reboot)) + .route("/system/shutdown", post(routes::system::system_shutdown)) .route_layer(middleware::from_fn(auth::require_auth)); let app = Router::new() diff --git a/src/routes/system.rs b/src/routes/system.rs index 0736119..fe582fb 100644 --- a/src/routes/system.rs +++ b/src/routes/system.rs @@ -4,6 +4,33 @@ use zbus::Connection; use crate::auth; use crate::models; +// POST /system/shutdown +pub async fn system_shutdown(headers: HeaderMap) -> impl IntoResponse { + let conn = match Connection::system().await { + Ok(c) => c, + Err(e) => { + return models::ActionResponse::err(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()) + .into_response(); + } + }; + + let result = conn + .call_method( + Some("org.freedesktop.login1"), + "/org/freedesktop/login1", + Some("org.freedesktop.login1.Manager"), + "PowerOff", + &(false,), + ) + .await; + + match result { + Ok(_) => models::ActionResponse::ok("Shutting down...".to_string()).into_response(), + Err(e) => models::ActionResponse::err(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()) + .into_response(), + } +} + // POST /system/reboot pub async fn system_reboot(headers: HeaderMap) -> impl IntoResponse { let conn = match Connection::system().await {