CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Test (windows-latest) (push) Canceled after 0s
CI / Storage tests on PostgreSQL (push) Canceled after 0s
CI / Complement (federation off) (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
CI / Smoke test the binary (push) Canceled after 0s
CI / Admin panel (push) Canceled after 0s
CI / Web client (push) Canceled after 0s
Every call in the web client now goes through MatrixRTC with a LiveKit
SFU, the model Element Call and Element X use; the legacy 1:1 m.call.*
calls are gone. In a room of two the other person is rung and can answer
or decline; in a bigger room a banner offers to join the call. Calls show
a grid of participant tiles with mute, camera, screen sharing and leave,
and media is end-to-end encrypted in encrypted rooms.
Server:
- MSC4140 delayed events (send/state with a delay, plus the
delayed_events list/restart/cancel/send API), stored and scheduled, so
a member whose client drops off is taken out of the call.
- POST /user/{userId}/openid/request_token, which lk-jwt-service uses to
hand out LiveKit tokens.
- org.matrix.msc4143.rtc_foci in /.well-known/matrix/client, configured
under client_api.rtc.
- Room presets let members send call membership state.
- Migration 0014 for both SQL dialects.
Deploy: LiveKit and lk-jwt-service in compose (calls.yml) and the helm
chart. Docs: docs/calls.md, configuration and deployment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
62 lines
2.5 KiB
Go
62 lines
2.5 KiB
Go
package clientapi_test
|
|
|
|
import (
|
|
"net/http"
|
|
"net/url"
|
|
"testing"
|
|
|
|
"github.com/dariuszjaniak/warp/server/internal/httputil"
|
|
)
|
|
|
|
// TestOpenIDToken is the exchange the LiveKit JWT service relies on: a user
|
|
// asks for a token, hands it over, and the service asks this server who it
|
|
// belongs to.
|
|
func TestOpenIDToken(t *testing.T) {
|
|
ts := newTestServer(t, nil)
|
|
alice := ts.register("alice", "correct-horse-battery-staple")
|
|
bob := ts.register("bob", "correct-horse-battery-staple")
|
|
path := "/_matrix/client/v3/user/" + url.PathEscape(alice.UserID) + "/openid/request_token"
|
|
|
|
rec := ts.post(path, alice.AccessToken, map[string]any{})
|
|
expectStatus(t, rec, http.StatusOK)
|
|
body := jsonBody(t, rec)
|
|
token, _ := body["access_token"].(string)
|
|
if token == "" || body["token_type"] != "Bearer" || body["matrix_server_name"] != testServerName ||
|
|
body["expires_in"] != float64(3600) {
|
|
t.Fatalf("request_token = %s", rec.Body.String())
|
|
}
|
|
|
|
// The token is no access token.
|
|
expectError(t, ts.get("/_matrix/client/v3/account/whoami", token), http.StatusUnauthorized, httputil.ErrCodeUnknownToken)
|
|
|
|
rec = ts.get("/_matrix/federation/v1/openid/userinfo?access_token="+url.QueryEscape(token), "")
|
|
expectStatus(t, rec, http.StatusOK)
|
|
if got := jsonBody(t, rec)["sub"]; got != alice.UserID {
|
|
t.Errorf("sub = %v, want %s", got, alice.UserID)
|
|
}
|
|
|
|
expectError(t, ts.get("/_matrix/federation/v1/openid/userinfo?access_token=nope", ""),
|
|
http.StatusUnauthorized, httputil.ErrCodeUnknownToken)
|
|
expectError(t, ts.get("/_matrix/federation/v1/openid/userinfo", ""),
|
|
http.StatusUnauthorized, "M_MISSING_TOKEN")
|
|
|
|
// Nobody gets a token in someone else's name.
|
|
expectError(t, ts.post(path, bob.AccessToken, map[string]any{}), http.StatusForbidden, httputil.ErrCodeForbidden)
|
|
}
|
|
|
|
// TestOpenIDUserInfoIgnoresFederationSwitch: the userinfo endpoint answers
|
|
// with federation off, so a server that does not federate can still let its
|
|
// users into group calls.
|
|
func TestOpenIDUserInfoIgnoresFederationSwitch(t *testing.T) {
|
|
ts := newTestServer(t, nil)
|
|
if ts.settings.FederationEnabled() {
|
|
t.Fatal("the test server is expected to start with federation off")
|
|
}
|
|
alice := ts.register("alice", "correct-horse-battery-staple")
|
|
rec := ts.post("/_matrix/client/v3/user/"+url.PathEscape(alice.UserID)+"/openid/request_token",
|
|
alice.AccessToken, nil)
|
|
expectStatus(t, rec, http.StatusOK)
|
|
token, _ := jsonBody(t, rec)["access_token"].(string)
|
|
expectStatus(t, ts.get("/_matrix/federation/v1/openid/userinfo?access_token="+url.QueryEscape(token), ""), http.StatusOK)
|
|
}
|