Skip to content

Secured Rooms

Dhruvik edited this page Nov 15, 2024 · 3 revisions

There will be rooms which you wish to be protected or where only authorized users are welcomed this section will give you example how to do it.

Logic

Mesh Global room is where clients default join . Its also the place from where client will join a particular room either directly as implemented below or indirectly from UI like wordsbattle .

Client via websocket can check if the token is correct or whatever roles you need a client has to have to join a room successfully . You can push the client roles directly into header as given in the 2nd code snippet app.Handle .

The below function will help you to get ClientAuthMetadata later on . Either through events of mesh-global room for direct room join below sample or triggered message in mesh-global to join a particular room like here you can get the client who want to join what is the authmetadata and verify if it can join .

server.GetClientAuthMetadata(clienslug string)

type Updates struct {
	Slug    string
	Roles   []string
	Message chan []string
}

// HandleRoomData implements simplysocket.RoomData.
func (r *Updates) HandleRoomData(room simplysocket.Room, server simplysocket.MeshServer) {
	roomname := room.GetRoomSlugInfo()
	r.Slug = roomname
	log.Println("Handeling data Server for ", roomname, server.GetGameName())
	r.PushETLUpdateMessages(room, server)
	r.HandleRoomEvents(room, server)
	for {
		select {
		case message, ok := <-room.ConsumeRoomMessage():
			if !ok {
				log.Println("Channel closed. Exiting HandleRoomData for", roomname)
			}
			if message.Target == roomname {
				switch message.Action {
				case "send-message":
					message.IsTargetClient = false
					room.BroadcastMessage(message)
				}
			}

		case <-room.RoomStopped():
			log.Println("Room is stopped so stop the handler")
			return

		}
	}
}


func (r *Updates) HandleRoomEvents(room simplysocket.Room, server simplysocket.MeshServer) {
	go func() {
		for {
			select {
			case clientevent := <-room.EventTriggers():
				if room.GetRoomSlugInfo() == "mesh-global" && clientevent[0] == "client-joined-room" {
					canJoinRoom := matchStringLists([]string{"loggedIn", "notify"}, server.GetClientAuthMetadata(clientevent[2]))
					if clientevent[1] == r.Slug {
						message := &simplysocket.Message{
							Action: "client-count",
							Target: room.GetRoomSlugInfo(),
							MessageBody: map[string]interface{}{
								"message": strconv.Itoa(len(server.GetClientsInRoom()[r.Slug])),
							},
							Sender:         "etl",
							IsTargetClient: false,
						}
						room.BroadcastMessage(message)
					}
					if !canJoinRoom {
						message := &simplysocket.Message{
							Action: "updates-message",
							Target: clientevent[2],
							MessageBody: map[string]interface{}{
								"message": []string{"API key is not correct so cannot notify", "fail"},
							},
							Sender:         "etl",
							IsTargetClient: true,
						}
						log.Println("NOT AUTHENTICATED")
						room.BroadcastMessage(message)

					} else {
						server.JoinClientRoom("room-updates", clientevent[2], &Updates{
							Message: r.Message,
							Roles:   []string{"loggedIn", "notify"},
							Slug:    "room-updates",
						})
						message := &simplysocket.Message{
							Action: "updates-message",
							Target: clientevent[2],
							MessageBody: map[string]interface{}{
								"message": []string{"Authenticated can notify", "info"},
							},
							Sender:         "etl",
							IsTargetClient: true,
						}
						log.Println("AUTHENTICATED")
						room.BroadcastMessage(message)
					}
				}

			case <-room.RoomStopped():
				log.Println("Room is stopped so stop the handler events")
				return
			}
		}
	}()
} 

client side :- You need to add header Role which takes comma seperated strings and later you can use it for room security . This is what server.GetAuthMetadata will return list of strings.

app.Handle("GET", "/etl-data", func(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
		key := r.URL.Query().Get("token")
		if strings.Compare(key, apiKey) != 0 {
			log.Println("is not authenticated", apiKey, key)
			simplysocket.ServeWs(ms, w, r)
			return nil
		} else {
			//must have Role , seperated
			log.Println("is authenticated")
			r.Header.Set("Role", "loggedIn,notify")
			simplysocket.ServeWs(ms, w, r)
			return nil
		}
	})

mesh-global is a global room which is provided where all the clients and rooms are present . You can use server.GetClientAuthMetadata(clientslug string) where you can get the clientslug from events in mesh-global room . The Room Data which is your custom struct will hold the Roles you want and can be matched .

This way you can match the authmetadata which you send through client side and then match it based on your custom room data .

Clone this wiki locally