104 lines
3.0 KiB
Go
104 lines
3.0 KiB
Go
package transcodenode
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
)
|
|
|
|
type staticCatalogPaths struct {
|
|
active map[string]bool
|
|
err error
|
|
}
|
|
|
|
func (s staticCatalogPaths) IsActivePath(_ context.Context, path string) (bool, error) {
|
|
return s.active[path], s.err
|
|
}
|
|
|
|
func TestCatalogPathAuthorizerAllowsCataloguedRegularFilesAndSymlinks(t *testing.T) {
|
|
mediaPath := filepath.Join(t.TempDir(), "movie.mkv")
|
|
if err := os.WriteFile(mediaPath, []byte("media"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
target := filepath.Join(t.TempDir(), "outside.mkv")
|
|
if err := os.WriteFile(target, []byte("media"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
link := filepath.Join(t.TempDir(), "linked.mkv")
|
|
if err := os.Symlink(target, link); err != nil {
|
|
t.Skipf("symlinks not supported on this platform: %v", err)
|
|
}
|
|
authorizer := NewCatalogPathAuthorizer(staticCatalogPaths{active: map[string]bool{
|
|
mediaPath: true,
|
|
link: true,
|
|
}})
|
|
|
|
for _, path := range []string{mediaPath, link} {
|
|
allowed, err := authorizer.Allowed(context.Background(), path)
|
|
if err != nil || !allowed {
|
|
t.Fatalf("approved media path %q: allowed = %v, err = %v", path, allowed, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCatalogPathAuthorizerRejectsUnsafeOrUncataloguedInputs(t *testing.T) {
|
|
existingUncatalogued := filepath.Join(t.TempDir(), "outside.mkv")
|
|
if err := os.WriteFile(existingUncatalogued, []byte("media"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
missingCatalogued := filepath.Join(t.TempDir(), "missing.mkv")
|
|
directoryCatalogued := t.TempDir()
|
|
authorizer := NewCatalogPathAuthorizer(staticCatalogPaths{active: map[string]bool{
|
|
missingCatalogued: true,
|
|
directoryCatalogued: true,
|
|
}})
|
|
|
|
for _, candidate := range []string{
|
|
"relative/movie.mkv",
|
|
"http://example.test/movie.mkv",
|
|
"file:" + existingUncatalogued,
|
|
"concat:" + existingUncatalogued + "|" + existingUncatalogued,
|
|
existingUncatalogued,
|
|
missingCatalogued,
|
|
directoryCatalogued,
|
|
} {
|
|
allowed, err := authorizer.Allowed(context.Background(), candidate)
|
|
if err != nil {
|
|
t.Fatalf("candidate %q: %v", candidate, err)
|
|
}
|
|
if allowed {
|
|
t.Errorf("candidate %q was allowed", candidate)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCatalogPathAuthorizerPropagatesRepositoryErrors(t *testing.T) {
|
|
wantErr := errors.New("database unavailable")
|
|
authorizer := NewCatalogPathAuthorizer(staticCatalogPaths{err: wantErr})
|
|
allowed, err := authorizer.Allowed(context.Background(), "/media/movie.mkv")
|
|
if allowed || !errors.Is(err, wantErr) {
|
|
t.Fatalf("allowed = %v, err = %v", allowed, err)
|
|
}
|
|
}
|
|
|
|
func TestPathWithinRootRejectsSymlinkedOutputParent(t *testing.T) {
|
|
if runtime.GOOS == "windows" {
|
|
t.Skip("symlink semantics differ on Windows")
|
|
}
|
|
root := t.TempDir()
|
|
outside := t.TempDir()
|
|
linkedParent := filepath.Join(root, "linked")
|
|
if err := os.Symlink(outside, linkedParent); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if pathWithinRoot(root, filepath.Join(linkedParent, "artifact.mp4")) {
|
|
t.Fatal("output under symlinked escape was accepted")
|
|
}
|
|
if !pathWithinRoot(root, filepath.Join(root, "artifact.mp4")) {
|
|
t.Fatal("direct child output was rejected")
|
|
}
|
|
}
|