All checks were successful
Server CI/CD / deploy (push) Successful in 1m31s
- 입력 검증 강화 (로그인/체인 핸들러 전체) - boss raid 비관적 잠금으로 동시성 문제 해결 - SSAFY 사용자명 sanitize + 트랜잭션 처리 - constant-time API 키 비교, 보안 헤더, graceful shutdown - 안전하지 않은 기본값 경고 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
64 lines
1.7 KiB
Go
64 lines
1.7 KiB
Go
package bossraid
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
type Repository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewRepository(db *gorm.DB) *Repository {
|
|
return &Repository{db: db}
|
|
}
|
|
|
|
func (r *Repository) Create(room *BossRoom) error {
|
|
return r.db.Create(room).Error
|
|
}
|
|
|
|
func (r *Repository) Update(room *BossRoom) error {
|
|
return r.db.Save(room).Error
|
|
}
|
|
|
|
func (r *Repository) FindBySessionName(sessionName string) (*BossRoom, error) {
|
|
var room BossRoom
|
|
if err := r.db.Where("session_name = ?", sessionName).First(&room).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &room, nil
|
|
}
|
|
|
|
// FindBySessionNameForUpdate acquires a row-level lock (SELECT ... FOR UPDATE)
|
|
// to prevent concurrent state transitions.
|
|
func (r *Repository) FindBySessionNameForUpdate(sessionName string) (*BossRoom, error) {
|
|
var room BossRoom
|
|
if err := r.db.Clauses(clause.Locking{Strength: "UPDATE"}).Where("session_name = ?", sessionName).First(&room).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &room, nil
|
|
}
|
|
|
|
// Transaction wraps a function in a database transaction.
|
|
func (r *Repository) Transaction(fn func(txRepo *Repository) error) error {
|
|
return r.db.Transaction(func(tx *gorm.DB) error {
|
|
return fn(&Repository{db: tx})
|
|
})
|
|
}
|
|
|
|
// CountActiveByUsername checks if a player is already in an active boss raid.
|
|
func (r *Repository) CountActiveByUsername(username string) (int64, error) {
|
|
var count int64
|
|
// LIKE 특수문자 이스케이프
|
|
escaped := strings.NewReplacer("%", "\\%", "_", "\\_").Replace(username)
|
|
search := `"` + escaped + `"`
|
|
err := r.db.Model(&BossRoom{}).
|
|
Where("status IN ? AND players LIKE ?",
|
|
[]RoomStatus{StatusWaiting, StatusInProgress},
|
|
"%"+search+"%",
|
|
).Count(&count).Error
|
|
return count, err
|
|
}
|