//! `hivectl matrix` — matrix account provisioning verbs. hivectl forwards //! each request to the daemon (which owns the register + admin tokens and //! the matrix creds dir) and renders the reply; it no longer links the //! matrix machinery itself. use std::path::Path; use anyhow::{Context as _, Result, bail}; use crate::cli::MatrixCmd; use crate::util::resolve_password; /// Route a `matrix` subcommand to its handler. Extracted from `main`'s /// dispatch match so the top-level router stays small. pub(crate) async fn run_matrix_cmd(socket: &Path, cmd: MatrixCmd) -> Result<()> { match cmd { MatrixCmd::CreateUser { name, password, password_stdin, } => matrix_create_user(socket, &name, password.as_deref(), password_stdin).await, MatrixCmd::SyncAdmin => matrix_sync_admin(socket).await, MatrixCmd::PromoteUser { name } => matrix_promote_user(socket, &name).await, MatrixCmd::ResetPassword { name } => matrix_reset_password(socket, &name).await, MatrixCmd::Invite { user, room } => matrix_invite(socket, &user, room.as_deref()).await, } } /// Send a matrix provisioning request to the daemon and print the /// operator-facing result lines it returns. The daemon owns the register + /// admin tokens and the matrix creds dir, so hivectl no longer links the /// matrix machinery — it just forwards the request and renders the reply. async fn matrix_request(socket: &Path, req: hive_host_sock::HostRequest) -> Result<()> { let resp = crate::client::request(socket, req) .await .with_context(|| format!("connect to daemon socket {}", socket.display()))?; if !resp.ok { bail!( "matrix: {}", resp.error.as_deref().unwrap_or("unknown error") ); } for line in &resp.messages { println!("{line}"); } Ok(()) } async fn matrix_create_user( socket: &Path, name: &str, password: Option<&str>, password_stdin: bool, ) -> Result<()> { // Resolve the password client-side (an inline flag or a stdin read); // the daemon never touches this process's stdin. The agent-vs-operator // branch + throwaway-password handling now live in the daemon handler. let password = resolve_password(password, password_stdin)?; matrix_request( socket, hive_host_sock::HostRequest::MatrixCreateUser { name: crate::util::parse_ident(name)?, password, }, ) .await } async fn matrix_sync_admin(socket: &Path) -> Result<()> { matrix_request(socket, hive_host_sock::HostRequest::MatrixSyncAdmin).await } async fn matrix_promote_user(socket: &Path, name: &str) -> Result<()> { matrix_request( socket, hive_host_sock::HostRequest::MatrixPromoteUser { name: crate::util::parse_ident(name)?, }, ) .await } async fn matrix_invite(socket: &Path, user: &str, room: Option<&str>) -> Result<()> { matrix_request( socket, hive_host_sock::HostRequest::MatrixInvite { user: user.to_owned(), room: room.map(str::to_owned), }, ) .await } async fn matrix_reset_password(socket: &Path, name: &str) -> Result<()> { matrix_request( socket, hive_host_sock::HostRequest::MatrixResetPassword { name: crate::util::parse_ident(name)?, }, ) .await }