Convert actorId / actorType in participants updates for federated users.

See https://github.com/nextcloud/spreed/pull/12863 for details.
This commit is contained in:
Joachim Bauch 2024-08-05 08:38:30 +02:00
commit 11a1f365d9
No known key found for this signature in database
GPG key ID: 77C1D22D53E15F02
3 changed files with 86 additions and 10 deletions

View file

@ -41,6 +41,9 @@ const (
// Version 2.0 validates auth params encoded as JWT.
HelloVersionV2 = "2.0"
ActorTypeUsers = "users"
ActorTypeFederatedUsers = "federated_users"
)
var (
@ -52,6 +55,17 @@ func makePtr[T any](v T) *T {
return &v
}
func getStringMapEntry[T any](m map[string]interface{}, key string) (s T, ok bool) {
var defaultValue T
v, found := m[key]
if !found {
return defaultValue, false
}
s, ok = v.(T)
return
}
// ClientMessage is a message that is sent from a client to the server.
type ClientMessage struct {
json.Marshaler

View file

@ -55,6 +55,18 @@ func isClosedError(err error) bool {
strings.Contains(err.Error(), net.ErrClosed.Error())
}
func getCloudUrl(s string) string {
if strings.HasPrefix(s, "https://") {
s = s[8:]
} else {
s = strings.TrimPrefix(s, "http://")
}
if pos := strings.Index(s, "/ocs/v"); pos != -1 {
s = s[:pos]
}
return s
}
type FederationClient struct {
hub *Hub
session *ClientSession
@ -577,17 +589,36 @@ func (c *FederationClient) joinRoom() error {
}
func (c *FederationClient) updateEventUsers(users []map[string]interface{}, localSessionId string, remoteSessionId string) {
localCloudUrl := "@" + getCloudUrl(c.session.BackendUrl())
localCloudUrlLen := len(localCloudUrl)
remoteCloudUrl := "@" + getCloudUrl(c.federation.Load().NextcloudUrl)
checkSessionId := true
for _, u := range users {
key := "sessionId"
sid, found := u[key]
if !found {
key := "sessionid"
sid, found = u[key]
if actorType, found := getStringMapEntry[string](u, "actorType"); found {
if actorId, found := getStringMapEntry[string](u, "actorId"); found {
switch actorType {
case ActorTypeFederatedUsers:
if strings.HasSuffix(actorId, localCloudUrl) {
u["actorId"] = actorId[:len(actorId)-localCloudUrlLen]
u["actorType"] = ActorTypeUsers
}
case ActorTypeUsers:
u["actorId"] = actorId + remoteCloudUrl
u["actorType"] = ActorTypeFederatedUsers
}
}
}
if found {
if sid, ok := sid.(string); ok && sid == remoteSessionId {
if checkSessionId {
key := "sessionId"
sid, found := getStringMapEntry[string](u, key)
if !found {
key := "sessionid"
sid, found = getStringMapEntry[string](u, key)
}
if found && sid == remoteSessionId {
u[key] = localSessionId
break
checkSessionId = false
}
}
}

View file

@ -24,6 +24,7 @@ package signaling
import (
"context"
"encoding/json"
"strings"
"testing"
"time"
@ -286,23 +287,53 @@ func Test_Federation(t *testing.T) {
}
}
// Simulate request from the backend that somebody joined the call.
// Simulate request from the backend that a federated user joined the call.
users := []map[string]interface{}{
{
"sessionId": remoteSessionId,
"inCall": 1,
"actorId": "remoteUser@" + strings.TrimPrefix(server2.URL, "http://"),
"actorType": "federated_users",
},
}
room := hub1.getRoom(roomId)
require.NotNil(room)
room.PublishUsersInCallChanged(users, users)
var event *EventServerMessage
// For the local user, it's a federated user on server 2 that joined.
assert.NoError(checkReceiveClientEvent(ctx, client1, "update", &event))
assert.Equal(remoteSessionId, event.Update.Users[0]["sessionId"])
assert.Equal("remoteUser@"+strings.TrimPrefix(server2.URL, "http://"), event.Update.Users[0]["actorId"])
assert.Equal("federated_users", event.Update.Users[0]["actorType"])
assert.Equal(roomId, event.Update.RoomId)
// For the federated user, it's a local user that joined.
assert.NoError(checkReceiveClientEvent(ctx, client2, "update", &event))
assert.Equal(hello2.Hello.SessionId, event.Update.Users[0]["sessionId"])
assert.Equal("remoteUser", event.Update.Users[0]["actorId"])
assert.Equal("users", event.Update.Users[0]["actorType"])
assert.Equal(federatedRoomId, event.Update.RoomId)
// Simulate request from the backend that a local user joined the call.
users = []map[string]interface{}{
{
"sessionId": hello1.Hello.SessionId,
"inCall": 1,
"actorId": "localUser",
"actorType": "users",
},
}
room.PublishUsersInCallChanged(users, users)
// For the local user, it's a local user that joined.
assert.NoError(checkReceiveClientEvent(ctx, client1, "update", &event))
assert.Equal(hello1.Hello.SessionId, event.Update.Users[0]["sessionId"])
assert.Equal("localUser", event.Update.Users[0]["actorId"])
assert.Equal("users", event.Update.Users[0]["actorType"])
assert.Equal(roomId, event.Update.RoomId)
// For the federated user, it's a federated user on server 1 that joined.
assert.NoError(checkReceiveClientEvent(ctx, client2, "update", &event))
assert.Equal(hello1.Hello.SessionId, event.Update.Users[0]["sessionId"])
assert.Equal("localUser@"+strings.TrimPrefix(server1.URL, "http://"), event.Update.Users[0]["actorId"])
assert.Equal("federated_users", event.Update.Users[0]["actorType"])
assert.Equal(federatedRoomId, event.Update.RoomId)
// Joining another "direct" session will trigger correct events.