99import io .swagger .v3 .oas .annotations .tags .Tag ;
1010import lombok .RequiredArgsConstructor ;
1111import lombok .extern .slf4j .Slf4j ;
12+ import org .springframework .beans .factory .annotation .Value ;
13+ import javax .crypto .Mac ;
14+ import javax .crypto .spec .SecretKeySpec ;
15+ import java .nio .charset .StandardCharsets ;
16+ import java .util .ArrayList ;
17+ import java .util .Base64 ;
1218import org .springframework .boot .context .properties .EnableConfigurationProperties ;
1319import org .springframework .http .HttpStatus ;
1420import org .springframework .http .ResponseEntity ;
1521import org .springframework .web .bind .annotation .*;
16-
1722import java .util .List ;
1823
1924@ Slf4j
@@ -26,6 +31,15 @@ public class WebRTCApiController {
2631
2732 private final WebRTCProperties webRTCProperties ;
2833
34+ @ Value ("${webrtc.turn.shared-secret}" )
35+ private String turnSharedSecret ;
36+
37+ @ Value ("${webrtc.turn.server-ip}" )
38+ private String turnServerIp ;
39+
40+ @ Value ("${webrtc.turn.ttl-seconds}" )
41+ private long turnTtlSeconds ;
42+
2943 @ GetMapping ("/ice-servers" )
3044 @ Operation (summary = "ICE 서버 설정 조회" )
3145 public ResponseEntity <RsData <IceServerConfig >> getIceServers (
@@ -34,13 +48,35 @@ public ResponseEntity<RsData<IceServerConfig>> getIceServers(
3448
3549 log .info ("ICE 서버 설정 요청 - userId: {}, roomId: {}" , userId , roomId );
3650
37- List <IceServer > iceServers =
51+ List <IceServer > iceServers = new ArrayList <>(
3852 webRTCProperties .iceServers ().stream ()
3953 .map (s -> new IceServer (s .urls (), s .username (), s .credential ()))
40- .toList ();
54+ .toList ()
55+ );
4156
42- IceServerConfig config = new IceServerConfig (iceServers );
57+ // 동적으로 시간제한이 있는 TURN 서버 인증 정보 생성
58+ try {
59+ // 유효기간 타임스탬프를 생성 (현재 시간 + TTL)
60+ long expiry = (System .currentTimeMillis () / 1000 ) + turnTtlSeconds ;
61+ String username = String .valueOf (expiry );
4362
63+ // HMAC-SHA1 알고리즘과 공유 비밀키를 사용하여 비밀번호(credential) 생성
64+ Mac sha1Hmac = Mac .getInstance ("HmacSHA1" );
65+ SecretKeySpec secretKey = new SecretKeySpec (turnSharedSecret .getBytes (StandardCharsets .UTF_8 ), "HmacSHA1" );
66+ sha1Hmac .init (secretKey );
67+ byte [] hmacBytes = sha1Hmac .doFinal (username .getBytes (StandardCharsets .UTF_8 ));
68+ String credential = Base64 .getEncoder ().encodeToString (hmacBytes );
69+
70+ // 생성된 TURN 서버 정보를 리스트에 추가
71+ String turnUrl = "turn:" + turnServerIp + ":3478" ;
72+ iceServers .add (IceServer .turn (turnUrl , username , credential ));
73+
74+ } catch (Exception e ) {
75+ log .error ("TURN 서버 동적 인증 정보 생성에 실패했습니다. STUN 서버만으로 응답합니다." , e );
76+ // 인증 정보 생성에 실패하더라도, STUN 서버만으로라도 서비스가 동작하도록 예외를 던지지 않음
77+ }
78+
79+ IceServerConfig config = new IceServerConfig (iceServers );
4480 log .info ("ICE 서버 설정 제공 완료 - STUN/TURN 서버 {}개" , config .iceServers ().size ());
4581
4682 return ResponseEntity
0 commit comments