Skip to content

fix(deploy): register accounts without leaving a session behind - #159

Merged
argiad merged 1 commit into
developmentfrom
fix/installer-registration-sessions
Nov 8, 2026
Merged

argiad merged 1 commit into
developmentfrom
fix/installer-registration-sessions

Conversation

@argiad

@argiad argiad commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #157. The live test of #157 found one unused session on the owner account (@admin) and a second session on @mm-core. This PR stops the installer creating them.

Cause

Synapse's shared-secret registration (/_synapse/admin/v1/register) also signs the new account in, creating a device and an access token, unless the request sets inhibit_login. register_new_matrix_user has no option for that, and it throws the token away. So every install so far has left:

Fix

_register_user (deploy/lib/bootstrap.sh) now does the same handshake itself, with inhibit_login: true:

  1. get a nonce;
  2. compute HMAC-SHA1 over nonce, user, password and admin, keyed with registration_shared_secret;
  3. POST the registration.

It runs as a short standard-library Python script under Synapse's own Python, inside its container, the way register_new_matrix_user runs. Behaviour is otherwise the same:

  • the password reaches it on stdin only;
  • an account that already exists fails with Synapse's answer (M_USER_IN_USE);
  • an unreachable Synapse fails with a one-line message, not a traceback.

Existing installs

Installs from before keep that one session on the owner account. It has no name, and "last seen" is empty, so signing it out from the app is safe; the CHANGELOG says so. The installer leaves the owner's sessions alone: telling this session apart from a real one relies on a heuristic, and #157 settled that a re-run leaves the owner account alone.

Tests

  • 5 new bats tests, each seen failing first. They run against deploy/test/fixtures/fake_synapse_register.py, a fake Synapse that checks the MAC as v1.163 does and records whether a device was created. Removing inhibit_login fails 2 of them.
  • Full suite 352/352, shellcheck clean (macOS bash 3.2).
  • Checked against a real matrixdotorg/synapse:v1.163.0 container (local, now removed). Its generated config has a quoted secret with symbols, which the parser handled. Results:
    • an owner account registered this way had 0 devices;
    • @mm-core had only the 1 sign-in I made;
    • an account registered with register_new_matrix_user, for comparison, had an extra never-used device (last_seen_ts: null);
    • the exact password, with quotes, a backslash and non-ASCII, signs in;
    • the account is an admin.

🤖 Generated with Claude Code

Synapse's shared-secret registration also signs the new account in (a
device and access token) unless the request sets inhibit_login.
register_new_matrix_user cannot ask for that and throws the token away,
so every install left one unused session on the owner account (listed in
their Matrix app) and one on @mm-core.

_register_user now performs the same handshake itself (nonce, HMAC-SHA1
over nonce/user/password/admin) with inhibit_login, using a short
standard-library script run by Synapse's own Python inside its container.
The password still reaches it on stdin only. An existing account fails
with Synapse's answer (M_USER_IN_USE), as before.

Tests: a fake Synapse checks the MAC as v1.163 does and records whether a
device was created. Checked against a real matrixdotorg/synapse:v1.163.0
container: accounts registered this way have no devices, while
register_new_matrix_user leaves one never-used device.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@argiad
argiad enabled auto-merge (rebase) November 8, 2026 21:13
@argiad
argiad merged commit c04092c into development Nov 8, 2026
13 checks passed
@argiad argiad mentioned this pull request Nov 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant