test: add proxy target rejection tests
This commit is contained in:
78
internal/playback/handler/proxy_target_test.go
Normal file
78
internal/playback/handler/proxy_target_test.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"mal/internal/domain"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type proxyTargetPlaybackService struct {
|
||||||
|
targetURL string
|
||||||
|
referer string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s proxyTargetPlaybackService) BuildWatchData(context.Context, int, []string, string, string, string) (domain.WatchPageData, error) {
|
||||||
|
return domain.WatchPageData{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s proxyTargetPlaybackService) SaveProgress(context.Context, string, int64, int, float64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s proxyTargetPlaybackService) CompleteAnime(context.Context, string, int64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s proxyTargetPlaybackService) SignProxyToken(string, string, string) (string, error) {
|
||||||
|
return "token", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s proxyTargetPlaybackService) ResolveProxyToken(string, string) (string, string, error) {
|
||||||
|
return s.targetURL, s.referer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s proxyTargetPlaybackService) UpsertSkipSegmentOverride(context.Context, string, int64, int, string, float64, float64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type recordingRoundTripper struct {
|
||||||
|
called bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt *recordingRoundTripper) RoundTrip(*http.Request) (*http.Response, error) {
|
||||||
|
rt.called = true
|
||||||
|
return &http.Response{
|
||||||
|
StatusCode: http.StatusOK,
|
||||||
|
Header: make(http.Header),
|
||||||
|
Body: io.NopCloser(strings.NewReader("WEBVTT\n")),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleProxySubtitleRejectsUnsafeTargetBeforeFetch(t *testing.T) {
|
||||||
|
rt := &recordingRoundTripper{}
|
||||||
|
h := &PlaybackHandler{
|
||||||
|
svc: proxyTargetPlaybackService{targetURL: "http://127.0.0.1/subtitle.vtt"},
|
||||||
|
proxyClient: &http.Client{Transport: rt},
|
||||||
|
subtitleCache: newSubtitleCache(0, 1),
|
||||||
|
}
|
||||||
|
|
||||||
|
req := httptest.NewRequestWithContext(context.Background(), http.MethodGet, "/watch/proxy/subtitle?token=token", nil)
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
router := gin.New()
|
||||||
|
router.GET("/watch/proxy/subtitle", h.HandleProxySubtitle)
|
||||||
|
router.ServeHTTP(rec, req)
|
||||||
|
|
||||||
|
if rec.Code != http.StatusBadGateway {
|
||||||
|
t.Fatalf("status = %d, want %d", rec.Code, http.StatusBadGateway)
|
||||||
|
}
|
||||||
|
if rt.called {
|
||||||
|
t.Fatal("proxy client was called for unsafe target")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -189,6 +189,33 @@ func TestPlaybackServiceProxyTokenDisabled(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPlaybackServiceSignProxyTokenRejectsUnsafeTargets(t *testing.T) {
|
||||||
|
svc := &playbackService{proxyTokenKey: "secret", proxyTokens: newProxyTokenStore()}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
targetURL string
|
||||||
|
}{
|
||||||
|
{name: "loopback ipv4", targetURL: "http://127.0.0.1/video.m3u8"},
|
||||||
|
{name: "private ipv4", targetURL: "https://10.0.0.4/segment.ts"},
|
||||||
|
{name: "loopback ipv6", targetURL: "http://[::1]/subtitle.vtt"},
|
||||||
|
{name: "unsupported scheme", targetURL: "file:///tmp/video.m3u8"},
|
||||||
|
{name: "missing host", targetURL: "https:///segment.ts"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
token, err := svc.SignProxyToken(tt.targetURL, "", "stream")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("SignProxyToken(%q) error = nil, token = %q", tt.targetURL, token)
|
||||||
|
}
|
||||||
|
if token != "" {
|
||||||
|
t.Fatalf("SignProxyToken(%q) token = %q, want empty", tt.targetURL, token)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type fakePlaybackRepository struct {
|
type fakePlaybackRepository struct {
|
||||||
inTxCalled bool
|
inTxCalled bool
|
||||||
getAnimeErr error
|
getAnimeErr error
|
||||||
|
|||||||
Reference in New Issue
Block a user