From 9504bf37de3439c32e48cef99df9acae2a095f70 Mon Sep 17 00:00:00 2001 From: tolelom <98kimsungmin@naver.com> Date: Sun, 15 Mar 2026 18:53:33 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20RequestEntry=20TOCTOU=20=EA=B2=BD?= =?UTF-8?q?=EC=9F=81=20=EC=A1=B0=EA=B1=B4=20=EC=88=98=EC=A0=95=20=E2=80=94?= =?UTF-8?q?=20=ED=8A=B8=EB=9E=9C=EC=9E=AD=EC=85=98=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9B=90=EC=9E=90=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 중복 입장 방지를 위해 active-room 체크와 room 생성을 단일 트랜잭션으로 래핑 Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/bossraid/service.go | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/internal/bossraid/service.go b/internal/bossraid/service.go index 97e5d96..5418834 100644 --- a/internal/bossraid/service.go +++ b/internal/bossraid/service.go @@ -64,17 +64,6 @@ func (s *Service) RequestEntry(usernames []string, bossID int) (*BossRoom, error seen[u] = true } - // Check if any player is already in an active room - for _, username := range usernames { - count, err := s.repo.CountActiveByUsername(username) - if err != nil { - return nil, fmt.Errorf("플레이어 상태 확인 실패: %w", err) - } - if count > 0 { - return nil, fmt.Errorf("플레이어 %s가 이미 보스 레이드 중입니다", username) - } - } - playersJSON, err := json.Marshal(usernames) if err != nil { return nil, fmt.Errorf("플레이어 목록 직렬화 실패: %w", err) @@ -90,8 +79,24 @@ func (s *Service) RequestEntry(usernames []string, bossID int) (*BossRoom, error Players: string(playersJSON), } - if err := s.repo.Create(room); err != nil { - return nil, fmt.Errorf("방 생성 실패: %w", err) + // Wrap active-room check + creation in a transaction to prevent TOCTOU race. + err = s.repo.Transaction(func(txRepo *Repository) error { + for _, username := range usernames { + count, err := txRepo.CountActiveByUsername(username) + if err != nil { + return fmt.Errorf("플레이어 상태 확인 실패: %w", err) + } + if count > 0 { + return fmt.Errorf("플레이어 %s가 이미 보스 레이드 중입니다", username) + } + } + if err := txRepo.Create(room); err != nil { + return fmt.Errorf("방 생성 실패: %w", err) + } + return nil + }) + if err != nil { + return nil, err } return room, nil