mirror of
https://github.com/strukturag/nextcloud-spreed-signaling
synced 2024-06-08 08:52:27 +02:00
Merge pull request #227 from strukturag/hide-displaynames
Add "permission" for sessions that may not receive display names.
This commit is contained in:
commit
f8f2adb0e2
|
@ -620,6 +620,18 @@ type RoomFlagsServerMessage struct {
|
||||||
Flags uint32 `json:"flags"`
|
Flags uint32 `json:"flags"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ChatComment map[string]interface{}
|
||||||
|
|
||||||
|
type RoomEventMessageDataChat struct {
|
||||||
|
Comment *ChatComment `json:"comment,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RoomEventMessageData struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
Chat *RoomEventMessageDataChat `json:"chat,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type EventServerMessage struct {
|
type EventServerMessage struct {
|
||||||
Target string `json:"target"`
|
Target string `json:"target"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
@ -646,6 +658,15 @@ type EventServerMessageSessionEntry struct {
|
||||||
RoomSessionId string `json:"roomsessionid,omitempty"`
|
RoomSessionId string `json:"roomsessionid,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *EventServerMessageSessionEntry) Clone() *EventServerMessageSessionEntry {
|
||||||
|
return &EventServerMessageSessionEntry{
|
||||||
|
SessionId: e.SessionId,
|
||||||
|
UserId: e.UserId,
|
||||||
|
User: e.User,
|
||||||
|
RoomSessionId: e.RoomSessionId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MCU-related types
|
// MCU-related types
|
||||||
|
|
||||||
type AnswerOfferMessage struct {
|
type AnswerOfferMessage struct {
|
||||||
|
|
130
clientsession.go
130
clientsession.go
|
@ -214,6 +214,9 @@ func (s *ClientSession) hasAnyPermissionLocked(permission ...Permission) bool {
|
||||||
func (s *ClientSession) hasPermissionLocked(permission Permission) bool {
|
func (s *ClientSession) hasPermissionLocked(permission Permission) bool {
|
||||||
if !s.supportsPermissions {
|
if !s.supportsPermissions {
|
||||||
// Old-style session that doesn't receive permissions from Nextcloud.
|
// Old-style session that doesn't receive permissions from Nextcloud.
|
||||||
|
if result, found := DefaultPermissionOverrides[permission]; found {
|
||||||
|
return result
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,6 +645,11 @@ func (s *ClientSession) SendError(e *Error) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ClientSession) SendMessage(message *ServerMessage) bool {
|
func (s *ClientSession) SendMessage(message *ServerMessage) bool {
|
||||||
|
message = s.filterMessage(message)
|
||||||
|
if message == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
|
@ -1030,6 +1038,110 @@ func (s *ClientSession) storePendingMessage(message *ServerMessage) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func filterDisplayNames(events []*EventServerMessageSessionEntry) []*EventServerMessageSessionEntry {
|
||||||
|
result := make([]*EventServerMessageSessionEntry, 0, len(events))
|
||||||
|
for _, event := range events {
|
||||||
|
if event.User == nil {
|
||||||
|
result = append(result, event)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var userdata map[string]interface{}
|
||||||
|
if err := json.Unmarshal(*event.User, &userdata); err != nil {
|
||||||
|
result = append(result, event)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, found := userdata["displayname"]; !found {
|
||||||
|
result = append(result, event)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(userdata, "displayname")
|
||||||
|
if len(userdata) == 0 {
|
||||||
|
// No more userdata, no need to serialize empty map.
|
||||||
|
e := event.Clone()
|
||||||
|
e.User = nil
|
||||||
|
result = append(result, e)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := json.Marshal(userdata)
|
||||||
|
if err != nil {
|
||||||
|
result = append(result, event)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
e := event.Clone()
|
||||||
|
e.User = (*json.RawMessage)(&data)
|
||||||
|
result = append(result, e)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClientSession) filterMessage(message *ServerMessage) *ServerMessage {
|
||||||
|
switch message.Type {
|
||||||
|
case "event":
|
||||||
|
switch message.Event.Target {
|
||||||
|
case "participants":
|
||||||
|
if message.Event.Type == "update" {
|
||||||
|
m := message.Event.Update
|
||||||
|
users := make(map[string]bool)
|
||||||
|
for _, entry := range m.Users {
|
||||||
|
users[entry["sessionId"].(string)] = true
|
||||||
|
}
|
||||||
|
for _, entry := range m.Changed {
|
||||||
|
if users[entry["sessionId"].(string)] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m.Users = append(m.Users, entry)
|
||||||
|
}
|
||||||
|
// TODO(jojo): Only send all users if current session id has
|
||||||
|
// changed its "inCall" flag to true.
|
||||||
|
m.Changed = nil
|
||||||
|
}
|
||||||
|
case "room":
|
||||||
|
switch message.Event.Type {
|
||||||
|
case "join":
|
||||||
|
if s.HasPermission(PERMISSION_HIDE_DISPLAYNAMES) {
|
||||||
|
message.Event.Join = filterDisplayNames(message.Event.Join)
|
||||||
|
}
|
||||||
|
case "message":
|
||||||
|
if message.Event.Message == nil || message.Event.Message.Data == nil || len(*message.Event.Message.Data) == 0 || !s.HasPermission(PERMISSION_HIDE_DISPLAYNAMES) {
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
var data RoomEventMessageData
|
||||||
|
if err := json.Unmarshal(*message.Event.Message.Data, &data); err != nil {
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Type == "chat" && data.Chat != nil && data.Chat.Comment != nil {
|
||||||
|
if displayName, found := (*data.Chat.Comment)["actorDisplayName"]; found && displayName != "" {
|
||||||
|
(*data.Chat.Comment)["actorDisplayName"] = ""
|
||||||
|
if encoded, err := json.Marshal(data); err == nil {
|
||||||
|
message.Event.Message.Data = (*json.RawMessage)(&encoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "message":
|
||||||
|
if message.Message != nil && message.Message.Data != nil && len(*message.Message.Data) > 0 && s.HasPermission(PERMISSION_HIDE_DISPLAYNAMES) {
|
||||||
|
var data MessageServerMessageData
|
||||||
|
if err := json.Unmarshal(*message.Message.Data, &data); err != nil {
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.Type == "nickChanged" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ClientSession) processNatsMessage(msg *NatsMessage) *ServerMessage {
|
func (s *ClientSession) processNatsMessage(msg *NatsMessage) *ServerMessage {
|
||||||
switch msg.Type {
|
switch msg.Type {
|
||||||
case "message":
|
case "message":
|
||||||
|
@ -1054,23 +1166,7 @@ func (s *ClientSession) processNatsMessage(msg *NatsMessage) *ServerMessage {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case "event":
|
case "event":
|
||||||
if msg.Message.Event.Target == "participants" &&
|
if msg.Message.Event.Target == "room" {
|
||||||
msg.Message.Event.Type == "update" {
|
|
||||||
m := msg.Message.Event.Update
|
|
||||||
users := make(map[string]bool)
|
|
||||||
for _, entry := range m.Users {
|
|
||||||
users[entry["sessionId"].(string)] = true
|
|
||||||
}
|
|
||||||
for _, entry := range m.Changed {
|
|
||||||
if users[entry["sessionId"].(string)] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
m.Users = append(m.Users, entry)
|
|
||||||
}
|
|
||||||
// TODO(jojo): Only send all users if current session id has
|
|
||||||
// changed its "inCall" flag to true.
|
|
||||||
m.Changed = nil
|
|
||||||
} else if msg.Message.Event.Target == "room" {
|
|
||||||
// Can happen mostly during tests where an older room NATS message
|
// Can happen mostly during tests where an older room NATS message
|
||||||
// could be received by a subscriber that joined after it was sent.
|
// could be received by a subscriber that joined after it was sent.
|
||||||
if msg.SendTime.Before(s.getRoomJoinTime()) {
|
if msg.SendTime.Before(s.getRoomJoinTime()) {
|
||||||
|
|
90
hub_test.go
90
hub_test.go
|
@ -259,6 +259,14 @@ func processAuthRequest(t *testing.T, w http.ResponseWriter, r *http.Request, re
|
||||||
UserId: params.UserId,
|
UserId: params.UserId,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
userdata := map[string]string{
|
||||||
|
"displayname": "Displayname " + params.UserId,
|
||||||
|
}
|
||||||
|
if data, err := json.Marshal(userdata); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else {
|
||||||
|
response.Auth.User = (*json.RawMessage)(&data)
|
||||||
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1827,6 +1835,88 @@ func TestJoinMultiple(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJoinMultipleDisplaynamesPermission(t *testing.T) {
|
||||||
|
hub, _, _, server := CreateHubForTest(t)
|
||||||
|
|
||||||
|
client1 := NewTestClient(t, server, hub)
|
||||||
|
defer client1.CloseWithBye()
|
||||||
|
if err := client1.SendHello(testDefaultUserId + "1"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
client2 := NewTestClient(t, server, hub)
|
||||||
|
defer client2.CloseWithBye()
|
||||||
|
if err := client2.SendHello(testDefaultUserId + "2"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
hello1, err := client1.RunUntilHello(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
hello2, err := client2.RunUntilHello(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
session2 := hub.GetSessionByPublicId(hello2.Hello.SessionId).(*ClientSession)
|
||||||
|
if session2 == nil {
|
||||||
|
t.Fatalf("Session %s does not exist", hello2.Hello.SessionId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client 2 may not receive display names.
|
||||||
|
session2.SetPermissions([]Permission{PERMISSION_HIDE_DISPLAYNAMES})
|
||||||
|
|
||||||
|
// Join room by id (first client).
|
||||||
|
roomId := "test-room"
|
||||||
|
if room, err := client1.JoinRoom(ctx, roomId); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if room.Room.RoomId != roomId {
|
||||||
|
t.Fatalf("Expected room %s, got %s", roomId, room.Room.RoomId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will receive a "joined" event.
|
||||||
|
if err := client1.RunUntilJoined(ctx, hello1.Hello); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join room by id (second client).
|
||||||
|
if room, err := client2.JoinRoom(ctx, roomId); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if room.Room.RoomId != roomId {
|
||||||
|
t.Fatalf("Expected room %s, got %s", roomId, room.Room.RoomId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will receive a "joined" event for the first and the second client.
|
||||||
|
if events, unexpected, err := client2.RunUntilJoinedAndReturn(ctx, hello1.Hello, hello2.Hello); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else {
|
||||||
|
if len(unexpected) > 0 {
|
||||||
|
t.Errorf("Received unexpected messages: %+v", unexpected)
|
||||||
|
} else if len(events) != 2 {
|
||||||
|
t.Errorf("Expected two event, got %+v", events)
|
||||||
|
} else if events[0].User != nil {
|
||||||
|
t.Errorf("Expected empty userdata for first event, got %+v", events[0].User)
|
||||||
|
} else if events[1].User != nil {
|
||||||
|
t.Errorf("Expected empty userdata for second event, got %+v", events[1].User)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The first client will also receive a "joined" event from the second client.
|
||||||
|
if events, unexpected, err := client1.RunUntilJoinedAndReturn(ctx, hello2.Hello); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else {
|
||||||
|
if len(unexpected) > 0 {
|
||||||
|
t.Errorf("Received unexpected messages: %+v", unexpected)
|
||||||
|
} else if len(events) != 1 {
|
||||||
|
t.Errorf("Expected one event, got %+v", events)
|
||||||
|
} else if events[0].User == nil {
|
||||||
|
t.Errorf("Expected userdata for first event, got nothing")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestJoinRoomSwitchClient(t *testing.T) {
|
func TestJoinRoomSwitchClient(t *testing.T) {
|
||||||
hub, _, _, server := CreateHubForTest(t)
|
hub, _, _, server := CreateHubForTest(t)
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,14 @@ var (
|
||||||
PERMISSION_MAY_PUBLISH_SCREEN Permission = "publish-screen"
|
PERMISSION_MAY_PUBLISH_SCREEN Permission = "publish-screen"
|
||||||
PERMISSION_MAY_CONTROL Permission = "control"
|
PERMISSION_MAY_CONTROL Permission = "control"
|
||||||
PERMISSION_TRANSIENT_DATA Permission = "transient-data"
|
PERMISSION_TRANSIENT_DATA Permission = "transient-data"
|
||||||
|
PERMISSION_HIDE_DISPLAYNAMES Permission = "hide-displaynames"
|
||||||
|
|
||||||
|
// DefaultPermissionOverrides contains permission overrides for users where
|
||||||
|
// no permissions have been set by the server. If a permission is not set in
|
||||||
|
// this map, it's assumed the user has that permission.
|
||||||
|
DefaultPermissionOverrides = map[Permission]bool{
|
||||||
|
PERMISSION_HIDE_DISPLAYNAMES: false,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type SessionIdData struct {
|
type SessionIdData struct {
|
||||||
|
|
|
@ -596,30 +596,36 @@ func (c *TestClient) checkMessageJoinedSession(message *ServerMessage, sessionId
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TestClient) RunUntilJoinedAndReturnIgnored(ctx context.Context, hello ...*HelloServerMessage) ([]*ServerMessage, error) {
|
func (c *TestClient) RunUntilJoinedAndReturn(ctx context.Context, hello ...*HelloServerMessage) ([]*EventServerMessageSessionEntry, []*ServerMessage, error) {
|
||||||
|
received := make([]*EventServerMessageSessionEntry, len(hello))
|
||||||
var ignored []*ServerMessage
|
var ignored []*ServerMessage
|
||||||
for len(hello) > 0 {
|
hellos := make(map[*HelloServerMessage]int, len(hello))
|
||||||
|
for idx, h := range hello {
|
||||||
|
hellos[h] = idx
|
||||||
|
}
|
||||||
|
for len(hellos) > 0 {
|
||||||
message, err := c.RunUntilMessage(ctx)
|
message, err := c.RunUntilMessage(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := checkMessageType(message, "event"); err != nil {
|
if err := checkMessageType(message, "event"); err != nil {
|
||||||
ignored = append(ignored, message)
|
ignored = append(ignored, message)
|
||||||
continue
|
continue
|
||||||
} else if message.Event.Target != "room" {
|
} else if message.Event.Target != "room" {
|
||||||
return nil, fmt.Errorf("Expected event target room, got %+v", message.Event)
|
return nil, nil, fmt.Errorf("Expected event target room, got %+v", message.Event)
|
||||||
} else if message.Event.Type != "join" {
|
} else if message.Event.Type != "join" {
|
||||||
return nil, fmt.Errorf("Expected event type join, got %+v", message.Event)
|
return nil, nil, fmt.Errorf("Expected event type join, got %+v", message.Event)
|
||||||
}
|
}
|
||||||
|
|
||||||
for len(message.Event.Join) > 0 {
|
for len(message.Event.Join) > 0 {
|
||||||
found := false
|
found := false
|
||||||
loop:
|
loop:
|
||||||
for idx, h := range hello {
|
for h, idx := range hellos {
|
||||||
for idx2, evt := range message.Event.Join {
|
for idx2, evt := range message.Event.Join {
|
||||||
if evt.SessionId == h.SessionId && evt.UserId == h.UserId {
|
if evt.SessionId == h.SessionId && evt.UserId == h.UserId {
|
||||||
hello = append(hello[:idx], hello[idx+1:]...)
|
received[idx] = evt
|
||||||
|
delete(hellos, h)
|
||||||
message.Event.Join = append(message.Event.Join[:idx2], message.Event.Join[idx2+1:]...)
|
message.Event.Join = append(message.Event.Join[:idx2], message.Event.Join[idx2+1:]...)
|
||||||
found = true
|
found = true
|
||||||
break loop
|
break loop
|
||||||
|
@ -627,15 +633,15 @@ func (c *TestClient) RunUntilJoinedAndReturnIgnored(ctx context.Context, hello .
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
return nil, fmt.Errorf("expected one of the passed hello sessions, got %+v", message.Event.Join[0])
|
return nil, nil, fmt.Errorf("expected one of the passed hello sessions, got %+v", message.Event.Join[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ignored, nil
|
return received, ignored, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TestClient) RunUntilJoined(ctx context.Context, hello ...*HelloServerMessage) error {
|
func (c *TestClient) RunUntilJoined(ctx context.Context, hello ...*HelloServerMessage) error {
|
||||||
unexpected, err := c.RunUntilJoinedAndReturnIgnored(ctx, hello...)
|
_, unexpected, err := c.RunUntilJoinedAndReturn(ctx, hello...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,7 +269,7 @@ func Test_TransientMessages(t *testing.T) {
|
||||||
t.Fatalf("Expected room %s, got %s", roomId, room.Room.RoomId)
|
t.Fatalf("Expected room %s, got %s", roomId, room.Room.RoomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
ignored, err := client3.RunUntilJoinedAndReturnIgnored(ctx, hello1.Hello, hello2.Hello, hello3.Hello)
|
_, ignored, err := client3.RunUntilJoinedAndReturn(ctx, hello1.Hello, hello2.Hello, hello3.Hello)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue