Commit Graph
7833 Commits
Author SHA1 Message Date
Quentin Gliech 2c08dfb304 Add a passwordless flag to registration tokens
A registration token can now be marked `passwordless`, which will let the
user register without picking a password: their identity is established by
the email verification code instead.

This only adds the column and plumbs it through the storage layer, the
admin API and the anonymous `registrationToken` GraphQL query; the
registration flow itself is unchanged for now.
2026-09-10 18:53:59 +02:00
Quentin Gliech f34d679fca Call the registration token an invite code in the form
The form is what an invited user sees, and `registration token` doesn't mean
anything to them.
2026-09-10 18:53:59 +02:00
Quentin Gliech 335be429ba Add an /invite/{token} route which pre-fills the registration form
`/invite/{token}` checks that the token exists and redirects to `/register`
with it in the query string, which hands it to the form island as a read-only
field. Once the token resolves over GraphQL, the username and email address it
was issued for are filled in and locked, and the email field shows up even when
the server would otherwise not ask for one.

The token is passed back in the POST body and attached to the registration.
Nothing validates it server-side yet.
2026-09-10 18:53:59 +02:00
Quentin Gliech f02c3fe293 Add a registrationToken GraphQL query for anonymous token lookup
The registration form needs to know, before the user submits anything, whether
the code they were handed is usable and which identity it pins. The query only
returns whether the token is valid and the username and email it was issued
for, never the admin-only details.
2026-09-10 18:53:59 +02:00
Quentin Gliech 40f8828a77 Expose the invite URL and the pinned username and email in the admin API
Registration tokens now report the `/invite/{token}` deep link alongside the
`username` and `email` they were issued for, and the create endpoint accepts
both. All the token endpoints now take the `UrlBuilder` so they can build that
link.
2026-09-10 18:53:59 +02:00
Quentin Gliech 5bc5baaa5f Add username and email columns to registration tokens
A registration token can now optionally carry the username and/or the email
address the account it is used for has to be registered with. This only adds
the columns and plumbs them through the storage layer and the CLI; nothing
enforces them yet.
2026-09-10 18:53:59 +02:00
Quentin Gliech 59f04fd087 Merge the password registration form into /register
`/register` was a username-first step handing off to
`/register/password`; now that the form checks availability as you type,
that step has nothing left to do. Both pages become one: the island
mounts on `/register` and renders the form, the upstream provider
buttons and the sign-in link, the way `/login` already lays them out. It
mounts even when password registration is disabled, since the providers
now live inside it.

`/register/password` and its `PasswordRegister` route are removed
outright rather than kept as an alias. `RegisterContext` and
`PasswordRegisterContext` become one context, which resolves the
provider URLs and the sign-in link server-side so that the island only
has to render them.
2026-09-10 18:53:59 +02:00
Quentin Gliech e98f26ee6b Rewrite the password registration form in React
The server-rendered registration form is replaced by a React-based
component which talks to the GraphQL API to validate the username as it
is typed, renders the CAPTCHA in-page, and gives live password
complexity feedback. Server-side validation errors are threaded into
the form through the mount node, so a rejected submission re-renders
with the same messages the old template showed.

Registering now requires JavaScript: the <noscript> block shows a
notice and a sign-in link 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.
2026-09-10 18:53:31 +02:00
Quentin Gliech bd52dc3829 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 this effectively is a username-existence oracle, the query is
rate-limited per requester, configurable through the new
`rate_limiting.username_availability` option.
2026-09-10 18:52:10 +02:00
Quentin Gliech fe8eaeaaa8 Merge all the pending PRs 2026-09-10 18:52:10 +02:00
Quentin Gliech 9a005459c4 Start upstream OAuth 2.0 flows with a form POST from the registration page 2026-09-10 18:52:10 +02:00
Quentin Gliech 60dfac6e17 Carry the username typed on the registration page through the upstream OAuth 2.0 flow 2026-09-10 18:50:52 +02:00
Quentin Gliech f52a2333d4 Extract a helper to start an upstream OAuth 2.0 authorization flow 2026-09-10 18:50:52 +02:00
Quentin Gliech 47004db8c3 Add a shared boot helper for React islands
The helper parses the mount node's dataset, waits for the i18n setup
before the first render, and swaps the page to a server-rendered error
notice when booting fails. This fixes the account app staying on its
loading screen forever when fetching the locale data fails, and gives
upcoming server-rendered pages with React islands a common entry point.
2026-09-10 18:50:50 +02:00
Quentin Gliech 2091a84b30 build(deps): bump rust-toolchain from 1.96.0 to 1.98.1 (#5966) 2026-09-10 16:58:57 +02:00
Quentin Gliech 2762927a47 Fix the lints introduced by clippy 1.98
The new `unused_async_trait_impl` lint flags `async fn` trait impls without any `.await`. The `FromRequestParts` impls that only read from the request parts now return `std::future::ready(...)` directly. The GraphQL module gets a module-wide allow: async-graphql's `#[Object]` refuses non-async resolvers and its `Enum` derive emits async trait impls of its own.

Also drop the `?` on two `return Err(...)?` statements in the introspection handler, flagged by `needless_return_with_question_mark`.
2026-09-10 15:53:23 +02:00
matrixbot c563f05052 Automatic merge back to main (#5968) 2026-09-08 23:06:49 +02:00
github-actions[bot] 258de7e8d2 1.25.0-rc.0 v1.25.0-rc.0 2026-09-08 20:51:34 +00:00
matrixbot e5a6dd9f79 Translations updates for main (#5967) 2026-09-08 22:42:10 +02:00
github-actions[bot] 98af240ce3 Translations updates 2026-09-08 20:25:07 +00:00
dependabot[bot] a5ead76240 build(deps): bump rust-toolchain from 1.96.0 to 1.98.1
Bumps [rust-toolchain](https://github.com/rust-lang/rust) from 1.96.0 to 1.98.1.
- [Release notes](https://github.com/rust-lang/rust/releases)
- [Changelog](https://github.com/rust-lang/rust/blob/main/RELEASES.md)
- [Commits](https://github.com/rust-lang/rust/compare/1.96.0...1.98.1)

---
updated-dependencies:
- dependency-name: rust-toolchain
  dependency-version: 1.98.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-08 13:54:17 +00:00
Quentin Gliech dda0f45dd9 Render the registration CAPTCHAs with React (#5885) 2026-09-08 12:54:44 +02:00
Quentin Gliech cd2ef4cbd7 Merge main into quenting/react-captcha 2026-09-08 12:38:14 +02:00
Quentin Gliech 7891a7a31b Fix positional arguments in manage CLI docs (#5964) 2026-09-08 12:36:53 +02:00
Quentin Gliech 065ff2fe55 CI: move to pnpm/setup for installing node, pnpm and installing frontend dependencies (#5965) 2026-09-08 12:18:46 +02:00
Olivier 'reivilibre 8a755e3217 Format log timestamps in the local timezone (#5932) 2026-09-08 10:27:46 +01:00
Quentin Gliech 60c0fdf438 Return M_APPSERVICE_LOGIN_UNSUPPORTED for m.login.application_service (#5961) 2026-09-07 18:01:32 +02:00
Quentin Gliech 1826034167 Replace pnpm/action-setup and actions/setup-node with pnpm/setup
One pinned step now installs pnpm, Node.js and the dependencies. `require-lockfile: true` keeps the `--frozen-lockfile` semantics, `cache: true` keeps the pnpm store cache.
2026-09-07 16:04:48 +02:00
Quentin Gliech dbbb93915e Declare the Node.js version in devEngines.runtime
`pnpm/setup` reads the runtime version from `package.json` and ignores `.node-version`. With `onFail: download`, pnpm records Node 24.15.0 in the lockfile and downloads it on every install unless `--no-runtime` is passed. The Dockerfile and the docs build pass it, since they already run a pinned Node. `.node-version` stays for the Cloudflare Pages build, which reads it to pick the Node that bootstraps corepack.
2026-09-07 16:04:48 +02:00
Olivier 'reivilibre 21d01ec192 build(deps): bump http-body-util from 0.1.3 to 0.1.5 (#5948) 2026-09-07 13:37:35 +01:00
Noah Gao aeae198d0e docs: fix manage command positional arguments 2026-09-06 02:57:35 +08:00
Olivier 'reivilibre bebc7731dd Implement hard shutdown and exit for task timeout (#5930) 2026-09-04 13:52:54 +01:00
Olivier 'reivilibre a55b25ef6b Add unittest for database connection via pgpass (#5926) 2026-09-04 13:51:29 +01:00
dependabot[bot] 21aaa65b34 build(deps): bump http-body-util from 0.1.3 to 0.1.5
Bumps [http-body-util](https://github.com/hyperium/http-body) from 0.1.3 to 0.1.5.
- [Release notes](https://github.com/hyperium/http-body/releases)
- [Commits](https://github.com/hyperium/http-body/compare/http-body-util-v0.1.3...http-body-util-v0.1.5)

---
updated-dependencies:
- dependency-name: http-body-util
  dependency-version: 0.1.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-04 12:48:24 +00:00
Olivier 'reivilibre 437570d4da Use a frozen clock in the mas-oidc-client integration tests (#5963) 2026-09-04 13:45:42 +01:00
Quentin Gliech 196cce170c Merge branch 'main' into fix-flaky-oidc-client-clock 2026-09-03 19:55:11 +02:00
Quentin Gliech 9d3f3df4e6 Merge branch 'main' into fix-missing-appservice-login-unsupported 2026-09-03 19:55:07 +02:00
Quentin Gliech 9075c96551 Stop wrapping comments in rustfmt, drop redundant options (#5956) 2026-09-03 19:54:40 +02:00
Quentin Gliech 9c56e7f4ee Stop wrapping comments in rustfmt, drop redundant options
`comment_width = 80` counts the whole line, indentation included, which
wraps far more aggressively than intended; the latest nightly rustfmt
(rust-lang/rustfmt#6802) started enforcing it on comments it previously
left alone. Turn `wrap_comments` off rather than reformat everything.

`max_width = 100`, `comment_width = 80` and `use_small_heuristics =
"Default"` are rustfmt's defaults, so drop them too; only the two
nightly-only import options remain.
2026-09-03 19:17:18 +02:00
Paul Chobert db25101de4 Fix flaky fail_verify_id_token_wrong_auth_time test
The oidc-client integration tests read the real system clock through a
`now()` helper. The ID token builder generates a fresh RSA key before
stamping `iat`, while each test captured its own `now` earlier for
verification. Under coverage instrumentation on a loaded CI runner, the
two key generations in `fail_verify_id_token_wrong_auth_time` took more
than the 5 minute `iat` leeway, so verification failed on `iat` before
ever reaching the `auth_time` check the test asserts on.

Make the helper return a frozen `MockClock` timestamp instead. Every
token and verification in the binary now shares one instant, so setup
duration can no longer affect the outcome, and the clippy opt-out for
`Utc::now()` goes away.
2026-09-03 16:09:44 +02:00
Paul Chobert aa8b6b9a27 Merge branch 'main' into fix-missing-appservice-login-unsupported 2026-09-03 15:28:01 +02:00
Paul ChobertandQuentin Gliech 9e1d3b94b1 Update crates/handlers/src/compat/login.rs
Co-authored-by: Quentin Gliech <quenting@element.io>
2026-09-03 12:05:30 +02:00
Paul Chobert 765fa97ffe Return M_APPSERVICE_LOGIN_UNSUPPORTED for m.login.application_service
Matrix 1.17 requires servers that don't support the legacy
authentication API to reject `m.login.application_service` on
`/login` with a 400 and the `M_APPSERVICE_LOGIN_UNSUPPORTED` error
code. Previously this login type fell through the generic unsupported
credentials path and returned `M_UNKNOWN`, which appservices written
against Matrix 1.17 can't distinguish from an unrelated failure.
2026-09-03 11:10:26 +02:00
Eric Eastwood 81d8e4bfe3 Automatic merge back to main (#5960) 2026-09-02 18:04:01 -05:00
Eric Eastwood d4b15acbec Merge branch 'main' into ref-merge/c7c13a2137f03abcff2e7619f4a10611c0cd5f9a 2026-09-02 17:17:09 -05:00
github-actions[bot] c7c13a2137 1.24.0 v1.24.0 2026-09-02 21:44:13 +00:00
Eric Eastwood dd2b6494eb Translations updates for v1.24 (#5958) 2026-09-02 16:42:49 -05:00
github-actions[bot] b0c53acf07 Translations updates 2026-09-02 21:24:07 +00:00
Quentin Gliech 46b558dfd1 Ignore RUSTSEC-2026-0269 in cargo-deny as MAS isn't affected by it (#5955) 2026-09-02 16:58:26 +02:00
Quentin Gliech f1e46bd675 Ignore RUSTSEC-2026-0269 in cargo-deny as MAS isn't affected by it 2026-09-02 16:26:31 +02:00