harden search parsing and qobuz refresh validation

This commit is contained in:
2026-04-21 19:04:33 +02:00
parent de4e561377
commit c67be72869
5 changed files with 86 additions and 2 deletions

View File

@@ -13,6 +13,7 @@ import (
"net/url"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"strconv"
@@ -1995,6 +1996,12 @@ func parseSearchArgs(args []string, defaultLimit int) (searchOptions, error) {
first := false
outputFile := ""
for i := 0; i < len(args); i++ {
if args[i] == "--" {
if i+1 < len(args) {
parts = append(parts, args[i+1:]...)
}
break
}
switch args[i] {
case "--force", "--ignore-db":
ignoreDB = true
@@ -2010,6 +2017,9 @@ func parseSearchArgs(args []string, defaultLimit int) (searchOptions, error) {
return searchOptions{}, fmt.Errorf("--output-file requires a path")
}
outputFile = strings.TrimSpace(args[i+1])
if outputFile == "" {
return searchOptions{}, fmt.Errorf("--output-file requires a non-empty path")
}
i++
continue
case "--num-results":
@@ -2036,6 +2046,9 @@ func parseSearchArgs(args []string, defaultLimit int) (searchOptions, error) {
i++
continue
}
if strings.HasPrefix(args[i], "-") {
return searchOptions{}, fmt.Errorf("unknown option %q", args[i])
}
parts = append(parts, args[i])
}
return searchOptions{
@@ -2196,6 +2209,12 @@ func writeSearchResultsToFile(source, mediaType string, results []searchResult,
if err != nil {
return err
}
dir := filepath.Dir(path)
if dir != "" && dir != "." {
if err = os.MkdirAll(dir, 0o755); err != nil {
return err
}
}
return os.WriteFile(path, b, 0o644)
}

View File

@@ -2,6 +2,9 @@ package main
import (
"errors"
"os"
"path/filepath"
"strings"
"testing"
)
@@ -198,6 +201,38 @@ func TestParseSearchArgsAllowsFirstAndOutputFileButCallerCanReject(t *testing.T)
}
}
func TestParseSearchArgsRejectsUnknownOption(t *testing.T) {
_, err := parseSearchArgs([]string{"query", "--bogus"}, 20)
if err == nil || !strings.Contains(err.Error(), "unknown option") {
t.Fatalf("expected unknown option error, got %v", err)
}
}
func TestParseSearchArgsSupportsDoubleDashTerminator(t *testing.T) {
opts, err := parseSearchArgs([]string{"--limit", "10", "--", "--weird", "track"}, 20)
if err != nil {
t.Fatalf("parseSearchArgs() error = %v", err)
}
if opts.limit != 10 {
t.Fatalf("limit = %d, want 10", opts.limit)
}
if opts.query != "--weird track" {
t.Fatalf("query = %q, want %q", opts.query, "--weird track")
}
}
func TestWriteSearchResultsToFileCreatesParentDirectory(t *testing.T) {
tmp := t.TempDir()
out := filepath.Join(tmp, "nested", "search", "results.json")
results := []searchResult{{ID: "1", Title: "Dreams"}}
if err := writeSearchResultsToFile("qobuz", "track", results, out); err != nil {
t.Fatalf("writeSearchResultsToFile() error = %v", err)
}
if _, err := os.Stat(out); err != nil {
t.Fatalf("expected output file, stat error = %v", err)
}
}
func TestErrorWithActionableHintForSSL(t *testing.T) {
err := errors.New("x509: certificate signed by unknown authority")
msg := errorWithActionableHint(err, globalOptions{})