589c317841
Deploy PROD / deploy (push) Successful in 26s
Karta "Na sali" dostala przelaczniki kamery i udostepniania ekranu przy kazdym uczestniku (wylacznie LiveKit). Uprawnienia licza sie z trzech niezaleznych praw (PublishRights: mikrofon, kamera, ekran) zamiast jednej roli, w jednym miejscu dla tokenu i zmiany na zywo; serwer pokoju nadaje i odbiera je bez ponownego wejscia na sale. Kolumny camera_allowed i screen_allowed (V32), domyslnie false. Zgoda indywidualna przezywa wylaczenie "wideo dla wszystkich". Uczestnik dostaje komunikat, a przy ekranie ostrzezenie, ze sala zobaczy wszystko. PublishRightsTest i PublishRightsTokenTest pilnuja, ze zgoda na jedno zrodlo nie otwiera innego; oba sprawdzone w obie strony. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
87 lines
3.2 KiB
Java
87 lines
3.2 KiB
Java
package com.softspm.webinar.video;
|
|
|
|
import com.softspm.webinar.domain.Webinar;
|
|
import com.softspm.webinar.settings.SettingKey;
|
|
import com.softspm.webinar.settings.SettingsService;
|
|
import io.jsonwebtoken.Jwts;
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.mockito.Mockito.mock;
|
|
import static org.mockito.Mockito.when;
|
|
|
|
/**
|
|
* Token LiveKit wydany dla indywidualnych zgod na kamere i ekran.
|
|
*
|
|
* Bez kontekstu Springa i bez bazy: ustawienia sa podstawione, a token
|
|
* rozkladany tak samo jak w `ProviderTokenTest`. Sprawdza to, co faktycznie
|
|
* trafia do serwera LiveKit, czyli liste zrodel w podpisanym tokenie, a nie
|
|
* tylko obiekt uprawnien po naszej stronie.
|
|
*/
|
|
class PublishRightsTokenTest {
|
|
|
|
private static final String SECRET = "sekret-testowy-livekit-co-najmniej-32-znaki";
|
|
|
|
private final LiveKitVideoProvider provider = new LiveKitVideoProvider(settings());
|
|
|
|
private static SettingsService settings() {
|
|
SettingsService settings = mock(SettingsService.class);
|
|
when(settings.get(SettingKey.LIVEKIT_URL)).thenReturn("wss://livekit.example.test");
|
|
when(settings.get(SettingKey.LIVEKIT_API_KEY)).thenReturn("klucz-testowy");
|
|
when(settings.get(SettingKey.LIVEKIT_API_SECRET)).thenReturn(SECRET);
|
|
return settings;
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
private Map<String, Object> grants(PublishRights rights) {
|
|
Webinar webinar = new Webinar();
|
|
webinar.setId(4242L);
|
|
String jwt = provider.createJoinTicket(webinar, new VideoProvider.JoinRequest(
|
|
"Jan Testowy", "reg-1", rights.closestRole(), rights)).token();
|
|
var claims = Jwts.parser()
|
|
.verifyWith(new SecretKeySpec(SECRET.getBytes(StandardCharsets.UTF_8), "HmacSHA256"))
|
|
.build()
|
|
.parseSignedClaims(jwt)
|
|
.getPayload();
|
|
return (Map<String, Object>) claims.get("video");
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
private static List<String> sources(Map<String, Object> video) {
|
|
Object raw = video.get("canPublishSources");
|
|
return raw == null ? List.of() : (List<String>) raw;
|
|
}
|
|
|
|
@Test
|
|
void screenOnlyTokenHasNoCameraAndNoMicrophone() {
|
|
var video = grants(new PublishRights(false, false, true));
|
|
assertThat(video.get("canPublish")).isEqualTo(true);
|
|
assertThat(sources(video)).containsExactlyInAnyOrder("screen_share", "screen_share_audio");
|
|
}
|
|
|
|
@Test
|
|
void cameraOnlyTokenHasNoMicrophone() {
|
|
var video = grants(new PublishRights(false, true, false));
|
|
assertThat(sources(video)).containsExactly("camera");
|
|
}
|
|
|
|
@Test
|
|
void noRightsMeansNoPublishing() {
|
|
var video = grants(PublishRights.NONE);
|
|
assertThat(video.get("canPublish")).isEqualTo(false);
|
|
assertThat(sources(video)).isEmpty();
|
|
}
|
|
|
|
@Test
|
|
void participantTokenNeverGetsRoomAdmin() {
|
|
var video = grants(new PublishRights(true, true, true));
|
|
assertThat(video.get("roomAdmin")).isNotEqualTo(true);
|
|
assertThat(video.get("roomRecord")).isNotEqualTo(true);
|
|
}
|
|
}
|