package repository import ( "database/sql" "errors" "time" ) var ErrRefreshTokenInvalid = errors.New("refresh token invalid") type RefreshTokenRepository struct { DB *sql.DB } func NewRefreshTokenRepository(db *sql.DB) *RefreshTokenRepository { return &RefreshTokenRepository{DB: db} } // Yeni refresh (HASH saklanır) func (r *RefreshTokenRepository) IssueRefreshToken( mkUserID int64, tokenHash string, expiresAt time.Time, ) error { _, err := r.DB.Exec(` INSERT INTO mk_refresh_tokens (mk_user_id, token_hash, expires_at) VALUES ($1,$2,$3) `, mkUserID, tokenHash, expiresAt) return err } // Tek refresh’i revoke et (rotation / logout) func (r *RefreshTokenRepository) RevokeByHash(hash string) error { _, err := r.DB.Exec(` UPDATE mk_refresh_tokens SET revoked_at = now() WHERE token_hash = $1 AND revoked_at IS NULL `, hash) return err } // Kullanıcının tüm refresh’lerini revoke et (logout-all / password change) func (r *RefreshTokenRepository) RevokeAllForUser(mkUserID int64) error { _, err := r.DB.Exec(` UPDATE mk_refresh_tokens SET revoked_at = now() WHERE mk_user_id = $1 AND revoked_at IS NULL `, mkUserID) return err } // Geçerli refresh’i tüket (validate + rotate) func (r *RefreshTokenRepository) ConsumeValid(tokenHash string) (int64, error) { var mkUserID int64 err := r.DB.QueryRow(` SELECT mk_user_id FROM mk_refresh_tokens WHERE token_hash = $1 AND revoked_at IS NULL AND expires_at > now() `, tokenHash).Scan(&mkUserID) if err != nil { if err == sql.ErrNoRows { return 0, ErrRefreshTokenInvalid } return 0, err } // tek kullanımlık: eskiyi revoke et _, _ = r.DB.Exec(` UPDATE mk_refresh_tokens SET revoked_at = now() WHERE token_hash = $1 `, tokenHash) return mkUserID, nil }