fix(voice): административный токен RoomService привязан к комнате
LiveKit принимает право `roomAdmin` только вместе с именем комнаты: без `video.room` RoomService отвечает 401 `permissions denied` — серверный мьют и отключение участника не доходили до SFU, хотя API отвечал 200 (AGENT.md 7.14). - `voice.IssueAdmin(room)` кладёт в грахт `room` и `roomAdmin` и отклоняет пустое имя комнаты; - `AdminClient.call` выпускает токен под конкретную комнату каждого вызова (GetParticipant, MutePublishedTrack, RemoveParticipant, ListParticipants); - тест на состав грахта и отказ при пустой комнате; - e2e: администратор и гость работают в отдельных api-контекстах (код 2FA одноразовый), нажатие «Войти» в комнату не ждёт стабильности исчезающей кнопки.
This commit is contained in:
+10
-8
@@ -120,12 +120,17 @@ func encodeSegment(payload []byte) string {
|
||||
return base64.RawURLEncoding.EncodeToString(payload)
|
||||
}
|
||||
|
||||
// IssueAdmin подписывает административный токен RoomService: полные права на
|
||||
// комнаты (модерация, удаление участников), но не на запись медиа.
|
||||
func (i *TokenIssuer) IssueAdmin() (string, error) {
|
||||
// IssueAdmin подписывает административный токен RoomService: права на
|
||||
// модерацию одной комнаты (мьют дорожки, удаление участника), но не на запись
|
||||
// медиа. LiveKit проверяет `roomAdmin` вместе с именем комнаты: без `room` в
|
||||
// грахте RoomService отвечает 401 `permissions denied`.
|
||||
func (i *TokenIssuer) IssueAdmin(room string) (string, error) {
|
||||
if !i.Enabled() {
|
||||
return "", ErrDisabled
|
||||
}
|
||||
if strings.TrimSpace(room) == "" {
|
||||
return "", fmt.Errorf("voice.invalid_room: пустое имя комнаты")
|
||||
}
|
||||
now := i.now().UTC()
|
||||
claims := map[string]any{
|
||||
"iss": i.apiKey,
|
||||
@@ -133,11 +138,8 @@ func (i *TokenIssuer) IssueAdmin() (string, error) {
|
||||
"nbf": now.Add(-10 * time.Second).Unix(),
|
||||
"exp": now.Add(10 * time.Minute).Unix(),
|
||||
"video": map[string]any{
|
||||
"roomCreate": true,
|
||||
"roomList": true,
|
||||
"roomAdmin": true,
|
||||
"roomRecord": false,
|
||||
"ingressAdmin": false,
|
||||
"room": room,
|
||||
"roomAdmin": true,
|
||||
},
|
||||
}
|
||||
header, err := json.Marshal(map[string]string{"alg": "HS256", "typ": "JWT"})
|
||||
|
||||
Reference in New Issue
Block a user