veza/veza-backend-api/internal/services/track_download_license.go
senke 563a1c9001 fix(security): verify track access before download (A04)
- Add TrackDownloadLicenseChecker to verify paid track download rights
- Check marketplace license when track is sold as product and user is not owner
- Return 403 with 'purchase required' message when license missing
2026-02-16 10:23:41 +01:00

58 lines
2.1 KiB
Go

package services
import (
"context"
"github.com/google/uuid"
"go.uber.org/zap"
"gorm.io/gorm"
)
// TrackDownloadLicenseChecker verifies if a user has the right to download a track
// (ownership, public track, share token, or valid marketplace license).
type TrackDownloadLicenseChecker interface {
// HasPaidTrackDownloadRight returns true if the track is sold as a product
// and the user has a valid license to download it. Returns false if track
// is not a paid product or user has no license (caller should use other checks).
HasPaidTrackDownloadRight(ctx context.Context, userID uuid.UUID, trackID uuid.UUID) (bool, error)
// IsTrackSoldAsProduct returns true if the track is linked to an active marketplace product.
IsTrackSoldAsProduct(ctx context.Context, trackID uuid.UUID) (bool, error)
}
// DBTrackDownloadLicenseChecker implements TrackDownloadLicenseChecker using the database.
type DBTrackDownloadLicenseChecker struct {
db *gorm.DB
logger *zap.Logger
}
// NewDBTrackDownloadLicenseChecker creates a new checker.
func NewDBTrackDownloadLicenseChecker(db *gorm.DB, logger *zap.Logger) *DBTrackDownloadLicenseChecker {
return &DBTrackDownloadLicenseChecker{db: db, logger: logger}
}
// IsTrackSoldAsProduct returns true if the track is linked to an active product.
func (c *DBTrackDownloadLicenseChecker) IsTrackSoldAsProduct(ctx context.Context, trackID uuid.UUID) (bool, error) {
var count int64
err := c.db.WithContext(ctx).Table("products").
Where("track_id = ? AND product_type = ? AND status = ?", trackID, "track", "active").
Count(&count).Error
if err != nil {
return false, err
}
return count > 0, nil
}
// HasPaidTrackDownloadRight returns true if the user has a valid license for the track.
func (c *DBTrackDownloadLicenseChecker) HasPaidTrackDownloadRight(ctx context.Context, userID uuid.UUID, trackID uuid.UUID) (bool, error) {
if userID == uuid.Nil {
return false, nil
}
var count int64
err := c.db.WithContext(ctx).Table("licenses").
Where("buyer_id = ? AND track_id = ? AND downloads_left > 0", userID, trackID).
Count(&count).Error
if err != nil {
return false, err
}
return count > 0, nil
}