7954 Commits
Author SHA1 Message Date
Quentin Gliech 93b6bb2032 Automatic merge back to main (#6063) unstable 2026-10-20 18:51:41 +02:00
github-actions[bot] eb8c1c6fd8 1.28.0-rc.0 v1.28.0-rc.0 2026-10-20 16:23:59 +00:00
Eric Eastwood 1b35f39021 Translations updates for main (#6062) 2026-10-20 11:22:32 -05:00
github-actions[bot] 6c592a67d9 Translations updates 2026-10-20 14:44:31 +00:00
Quentin Gliech d778f373f1 Translations updates for main (#6056) 2026-10-16 15:26:57 +02:00
github-actions[bot] 339a937e3c Translations updates 2026-10-16 13:11:01 +00:00
Quentin Gliech 5ef82bbfbd Interactive feedback for username availability in the registration form (#5977) 2026-10-16 14:58:16 +02:00
Quentin Gliech 3a1e62c72b Check the username availability as it is typed in the registration form
Once the username input settles, the field queries `usernameAvailable`
and reports next to it whether the name is available, taken or rejected
by the registration policy. In the two-step layout, continuing is held
back while a settled verdict says the name can't be used. The island now
declares the GraphQL endpoint on its mount node and brings its own query
client.
2026-10-16 11:34:22 +02:00
Quentin Gliech 24683fb938 Add a usernameAvailable GraphQL query for anonymous lookups
Exposes a new query telling whether a given username is available for
registration, and if not, why: already taken, or rejected by the
registration policy. A username reserved on the homeserver side is
deliberately reported as taken, mirroring the ambiguity of the
registration form, which doesn't tell the two apart either.

Because the query reveals whether a username exists, it is rate-limited
per requester, configurable through the new
`rate_limiting.username_availability` option.
2026-10-16 11:34:22 +02:00
Quentin Gliech a50de86da6 Render the registration form with React (#5591) 2026-10-16 11:34:16 +02:00
Quentin Gliech f03c39e773 Render the island error boundary without the page layout
The boundary only wraps islands, which already sit in the page layout and have no React Query client for the footer, so a render error (e.g. a blocked captcha script) left a blank island.
2026-10-16 11:17:12 +02:00
Quentin Gliech 3870a479d4 Add a back button to the password registration step
The step change does not touch the browser history, so without it the provider buttons were out of reach once on the password step.
2026-10-16 11:17:12 +02:00
Quentin Gliech 818e398dd4 List every allowed character in the invalid username message
The policy accepts `. _ - + / =` too, matching the message shown by the client-side check.
2026-10-16 11:17:12 +02:00
Quentin Gliech fda8a00a50 Send the password-too-weak code with the weak password error
The frontend already translates that code, so the user no longer sees the untranslated server message.
2026-10-16 11:17:12 +02:00
Quentin Gliech 5a649f0424 Lowercase usernames without the browser locale
`toLocaleLowerCase()` follows the browser locale, so with a Turkish locale `I` became a dotless `ı`, which is not a valid localpart and does not match what the server does with `to_lowercase`.
2026-10-16 11:17:12 +02:00
Quentin Gliech 7232057685 Render the registration form with React
The server-rendered registration form is replaced by a React island mounted
on `/register`, which renders the CAPTCHA in-page, gives live password
complexity feedback, and lays out the upstream provider buttons and the
sign-in link the way `/login` does. The island owns the whole form, so every
variant of the page is rendered from the mount data alone, and the user fills
it in one step. Server-side validation errors are threaded back into it
through the mount node, so a rejected submission re-renders with the errors
attached to the fields they belong to, until the user edits them.

`RegisterContext` resolves the provider names and the sign-in link server-side
so that the island only has to render them. The sign-in link is derived from
the post-auth action in the query string instead of the `PostAuthContext`
loaded from the database, which drops a round trip from both the GET and the
invalid-form re-render.

Registering now requires JavaScript, including on the variant with upstream
providers only and on the one without a CAPTCHA: the <noscript> block shows a
notice instead of a duplicate form, which could not work anyway when a CAPTCHA
is configured. While the script loads, the page shows a skeleton of the form
to avoid layout shifts, and a hidden error notice is revealed if it fails to
boot. The server-rendered CAPTCHA component and its entrypoint are removed
with their only consumer.
2026-10-16 11:17:12 +02:00
Quentin Gliech 8e1d4e0f6d Reserve the space of the password confirmation message
The message appears when the confirmation field loses focus, which shifted the
button below it under the click that moved the focus away.
2026-10-16 11:17:12 +02:00
Quentin Gliech 4a64be619d Move the "or" separator styles into a CSS module
The class becomes `or-separator`, as the global `.separator` also matched the
footer's separator. The module is imported by `templates.css` for the SSR
`field.separator()` macro.
2026-10-16 11:17:12 +02:00
Quentin Gliech f208498669 Normalize the username server-side when registering
`POST /register` trims and lowercases the username before either the password
or the upstream provider path looks at it, since Matrix localparts are
lowercase.
2026-10-16 11:17:12 +02:00
Quentin Gliech c0e6c3588c Explain the /register/password redirect and reword a registration test comment 2026-10-16 11:17:11 +02:00
Quentin Gliech 00a6a06762 Import the CAPTCHA component only from base.html on the registration page
The page imported it on its own as well, which is what broke the CAPTCHA rendering fixed by #5992 on the old password registration page. Also test that the page renders with a CAPTCHA configured.
2026-10-16 11:17:11 +02:00
Quentin Gliech 96a0eb2c82 Remove the old password registration template
`password.html` and the two "continue with" labels it needed have no caller
left.
2026-10-16 11:17:11 +02:00
Quentin Gliech f67287766b Register with a password from POST /register
The registration page had two steps: `/register` picked between a password
and an upstream provider, then `/register/password` collected the username,
email and password. Both now live on `/register`, whose `POST` handler runs
the provider branch first and otherwise hands the form to the registration
body, which stays in `password.rs` as a helper.

The page renders the username, email, password and terms-of-service fields,
the captcha and the provider buttons in a single form. The provider buttons
submit that same form, so they are marked `formnovalidate` to skip the
validation of the fields they do not use, and come after the primary submit
button so that Enter still registers.

`/register/password` is gone; a `GET` on it redirects to `/register` with the
query string it was given, so bookmarks and links keep working. Its
`?username=` prefill has no producer left and is dropped.

`GET /register` now renders the page whenever password registration is
enabled, instead of redirecting to `/register/password` when there is no
upstream provider. Without password registration, a single provider still
gets redirected to directly, and no provider at all now redirects to
`/login`, where `/register/password` used to send that case.

An unknown or disabled provider gives a 404 through an inline `GenericError`
rather than the route-wide `RouteError`, and an expired CSRF token on the
password path now sends the user back to `/register` instead of failing the
request.
2026-10-16 11:17:11 +02:00
Quentin Gliech 779106b34c Absorb the registration form state and the captcha into RegisterContext
The registration page is about to render the password registration form
itself, so its context needs the form state and the captcha configuration
`PasswordRegisterContext` carries today.
2026-10-16 11:17:11 +02:00
Quentin Gliech ebb9865abe Handle concurrent registrations of identical public clients (#6035) 2026-10-16 11:09:09 +02:00
Quentin Gliech 960584056c Update wasmtime to 49.0.3 to fix RUSTSEC-2026-0353 to RUSTSEC-2026-0364 (#6055) 2026-10-16 10:42:57 +02:00
Quentin Gliech 1081a23591 Update rustls to 0.23.46 to fix RUSTSEC-2026-0346 to RUSTSEC-2026-0349 (#6054) 2026-10-16 09:52:39 +02:00
Quentin Gliech 24c47c38e1 Update wasmtime to 49.0.3 to fix RUSTSEC-2026-0353 to RUSTSEC-2026-0364 2026-10-15 18:20:55 +02:00
Quentin Gliech a1a8146c4e Update rustls to 0.23.46 to fix RUSTSEC-2026-0346 to RUSTSEC-2026-0349 2026-10-15 18:20:55 +02:00
ElementBot 96cec94f3f Automatic merge back to main (#6049) 2026-10-13 23:03:00 +01:00
github-actions[bot] f7917acea9 1.27.0 v1.27.0 2026-10-13 21:46:10 +00:00
Eric Eastwood 0163cd8049 Translations updates for v1.27 (#6048) 2026-10-13 16:44:44 -05:00
github-actions[bot] 7798bb63d2 Translations updates 2026-10-13 21:16:10 +00:00
Quentin Gliech 0b982a2719 Refresh the browser sessions list after removing a browser session (#6042) 2026-10-13 15:21:35 +02:00
Quentin Gliech 3b705d9129 Merge branch 'main' into stefan/browserSessionRefresh 2026-10-13 10:56:45 +02:00
Quentin Gliech 6057e83790 Upgrade ulid to 3.0 (#6039) 2026-10-12 13:32:44 +02:00
Stefan Ceriu a358c7e254 Refresh the browser sessions list after removing a browser session 2026-10-12 09:44:39 +03:00
Quentin Gliech 6b37eb7d74 Upgrade ulid to 3.0
ulid 3 moves to `rand` 0.10, so it no longer pulls the `rand` 0.9
generation. Only `opentelemetry_sdk` and `sentry` still need it.

ULID generation keeps going through `UlidExt`, whose bit layout matches
ulid's own `from_datetime_with_source`. The only API change affecting
MAS is the rename of `Ulid::new` to `Ulid::generate`, which the clippy
ban list now targets.
2026-10-09 16:50:36 +02:00
Quentin Gliech 2d3bf03d63 Upgrade to rand 0.10 and the next RustCrypto generation
`rand` 0.10 and the new RustCrypto generation both build on `rand_core`
0.10, so they have to move together:

 - `rand`, `rand_chacha` and `rand_core` 0.10
 - `digest` 0.11, `sha2` 0.11, `hmac` 0.13, `const-oid` 0.10
 - `elliptic-curve` 0.14, `ecdsa` 0.17, `p256`, `p384` and `k256` 0.14,
   `signature` 3
 - `der`, `spki` and `sec1` 0.8, `pkcs8` 0.11, `pem-rfc7468` 1.0
 - `rsa` 0.10.0-rc.19 and `pkcs1` 0.8.0-rc.5, which have no stable
   release yet. They are pinned exactly, because release candidates
   break their API between releases.
 - `argon2` 0.6 and `pbkdf2` 0.13

On the `rand` side, `RngCore` becomes `Rng` and the old `Rng` becomes
`RngExt`. `gen_*` becomes `random_*`, `thread_rng` becomes `rng`,
`distributions` becomes `distr`, and `from_rng` can no longer fail. On
the crypto side, `mas-jose` and `mas-keystore` move to `BoxedUint` for
RSA, to the `pkcs1` and `pkcs8` reference types, and to the `Generate`
trait for key generation, and `mas-jose` no longer depends on
`generic-array`. Password hashing goes through `hash_password_with_rng`.

Stored data is unaffected. The password hashing snapshots are unchanged,
so bcrypt, Argon2 and PBKDF2 produce the same hashes for the same input
and salt, and `pbkdf2` 0.13 keeps the same defaults (SHA-256, 600 000
rounds). The keystore snapshots change only because keys generated from
a seeded RNG differ. The snapshots of keys loaded from files are
unchanged.

`opa-wasm` 0.3.3 already uses this generation, so most of the duplicate
crates it pulled in go away. The `deny.toml` skip list now names what
still pulls the older versions: cookie, sqlx, headers, wasmtime and pest
for RustCrypto, and opentelemetry_sdk, sentry and ulid for `rand` 0.9.
2026-10-09 15:42:26 +02:00
Quentin Gliech 9f40244eab Bump chacha20poly1305 from 0.10 to 0.11
It moves from `generic-array` to `hybrid-array`, so `Encrypter` builds
its key and nonce with the `Key` and `Nonce` aliases, and `mas-keystore`
no longer depends on `generic-array`. Cookie (via `aes-gcm`) is still on
`aead` 0.5, so the older `aead` and `universal-hash` go on the cargo-deny
skip list.
2026-10-09 15:38:53 +02:00
Quentin Gliech f8b7c5b879 Bump bcrypt from 0.18 to 0.19
The hashes it produces are unchanged. It pulls `blowfish` 0.10, which is
on `cipher` 0.5 while the rest of the tree is on 0.4, so the older
`cipher` and `inout` go on the cargo-deny skip list.
2026-10-09 15:38:53 +02:00
Quentin Gliech 9659701f7a Bump rand from 0.8.5 to 0.8.6 to address RUSTSEC-2026-0097
0.8.6 is the patched release for the `rand::thread_rng` unsoundness with
custom loggers, so the advisory ignore is no longer needed.
2026-10-09 15:38:52 +02:00
Quentin Gliech 186c592d61 Allow the duplicate crates pulled in by opa-wasm 0.3 and the icu bump
The `cargo deny` bans check fails on main because two dependency bumps
introduced duplicate crate versions:

 - `opa-wasm` 0.3.3 (#6029) uses `rand` 0.10, `base64` 0.23 and the
   `digest` 0.11 generation of the RustCrypto crates, while the rest of
   the tree is still on `rand` 0.9, `base64` 0.22 and `digest` 0.10.
 - The icu bump (#6015) pulls `zerovec-derive` 0.11.6, which uses `syn` 3,
   while everything else is on `syn` 2.

Add the older versions to the skip list until the rest of the tree
catches up.
2026-10-09 15:26:05 +02:00
Quentin Gliech 03b4eba347 Handle concurrent registrations of identical public clients
Two registrations with the same metadata could both miss the `find_by_metadata_digest` lookup and then race on the insert, the loser failing with a unique violation on `oauth2_clients_metadata_digest_key` and getting a 500.

`OAuth2ClientRepository::add` becomes `add_or_reuse` and inserts with `ON CONFLICT (metadata_digest) DO UPDATE ... RETURNING`, which yields the existing client when the digest is taken, including one committed while the insert was waiting on it. It reports whether it inserted, so the registration handler drops its lookup and still tells created and reused clients apart in the metric. `find_by_metadata_digest` has no callers left and is removed.

The returned client is now built from the database row, so it carries the metadata digest instead of always `None`, and the span records the id of the client actually returned.
2026-10-09 14:55:11 +02:00
Olivier 'reivilibre 2277a37c59 Remove the "Application Services login" warning page (#5962) 2026-10-09 11:18:08 +01:00
Eric Eastwood 1968992f16 Automatic merge back to main (#6031) 2026-10-06 11:44:51 -05:00
github-actions[bot] 912bcf2192 1.27.0-rc.0 v1.27.0-rc.0 2026-10-06 15:50:28 +00:00
Eric Eastwood 5a78ee96cd Translations updates for main (#6030) 2026-10-06 10:49:04 -05:00
github-actions[bot] 15e27bed51 Translations updates 2026-10-06 15:13:57 +00:00
Andrew Morgan eb834276cb Bump opa-wasm from 0.2.0 to 0.3.3, wasmtime from 43.0.2 to 49.0.2 (#6029) 2026-10-06 16:02:50 +01:00