hive-c0re/matrix.rs: trim UIAA prose to docs pointer (#715 batch 1)
This commit is contained in:
parent
017786564a
commit
91e50d843c
1 changed files with 23 additions and 51 deletions
|
|
@ -1,35 +1,11 @@
|
|||
//! Optional matrix-tuwunel wiring. When the `hive-matrix` nixos-container
|
||||
//! is present and running, hive-c0re ensures:
|
||||
//! Optional matrix-tuwunel wiring: shared registration token (host) +
|
||||
//! per-agent UIAA registration → `<agent-state>/matrix-token`. No-op
|
||||
//! when the `hive-matrix` container isn't running, so operators who
|
||||
//! haven't flipped `hyperhive.matrix.enable = true` pay nothing.
|
||||
//!
|
||||
//! 1. A shared `registration_token` exists at
|
||||
//! `/var/lib/hyperhive/matrix-register-token` (mode 0600, generated
|
||||
//! once on first boot). The hive-matrix module bind-mounts that file
|
||||
//! read-only into the tuwunel container so tuwunel can resolve its
|
||||
//! `registration_token_file` setting against it.
|
||||
//! 2. Every agent (and the manager) has a matrix account on the local
|
||||
//! homeserver with an `access_token` written to
|
||||
//! `<agent-state>/matrix-token`. Idempotent: skips registration when
|
||||
//! the token file already exists.
|
||||
//!
|
||||
//! Agents never see the registration token — only their own `access_token`.
|
||||
//! Account provisioning rides the matrix-spec UIAA flow:
|
||||
//!
|
||||
//! ```text
|
||||
//! POST /_matrix/client/v3/register
|
||||
//! {"username": "<agent>", "password": "<random>"}
|
||||
//! → 401 {"flows":[{"stages":["m.login.registration_token"]}],
|
||||
//! "session": "<id>", ...}
|
||||
//!
|
||||
//! POST /_matrix/client/v3/register
|
||||
//! {"username": "<agent>", "password": "<random>",
|
||||
//! "auth": {"type": "m.login.registration_token",
|
||||
//! "token": "<reg_token>", "session": "<id>"}}
|
||||
//! → 200 {"user_id": "@agent:server", "access_token": "<at>", ...}
|
||||
//! ```
|
||||
//!
|
||||
//! No-op when the `hive-matrix` container isn't running (detected via
|
||||
//! `nixos-container list`), so operators who haven't flipped
|
||||
//! `hyperhive.matrix.enable = true` pay nothing.
|
||||
//! See `docs/matrix.md::Provisioning flow (registration token)` for
|
||||
//! the full UIAA round-trip, token-file shape, and host/container
|
||||
//! bind-mount layout.
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
|
@ -123,15 +99,12 @@ pub fn ensure_register_token() -> Result<String> {
|
|||
}
|
||||
std::fs::write(path, format!("{token}\n"))
|
||||
.with_context(|| format!("write registration token to {}", path.display()))?;
|
||||
// Mode 0640: tuwunel inside the hive-matrix container runs as a
|
||||
// non-root user; the file gets `chown :tuwunel` via the activation
|
||||
// script in `nix/modules/hive-matrix.nix` so the tuwunel group
|
||||
// gains read. 0600 would block tuwunel with `Permission denied
|
||||
// (os error 13)` (#644); 0644 would world-read the token (mara
|
||||
// veto: footgun). 0640 with a pinned group is the sweet spot.
|
||||
// The host-side activation script also chowns + chmods on every
|
||||
// boot, so this is best-effort: hive-c0re may write the file
|
||||
// before the chown lands, but the next activation reconciles it.
|
||||
// Mode 0640 (group-readable for tuwunel via the host-side
|
||||
// activation script's chown). 0600 blocks tuwunel; 0644
|
||||
// world-reads the token. The activation script reconciles
|
||||
// chown + chmod on every boot, so this write is best-effort.
|
||||
// See `docs/matrix.md::Provisioning flow (registration token)`
|
||||
// for the host/container permission split.
|
||||
let _ = std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o640));
|
||||
tracing::info!(path = %path.display(), "matrix: generated registration token");
|
||||
Ok(token)
|
||||
|
|
@ -172,9 +145,9 @@ async fn register_post(
|
|||
/// Generate a throwaway random password for matrix UIAA registration.
|
||||
/// `PASSWORD_BYTES` raw bytes ⇒ 64-char hex string. Agents authenticate
|
||||
/// by `access_token` so the password is protocol overhead we never
|
||||
/// persist; the operator path in `hivectl` (#663) lets the caller
|
||||
/// supply a real password instead so they can log into a matrix web
|
||||
/// client (`m.login.password`).
|
||||
/// persist; the operator path in `hivectl` lets the caller supply a
|
||||
/// real password instead so they can log into a matrix web client
|
||||
/// (`m.login.password`).
|
||||
pub fn random_password() -> Result<String> {
|
||||
random_hex(PASSWORD_BYTES)
|
||||
}
|
||||
|
|
@ -188,7 +161,7 @@ pub fn random_password() -> Result<String> {
|
|||
///
|
||||
/// Caller picks the password: agents use [`random_password`] (throwaway
|
||||
/// — they auth by `access_token`), operators on the `hivectl` path
|
||||
/// supply their own so they can log into matrix web clients (#663).
|
||||
/// supply their own so they can log into matrix web clients.
|
||||
async fn register_user(
|
||||
client: &reqwest::Client,
|
||||
agent: &str,
|
||||
|
|
@ -250,8 +223,7 @@ fn extract_access_token(body: &serde_json::Value) -> Result<String> {
|
|||
/// To force re-registration, delete the token file.
|
||||
///
|
||||
/// `client` is shared across the sweep so we build one reqwest
|
||||
/// connection pool for all agents rather than one per call (argus
|
||||
/// nit on #565 — bounded but wasteful).
|
||||
/// connection pool for all agents rather than one per call.
|
||||
pub async fn ensure_user_for(
|
||||
client: &reqwest::Client,
|
||||
name: &str,
|
||||
|
|
@ -285,11 +257,11 @@ pub async fn ensure_user_for(
|
|||
/// for storing it. Used by `hivectl matrix create-user` for human
|
||||
/// (non-agent) accounts so we don't create stray
|
||||
/// `/var/lib/hyperhive/agents/<name>/` directories for users that
|
||||
/// aren't agents (#662). For operator accounts the caller passes a
|
||||
/// real password so the operator can `m.login.password` into matrix
|
||||
/// web clients afterwards (#663); for headless agent re-provisioning
|
||||
/// the caller can pass [`random_password`] to keep the existing
|
||||
/// throwaway behaviour.
|
||||
/// aren't agents. For operator accounts the caller passes a real
|
||||
/// password so the operator can `m.login.password` into matrix web
|
||||
/// clients afterwards; for headless agent re-provisioning the caller
|
||||
/// can pass [`random_password`] to keep the existing throwaway
|
||||
/// behaviour.
|
||||
///
|
||||
/// **Not idempotent** (unlike [`forge::provision_user_token`]): the
|
||||
/// matrix UIAA `/register` endpoint returns `M_USER_IN_USE` (HTTP 400)
|
||||
|
|
|
|||
Loading…
Reference in a new issue