Mints a single-use, passwordless registration token for each guest,
pinned to their address and username and expiring after
`guest_invites.invite_lifetime`, and schedules their invite emails. The
links are only ever mailed to the guests, so the response carries a
count rather than the tokens.
Everything is validated before anything is minted, and the batch is
committed as a whole, so a rejected request sends no email at all. Each
invite goes through the registration policy as `POST /register` will
check it, so an invite the guest form would refuse is a 400 naming the
invite and every violation. The policy sees an empty requester, as the
request comes from the inviter's homeserver rather than the guest. A
username that is already taken is refused up front, rather than emailed
out as a link nobody can register with. Addresses are deduplicated
ignoring case before the usernames are checked, keeping the first entry,
so a repeated address never counts as a username given twice.
The caller sends the room name and the inviter on the inviter's behalf,
so the endpoint doesn't trust them. The room name and the inviter's
display name are stripped of control characters, including the
bidirectional controls `char::is_control` misses, and truncated before
they are stored in the job payload. The inviter's Matrix ID is never
truncated, so it can't show a server it isn't from: it is kept whole if
it is valid under the historical grammar, and left out otherwise.
The room ID is checked as `/open-room` checks it, and is only recorded
on the span once it is valid.
The endpoint answers 404 while guest invites are disabled. The check is
in the handler, as the admin router doesn't see the configuration.
`guest_invites.enabled` turns it on, and requires `client_room_url`.
`/open-room` keeps using `client_room_url` while the endpoint is
disabled, so that links already sent keep working.
`invite_lifetime` is a positive number of seconds that fits in a `u32`,
so MAS refuses a zero or negative lifetime at startup, and adding it to
the current time can't overflow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Holds the settings for inviting guests to rooms by email, starting with
the client URL invitees are sent to once they are signed in. The value
goes on `SiteConfig`, which the admin handlers and the views already
take.
`client_room_url` is a string rather than a URL, because parsing it as
one would percent-encode the braces of a `{room_id}` placeholder in its
path, which would then never be replaced. Whenever it is set, it must
contain `{room_id}` and still parse as an absolute `http` or `https` URL
with a host once the placeholder is filled in, so that `/open-room`
never redirects relative to MAS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add a dedicated `device_code_link` rate limiter for device authorization user code verification.
This is to help mitigate the User Code Brute Forcing attack as described by [RFC 8628 section 5.1](https://datatracker.ietf.org/doc/html/rfc8628#section-5.1)
Proposed default is 1 per minute and burst of 10. This can be overridden by the server admin.
The interactive playground page and its route/config option are gone; the GraphQL API itself (POST /graphql) is unaffected. External GraphQL usage is deprecated anyway in favour of the REST admin API.
Fixes#5572Fixes#2424
This makes it so that MAS binds on a temporary path on startup, sets
permissions and then moves it to the configured path. This means that we don't
error out anymore if there is a stale socket file, and that it is safe to
rollout a new process without killing the old one first, without breaking
connections.
When a browser signs out (or discovers its session was ended), the
session cookie now remembers when that happened; the flag is cleared by
the next successful login. The `additional_authorization_parameters`
templates can read it as `logged_out`, so operators can force a fresh
prompt at the upstream provider after sign-out, e.g.:
additional_authorization_parameters:
prompt: "{% if logged_out %}login{% endif %}"
This addresses the "sign out signs me back in" loop with upstream SSO
providers that still hold a live session.
Fixes#1569
branding.logo_uri was accepted and validated by the config layer but never
plumbed through to SiteConfig or any template, so it had no effect. Remove the
field and regenerate the committed config schema to remove the confusion.
This was done by auditing what's in the `mas-config` crate (and resulting
config JSON schema) and comparing it to the current configuration options
documentation.
Add a reference page describing the `http.server.response` log line and its
fields (method, status, requester, client address, GraphQL operation, request
id, trace id, …), aimed at administrators feeding the logs into a SIEM, with a
table of well-known operations and how to classify them (login, logout, token
issuance, …).
Updates the field doc-comment to describe the new templating semantics
and adds a deprecation note on `forward_login_hint` pointing to the
recommended replacement. Regenerates the JSON schema.
The runtime behavior (template rendering, forward_login_hint
soft-deprecation) is wired up in follow-up commits.