Skip to content

Releases: sufforest/vela

Release list

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 27 Jun 12:46
d58f207

[0.3.0] — 2026-06-27

A sandboxed WebAssembly extension platform, plus a round of federation,
end-to-end-encryption, and client-compatibility hardening.

Added

  • Extension platform. Sandboxed WebAssembly plugins (wasmtime + the
    Component Model) hook the server at well-defined points without forking it.
    Decision points — check_registration, check_login, check_media_upload,
    check_profile_update, check_room_create — allow / deny / modify a
    request; on_event observes events asynchronously; filter_sync_event
    shapes what a client sees in /sync; inbound federated events can be
    soft-failed by a plugin. Plugins get three capabilities — structured
    logging, an emit-event bot channel, and per-plugin key/value state — all
    behind a manifest whose grants are reconciled against the component's actual
    imports before it loads. Per-plugin fuel, memory, and wall-clock limits;
    hot-reload on SIGHUP. Ships an SDK and example plugins.
  • Third-party protocols + matrix-rtc transports. GET /_matrix/client/v3/thirdparty/protocols and the MSC4143 rtc/transports
    discovery endpoint.

Security

  • /keys/query no longer leaks other users' user_signing_keys — they
    are returned only for a self-query, per spec. (Cross-user leakage corrupted
    the client trust model and showed verified users as untrusted.)
  • /preview_url SSRF guard. The URL-preview fetch refuses targets that
    resolve to private/internal addresses, re-validates each redirect hop, pins
    the connection to the validated address, and caps the response body.
    Operators with internal preview targets opt out via
    [media] url_preview_allow_private_ips.
  • Cross-signing signature uploads are scoped to the caller — a client can
    no longer fold signatures attributed to another user, or into another user's
    device/signing keys (cross-user signing is limited to the master key). The
    cross-signing-key UIA gate keys off key material, not signatures.
  • Cap federation response bodies (key server 256 KiB, general 100 MiB).

Fixed

  • Federation signing keys. Refetch a remote server's keys when a signature
    references an unknown key id instead of serving a stale cached key; accept
    events signed with a server's rotated-out keys within their validity window.
  • E2EE / devices. Preserve cross-signing signatures across a key re-upload
    (a verified device no longer reverts to unverified); track device
    last_seen; deliver to-device messages delete-on-ack on both /sync and
    sliding sync (a dropped sync can't lose a verification request); notify a
    user's other devices and room-mates when a device is deleted.
  • Client compatibility. Stop a /sync busy-loop on lazy-loaded
    incremental syncs; emit the MSC4222 state_after under the key matching the
    client's opt-in param (rooms no longer render as "v1"/empty in Element);
    keep room heroes' membership through lazy-load (fixes "Empty room" on fresh
    login); align the /login well_known base URL with discovery; return
    M_UNRECOGNIZED for auth-metadata when delegated auth is off.

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 14 Jun 05:42
81d6708

[0.2.0] — 2026-06-13

Spec-maturity milestone: faster joins (MSC3706/MSC3902), delegated auth
(MSC3861), extended profiles (MSC4133), notifications history, dehydrated
devices (MSC3814), and a long tail of CS-API / federation correctness work.

Added

  • Dehydrated devices (MSC3814). PUT/GET/DELETE /_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device plus
    POST .../{device_id}/events let a client park an encrypted, offline
    device on the server and rehydrate it later to decrypt to-device room keys
    that arrived while it was away. The dehydrated device is registered like
    any other device, so /keys/query, /keys/claim, to-device routing, and
    cross-server m.device_list_update all work for it; the events endpoint
    drains its to-device queue with a read-ahead cursor. One per user — a new
    upload replaces and purges the previous one; device_data and one-time-key
    counts are bounded, and a dehydrated id may not alias an existing device.

  • Notification history. GET /_matrix/client/v3/notifications returns a
    paginated list of past notifications (with from / limit / only=highlight).
    Rows are persisted whenever a push rule matches for a local recipient — even
    when no push gateway is registered — and the read flag is computed at query
    time from the user's m.read receipt / m.fully_read marker.

  • Extended profile fields (MSC4133). GET/PUT/DELETE /_matrix/client/v3/profile/{userId}/{keyName} for arbitrary profile fields
    (timezone, pronouns, …) alongside the standard displayname/avatar_url;
    the full-profile response folds them in. Owner-only writes, size-bounded.

  • GET /_matrix/client/v1/auth_metadata (MSC2965). Relays the configured
    IdP's OAuth authorization-server metadata, falling back to an issuer-only
    document if the IdP is unreachable; 404 when delegated auth is off.

  • Faster remote joins (MSC3706 + MSC3902 partial state). Joining a
    large federated room no longer blocks on downloading its full member
    list. vela requests a join with omit_members=true, becomes joinable
    immediately with a partial-state hint, and a background filler
    reconciles the rest of the room state and device lists out of band.
    /sync surfaces partial_state: true so clients can soft-fail
    membership-dependent features until the room resolves; endpoints that
    need complete state (/members, /joined_members, /state,
    /state_ids, inbound make/send_join and make/send_knock) block or
    reject while a room is still partial rather than serving incomplete
    answers. The filler mirrors member transitions and the remote
    device-key cache on re-verify, replays buffered m.device_list_update
    EDUs once full state lands, and re-evaluates events optimistically
    accepted or soft-failed during the partial window.

  • Delegated authentication via OIDC / OAuth2 (MSC3861, phase 2). vela
    can defer login to an external identity provider instead of managing
    passwords itself. Set [auth.oidc].introspection_endpoint and vela
    validates Bearer tokens by introspecting them against the IdP (RFC 7662,
    client_secret_basic / client_secret_post), caches results up to two
    minutes bounded by the token's own expiry, and provisions accounts on
    first touch from the sub / username / device_id claims. When
    enabled, the legacy auth surface is refused: /login advertises no
    password flow, /register rejects non-AS callers, and
    /account/password / /account/deactivate return M_UNRECOGNIZED.

  • Stateful sliding sync (MSC4186). The /sync successor persists
    per-connection state in a new sliding_sync_conns column family.
    Reconnects no longer re-deliver state the client already has; the
    server emits room data only for rooms that crossed a list window,
    visibility, or state version since the last poll (DELTA ops), and
    explicit room subscriptions stay live across polls until the client
    drops them (sticky subscriptions).

  • Matrix Application Service support. Bridges (mautrix-telegram,
    mautrix-discord, mautrix-signal, etc.) and bots can now register
    with vela. An operator pastes the AS's registration YAML into the
    admin room via !as register <yaml>; vela validates the
    namespaces, hashes the tokens (cleartext is shown to the operator
    once, never stored), persists to a new appservices CF, and
    starts a per-AS outbound delivery worker. Every event matching the
    AS's namespaces is enqueued into the new appservice_outbox CF;
    the worker drains it, posts to PUT /_matrix/app/v1/transactions/ {txnId} with Authorization: Bearer <hs_token>, falls back to
    the legacy /transactions/{txnId} URL on 404/405, and retries
    with exponential backoff (2s → 5min cap, 24h dead threshold).
    Inbound Bearer <as_token> + ?user_id= masquerades the request
    as a user in the AS's namespace — virtual users are provisioned
    on demand. Admin commands: !as register/list/unregister/enable/ disable. Interest filter is wired into both the local send path
    and federation_receive, so federated events trigger AS delivery
    too. Deferred to follow-ups: m.login.application_service
    register/login types, M_EXCLUSIVE enforcement on non-AS callers,
    ping protocol, query endpoints, ?ts= timestamp massaging,
    ephemeral passthrough (m.presence/m.typing/m.receipt under
    receive_ephemeral), device management UIA bypass, third-party
    protocols.

  • Delayed events (MSC4140). Clients can schedule an event to be sent
    after a delay (self-destructing status, scheduled posts). A
    [server] max_delay_ms knob caps how far out a delay may be set.

  • Event relationships over federation (MSC2836).
    /event_relationships walks and backfills threaded and related events
    across servers, so clients see complete relation chains for rooms whose
    history spans multiple homeservers.

  • Owned state events (MSC3757). State events whose state_key is a
    user's own MXID can be set by that user regardless of power level,
    enabling per-user state without granting elevated permissions.

  • Server-side invite filtering (MSC4155). An invitee's
    org.matrix.msc4155.invite_permission_config account data drives
    which invites vela accepts on their behalf, so unwanted invites are
    rejected before they ever reach the client.

  • Restricted-room joins over federation. vela can complete the
    send_join happy path for restricted rooms, joining via a third
    server that vouches for the join authorisation.

  • Notary server-key proxy. /_matrix/key/v2/query answers questions
    about other servers' keys: vela fetches the target's
    /key/v2/server, countersigns it, and returns the result, acting as a
    key-notary for peers.

  • Room summary (MSC3266). GET /_matrix/client/v1/rooms/{roomIdOrAlias}/summary
    (and the im.nheko.summary unstable path) lets clients preview a room
    before joining. Resolves aliases, gates visibility via the existing
    peek rules (members/invitees always; otherwise public/knock/
    world-readable/allow-list), returns the caller's membership, and
    serves unauthenticated requests for world-readable rooms only. Rooms we
    don't host are summarised over federation (the hierarchy root from a
    via / known candidate server), so previewing a remote room works for
    authenticated callers.

  • Intentional mentions (MSC3952). m.mentions is now honoured for
    push: .m.rule.is_user_mention notifies a user listed in
    content.m.mentions.user_ids, and .m.rule.is_room_mention handles
    @room — but only when the sender's power level meets the room's
    notifications.room threshold, so low-power users can't @room-spam.
    Highlight counts in /sync reflect the same rules.

  • Batch device delete. POST /_matrix/client/v3/delete_devices
    with the same UIA discipline as single-device delete; ids the caller
    doesn't own are skipped instead of failing the whole batch.

  • Content reporting. POST /_matrix/client/v3/rooms/{roomId}/report/{eventId}
    plus the v1.13 /rooms/{roomId}/report and v1.14
    /users/{userId}/report siblings. v1.18 semantics: optional
    reason, no score. Always returns 200 {} (privacy mode —
    doesn't leak whether the target exists or the reporter is in the
    room). Reports persist into a new event_reports CF.

  • ?server= on /publicRooms. GET/POST /_matrix/client/v3/publicRooms
    now accept the server query param. When set to a remote homeserver
    name, vela forwards the request via
    POST /_matrix/federation/v1/publicRooms and returns the peer's
    response. Clients can browse other homeservers' directories without
    having to talk to them directly.

  • /.well-known/matrix/support. Serves admin/security contacts and
    a support page from a new [support] config section (MSC1929);
    returns 404 when unconfigured.

  • m.get_login_token capability advertised as disabled so clients
    hide the cross-device-login affordance we don't implement.

  • vela-admin rooms-top and diagnose. rooms-top --limit N lists
    rooms by most-recent activity with a relative-age column (clock-skewed
    future bumps render as future); diagnose is a one-screen operator
    health probe covering current stream position, rooms still mid
    partial-state resync, destinations with pending outbound queues, and
    24h / 7d room activity. Both read existing schema, no new state.

  • Admin bot commands !reports [N] (show the last N abuse reports,
    default 20), !reactivate <mxid> (undo !deactivate's flag), and
    !reset-password <mxid> [password] (atomic: fresh argon2 hash, clear
    the deactivated flag, revoke every access token; generates a random
    password when none is given).

  • Complement in CI. The Matrix spec-compliance suite now runs on
    every PR via .github/workflows/complement.yml. Image build is
    cached through buildkit's GHA backend; the existing
    tools/testing/complement/{run.sh,skiplist.txt} runner is reu...

Read more