mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-07 09:23:38 +00:00
🔒️(backend) rely on backend to allow participant update their metadata
Introduce toggle-hand and rename endpoints in RoomViewSet, secured with LiveKit token authentication. Remove direct permission for clients to update their own metadata via LiveKit tokens to prevent spoofing (e.g. faking admin status). Proxy participant metadata updates through the backend to enforce proper validation and authorization. Signed-off-by: lebaudantoine <lebaud.antoine131@gmail.com>
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
import { fetchApi } from '@/api/fetchApi'
|
||||
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
|
||||
|
||||
export const useRenameParticipant = () => {
|
||||
const data = useRoomData()
|
||||
|
||||
const renameParticipant = async (name: string) => {
|
||||
if (!data?.id) {
|
||||
throw new Error('Room id is not available')
|
||||
}
|
||||
|
||||
const token = data?.livekit?.token
|
||||
|
||||
if (!token) {
|
||||
throw new Error('LiveKit token is not available')
|
||||
}
|
||||
|
||||
return fetchApi(`rooms/${data.id}/rename/`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
token,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
return { renameParticipant }
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { fetchApi } from '@/api/fetchApi'
|
||||
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
|
||||
|
||||
export const useRaiseHand = () => {
|
||||
const data = useRoomData()
|
||||
|
||||
const raiseHand = async (raised: boolean) => {
|
||||
if (!data?.id) {
|
||||
throw new Error('Room id is not available')
|
||||
}
|
||||
|
||||
const token = data?.livekit?.token
|
||||
|
||||
if (!token) {
|
||||
throw new Error('LiveKit token is not available')
|
||||
}
|
||||
|
||||
return fetchApi(`rooms/${data.id}/toggle-hand/`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
raised,
|
||||
token,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
return { raiseHand }
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
import { LocalParticipant, Participant } from 'livekit-client'
|
||||
import { Participant } from 'livekit-client'
|
||||
import {
|
||||
useParticipantAttribute,
|
||||
useParticipants,
|
||||
} from '@livekit/components-react'
|
||||
import { isLocal } from '@/utils/livekit'
|
||||
import { useMemo } from 'react'
|
||||
import { useRaiseHand } from '@/features/rooms/api/updateRaiseHand'
|
||||
|
||||
type useRaisedHandProps = {
|
||||
participant: Participant
|
||||
@@ -40,18 +41,19 @@ export function useRaisedHand({ participant }: useRaisedHandProps) {
|
||||
const handRaisedAtAttribute = useParticipantAttribute('handRaisedAt', {
|
||||
participant,
|
||||
})
|
||||
const { raiseHand } = useRaiseHand()
|
||||
|
||||
const isHandRaised = !!handRaisedAtAttribute
|
||||
|
||||
const toggleRaisedHand = async () => {
|
||||
if (!isLocal(participant)) return
|
||||
const localParticipant = participant as LocalParticipant
|
||||
|
||||
const attributes: Record<string, string> = {
|
||||
handRaisedAt: !isHandRaised ? new Date().toISOString() : '',
|
||||
try {
|
||||
await raiseHand(!isHandRaised)
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Failed to toggle hand: ${e instanceof Error ? e.message : 'Unknown error'}`
|
||||
)
|
||||
}
|
||||
|
||||
await localParticipant.setAttributes(attributes)
|
||||
}
|
||||
|
||||
return { isHandRaised, toggleRaisedHand }
|
||||
|
||||
@@ -8,6 +8,7 @@ import { HStack } from '@/styled-system/jsx'
|
||||
import { useState } from 'react'
|
||||
import { LoginButton } from '@/components/LoginButton'
|
||||
import { usePersistentUserChoices } from '@/features/rooms/livekit/hooks/usePersistentUserChoices'
|
||||
import { useRenameParticipant } from '@/features/rooms/api/renameParticipant'
|
||||
|
||||
export type AccountTabProps = Pick<DialogProps, 'onOpenChange'> &
|
||||
Pick<TabPanelProps, 'id'>
|
||||
@@ -17,16 +18,25 @@ export const AccountTab = ({ id, onOpenChange }: AccountTabProps) => {
|
||||
const { saveUsername } = usePersistentUserChoices()
|
||||
const room = useRoomContext()
|
||||
const { user, isLoggedIn, logout } = useUser()
|
||||
|
||||
const { renameParticipant } = useRenameParticipant()
|
||||
|
||||
const [name, setName] = useState(room?.localParticipant.name ?? '')
|
||||
const userDisplay =
|
||||
user?.full_name && user?.email
|
||||
? `${user.full_name} (${user.email})`
|
||||
: user?.email
|
||||
|
||||
const handleOnSubmit = () => {
|
||||
if (room) room.localParticipant.setName(name)
|
||||
saveUsername(name)
|
||||
if (onOpenChange) onOpenChange(false)
|
||||
const handleOnSubmit = async () => {
|
||||
try {
|
||||
if (room) await renameParticipant(name)
|
||||
saveUsername(name)
|
||||
onOpenChange?.(false) // only close on success
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Failed to rename participant: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
)
|
||||
}
|
||||
}
|
||||
const handleOnCancel = () => {
|
||||
if (onOpenChange) onOpenChange(false)
|
||||
|
||||
Reference in New Issue
Block a user