mirror of
https://github.com/stashapp/stash.git
synced 2026-04-21 06:22:29 +02:00
HMAC-signed URLs allow authenticated streaming to devices that cannot pass cookies (AirPlay, Chromecast). Signing is scoped to scene stream using a prefix-based approach so one signature covers all derivative segment URLs. Credentialid hides username from public network. When credentials are disabled, signing is bypassed entirely. API key takes precedence over signed params when both are present.
62 lines
1.5 KiB
Go
62 lines
1.5 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/stashapp/stash/internal/api/urlbuilders"
|
|
"github.com/stashapp/stash/internal/manager"
|
|
"github.com/stashapp/stash/pkg/models"
|
|
"github.com/stashapp/stash/pkg/session"
|
|
"github.com/stashapp/stash/pkg/signedurl"
|
|
)
|
|
|
|
func (r *queryResolver) SceneStreams(ctx context.Context, id *string) ([]*manager.SceneStreamEndpoint, error) {
|
|
sceneID, err := strconv.Atoi(*id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// find the scene
|
|
var scene *models.Scene
|
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
|
var err error
|
|
scene, err = r.repository.Scene.Find(ctx, sceneID)
|
|
|
|
if scene != nil {
|
|
err = scene.LoadPrimaryFile(ctx, r.repository.File)
|
|
}
|
|
|
|
return err
|
|
}); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if scene == nil {
|
|
return nil, fmt.Errorf("scene with id %d not found", sceneID)
|
|
}
|
|
|
|
config := manager.GetInstance().Config
|
|
|
|
baseURL, _ := ctx.Value(BaseURLCtxKey).(string)
|
|
builder := urlbuilders.NewSceneURLBuilder(baseURL, scene)
|
|
|
|
streamURL := builder.GetStreamURL("")
|
|
if config.HasCredentials() {
|
|
userID := session.GetCurrentUserID(ctx)
|
|
if userID == nil {
|
|
return nil, fmt.Errorf("user ID not found")
|
|
}
|
|
streamURL.RawQuery = signedParams(config, *userID, signedurl.DerivePrefix(streamURL.Path)).Encode()
|
|
} else {
|
|
apiKey := config.GetAPIKey()
|
|
if apiKey != "" {
|
|
v := streamURL.Query()
|
|
v.Set("apikey", apiKey)
|
|
streamURL.RawQuery = v.Encode()
|
|
}
|
|
}
|
|
|
|
return manager.GetSceneStreamPaths(scene, streamURL, config.GetMaxStreamingTranscodeSize())
|
|
}
|