fix: remove Synapse admin API path — use admin-room reset exclusively (tuwunel only)

This commit is contained in:
atlas 2026-06-04 15:07:48 +02:00 committed by mara
commit a56badd004
2 changed files with 19 additions and 54 deletions

View file

@ -478,7 +478,6 @@ async fn matrix_reset_password(name: &str) -> Result<()> {
);
}
let admin_token = hive_c0re::matrix::read_admin_token()?;
let new_password = hive_c0re::matrix::random_password().context("generate random password")?;
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(30))
.build()
@ -486,16 +485,10 @@ async fn matrix_reset_password(name: &str) -> Result<()> {
let server_name = hive_c0re::matrix::discover_server_name(&client)
.await
.context("discover matrix server_name")?;
hive_c0re::matrix::reset_user_password(
&client,
&admin_token,
name,
&server_name,
&new_password,
)
.await
.with_context(|| format!("matrix reset-password {name}"))?;
// Password is persisted by reset_user_password (including admin-room path).
hive_c0re::matrix::reset_user_password(&client, &admin_token, name, &server_name)
.await
.with_context(|| format!("matrix reset-password {name}"))?;
// Password is persisted by reset_user_password.
let pw_path = PathBuf::from("/var/lib/hyperhive/matrix-creds").join(format!("{name}-password"));
println!("matrix: password for @{name}:{server_name} reset");
println!("password persisted at: {}", pw_path.display());

View file

@ -299,14 +299,13 @@ async fn auto_reset_password(client: &reqwest::Client, name: &str) -> anyhow::Re
let server_name = discover_server_name(client)
.await
.context("matrix: discover_server_name for auto-recovery")?;
let new_password = random_password()?;
let effective_password =
reset_user_password(client, &admin_token, name, &server_name, &new_password)
reset_user_password(client, &admin_token, name, &server_name)
.await
.with_context(|| {
format!("matrix: admin API password reset for {name} (auto-recovery)")
format!("matrix: admin-room password reset for {name} (auto-recovery)")
})?;
tracing::info!(%name, "matrix: auto-recovered password via admin API reset");
tracing::info!(%name, "matrix: auto-recovered password via admin-room reset");
Ok(effective_password)
}
@ -823,54 +822,27 @@ pub async fn promote_user_to_admin(
)
}
/// Reset a user's password, trying the Synapse admin REST API first and
/// falling back to the Matrix admin room (`#admins:<server>`) if the endpoint
/// returns 404 (e.g. on tuwunel which does not implement the Synapse API).
/// Reset a user's password via the Matrix admin room (`#admins:<server>`).
///
/// Returns the effective new password — which may be the caller-supplied
/// `new_password` (Synapse path) or a server-generated one (admin-room path).
/// The caller must use the returned password for subsequent `login_user` calls.
/// Sends `reset-password @<localpart>:<server>` to the admin room as @hive,
/// polls for the bot's response containing the new password, and persists
/// it to the non-purgeable creds path so [`ensure_user_for`] can re-login
/// on the next provisioning sweep.
///
/// Writes the new password to the non-purgeable creds path so
/// [`ensure_user_for`] can re-login on the next provisioning sweep.
/// Returns the new password for use in subsequent `login_user` calls.
pub async fn reset_user_password(
client: &reqwest::Client,
admin_token: &str,
localpart: &str,
server_name: &str,
new_password: &str,
) -> Result<String> {
let url = format!("{MATRIX_HTTP}/_synapse/admin/v2/users/%40{localpart}%3A{server_name}");
let resp = client
.put(&url)
.bearer_auth(admin_token)
.json(&serde_json::json!({"password": new_password}))
.send()
let pw = admin_room_reset_password(client, admin_token, server_name, localpart)
.await
.context("matrix: PUT /_synapse/admin/v2/users (reset password)")?;
let status = resp.status();
if status.is_success() {
persist_password(localpart, new_password);
return Ok(new_password.to_owned());
}
// 404 = endpoint not implemented (e.g. tuwunel 1.6.x): fall back to admin room.
if status == StatusCode::NOT_FOUND {
tracing::debug!(
%localpart,
"matrix: Synapse admin API returned 404 — falling back to admin-room reset"
);
let pw = admin_room_reset_password(client, admin_token, server_name, localpart)
.await
.with_context(|| {
format!("matrix: admin-room fallback for reset password of @{localpart}:{server_name}")
})?;
persist_password(localpart, &pw);
return Ok(pw);
}
let body = resp.json::<serde_json::Value>().await.unwrap_or_default();
anyhow::bail!(
"matrix: reset password for @{localpart}:{server_name}: HTTP {status}, body: {body}"
)
.with_context(|| {
format!("matrix: admin-room password reset for @{localpart}:{server_name}")
})?;
persist_password(localpart, &pw);
Ok(pw)
}
/// Persist the matrix password for `localpart` to the non-purgeable creds path.