fix: RequestEntry TOCTOU 경쟁 조건 수정 — 트랜잭션으로 원자화
중복 입장 방지를 위해 active-room 체크와 room 생성을 단일 트랜잭션으로 래핑 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user