- 입력 검증 강화 (로그인/체인 핸들러 전체) - boss raid 비관적 잠금으로 동시성 문제 해결 - SSAFY 사용자명 sanitize + 트랜잭션 처리 - constant-time API 키 비교, 보안 헤더, graceful shutdown - 안전하지 않은 기본값 경고 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -313,21 +313,36 @@ func (s *Service) SSAFYLogin(code string) (accessToken, refreshToken string, use
|
||||
}
|
||||
|
||||
ssafyID := userInfo.UserID
|
||||
username := "ssafy_" + ssafyID
|
||||
user = &User{
|
||||
Username: username,
|
||||
PasswordHash: string(hash),
|
||||
Role: RoleUser,
|
||||
SsafyID: &ssafyID,
|
||||
// SSAFY ID에서 영문 소문자+숫자만 추출하여 안전한 username 생성
|
||||
safeID := sanitizeForUsername(ssafyID)
|
||||
if safeID == "" {
|
||||
safeID = hex.EncodeToString(randomBytes[:8])
|
||||
}
|
||||
if err := s.repo.Create(user); err != nil {
|
||||
username := "ssafy_" + safeID
|
||||
if len(username) > 50 {
|
||||
username = username[:50]
|
||||
}
|
||||
|
||||
var newUserID uint
|
||||
err = s.repo.Transaction(func(txRepo *Repository) error {
|
||||
user = &User{
|
||||
Username: username,
|
||||
PasswordHash: string(hash),
|
||||
Role: RoleUser,
|
||||
SsafyID: &ssafyID,
|
||||
}
|
||||
return txRepo.Create(user)
|
||||
})
|
||||
if err != nil {
|
||||
return "", "", nil, fmt.Errorf("계정 생성 실패: %v", err)
|
||||
}
|
||||
newUserID = user.ID
|
||||
|
||||
if s.walletCreator != nil {
|
||||
if err := s.walletCreator(user.ID); err != nil {
|
||||
log.Printf("wallet creation failed for SSAFY user %d: %v — rolling back", user.ID, err)
|
||||
if delErr := s.repo.Delete(user.ID); delErr != nil {
|
||||
log.Printf("WARNING: rollback delete also failed for SSAFY user %d: %v", user.ID, delErr)
|
||||
if err := s.walletCreator(newUserID); err != nil {
|
||||
log.Printf("wallet creation failed for SSAFY user %d: %v — rolling back", newUserID, err)
|
||||
if delErr := s.repo.Delete(newUserID); delErr != nil {
|
||||
log.Printf("WARNING: rollback delete also failed for SSAFY user %d: %v", newUserID, delErr)
|
||||
}
|
||||
return "", "", nil, fmt.Errorf("계정 초기화에 실패했습니다. 잠시 후 다시 시도해주세요")
|
||||
}
|
||||
@@ -373,6 +388,17 @@ func (s *Service) VerifyToken(tokenStr string) (string, error) {
|
||||
return claims.Username, nil
|
||||
}
|
||||
|
||||
// sanitizeForUsername strips characters that are not [a-z0-9_-].
|
||||
func sanitizeForUsername(s string) string {
|
||||
var b strings.Builder
|
||||
for _, c := range strings.ToLower(s) {
|
||||
if (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '-' {
|
||||
b.WriteRune(c)
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (s *Service) EnsureAdmin(username, password string) error {
|
||||
if _, err := s.repo.FindByUsername(username); err == nil {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user