71 lines
1.9 KiB
Go
71 lines
1.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/Silo-Server/silo-server/internal/catalog"
|
|
"github.com/Silo-Server/silo-server/internal/models"
|
|
"github.com/Silo-Server/silo-server/internal/scanner"
|
|
)
|
|
|
|
// MediaFileAuthorizer validates that the authenticated user can access a media file.
|
|
type MediaFileAuthorizer struct {
|
|
FileResolver FilePathResolver
|
|
ItemAccess PlaybackItemAccessChecker
|
|
EpisodeLookup PlaybackEpisodeLookup
|
|
}
|
|
|
|
// Authorize returns the media file when the caller may access it, or catalog.ErrItemNotFound.
|
|
func (a *MediaFileAuthorizer) Authorize(r *http.Request, fileID int) (*models.MediaFile, error) {
|
|
if a == nil || a.FileResolver == nil || a.ItemAccess == nil {
|
|
return nil, fmt.Errorf("media file authorization dependencies not configured")
|
|
}
|
|
|
|
file, err := a.FileResolver.GetByID(r.Context(), fileID)
|
|
if err != nil {
|
|
return nil, mapMediaFileLookupError(err)
|
|
}
|
|
if file == nil || file.MissingSince != nil {
|
|
return nil, catalog.ErrItemNotFound
|
|
}
|
|
|
|
filter := requestAccessFilter(r)
|
|
switch {
|
|
case file.EpisodeID != "":
|
|
if a.EpisodeLookup == nil {
|
|
return nil, fmt.Errorf("episode lookup not configured")
|
|
}
|
|
episode, err := a.EpisodeLookup.GetByID(r.Context(), file.EpisodeID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if episode == nil {
|
|
return nil, catalog.ErrEpisodeNotFound
|
|
}
|
|
if err := a.ItemAccess.EnsureAccessible(r.Context(), episode.SeriesID, filter); err != nil {
|
|
return nil, err
|
|
}
|
|
case file.ContentID != "":
|
|
if err := a.ItemAccess.EnsureAccessible(r.Context(), file.ContentID, filter); err != nil {
|
|
return nil, err
|
|
}
|
|
default:
|
|
return nil, catalog.ErrItemNotFound
|
|
}
|
|
|
|
if !catalog.FileAllowedByAccess(file, filter) {
|
|
return nil, catalog.ErrItemNotFound
|
|
}
|
|
|
|
return file, nil
|
|
}
|
|
|
|
func mapMediaFileLookupError(err error) error {
|
|
if errors.Is(err, scanner.ErrFileNotFound) {
|
|
return catalog.ErrItemNotFound
|
|
}
|
|
return err
|
|
}
|