Compare commits

...

2 commits

Author SHA1 Message Date
Viktor Varland 1be09be9db
chore: queue-file path to container
Some checks are pending
build / build (push) Waiting to run
2025-09-30 12:01:23 +02:00
Viktor Varland 9d9f8ae0a9
feat: add authfile for secret management 2025-09-30 11:56:22 +02:00
6 changed files with 33 additions and 6 deletions

View file

@ -22,4 +22,4 @@ Commits follow a Conventional Commits prefix (`fix:`, `refactor:`) in imperative
Document expected locations for `yt-dlp`, cookies, and OPML files when altering defaults. If a change requires bgutil or other external services, provide startup commands and update the sample `config.json`. Ensure new options degrade gracefully for existing configs and call out migration steps in the PR description.
## HTTP API
Enable the intake server with `http_api.enable` (binds to `127.0.0.1:4416`). Set `auth_token` for bearer auth and `queue_file` to persist pending jobs. Example: `curl -H "Authorization: Bearer $TOKEN" -d '{"url":"https://youtu.be/ID","out_dir":"Channel"}' http://127.0.0.1:4416/v1/videos`. Inspect the queue with `curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:4416/status`.
Enable the intake server with `http_api.enable` (binds to `127.0.0.1:4416`). Set `auth_token` or point `auth_token_file` at a mounted secret, and use `queue_file` to persist pending jobs. Example: `curl -H "Authorization: Bearer $TOKEN" -d '{"url":"https://youtu.be/ID","out_dir":"Channel"}' http://127.0.0.1:4416/v1/videos`. Inspect the queue with `curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:4416/status`.

View file

@ -51,6 +51,12 @@ COPY <<-EOT /data/config.json
"daemon": true,
"dry_run": false,
"out_dir": "/data/vids",
"http_api": {
"enable": true,
"listen": "127.0.0.1:4416",
"auth_token_file": "/run/secrets/subsyt-token",
"queue_file": "/data/api-queue.json"
},
"provider": {
"youtube": {
"verbose": false,

View file

@ -273,7 +273,7 @@ OPML export.
"http_api": {
"enable": true,
"listen": "127.0.0.1:4416",
"auth_token": "super-secret",
"auth_token_file": "/run/secrets/subsyt-token",
"queue_file": "./tmp/api-queue.json"
}
}
@ -283,7 +283,7 @@ Submit new downloads with bearer authentication:
```
curl \
-H "Authorization: Bearer super-secret" \
-H "Authorization: Bearer $(cat /run/secrets/subsyt-token)" \
-H "Content-Type: application/json" \
--data '{"url":"https://youtu.be/VIDEO","out_dir":"Channel"}' \
http://127.0.0.1:4416/v1/videos

View file

@ -25,6 +25,7 @@ type Http_api struct {
Enable bool
Listen string
Auth_token string
Auth_token_file string
Queue_file string
}

View file

@ -7,6 +7,7 @@ import (
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"time"
@ -22,15 +23,28 @@ type Server struct {
defaultOutDir string
httpServer *http.Server
shutdownSignal chan struct{}
authToken string
}
func NewServer(cfg config.Http_api, defaultOutDir string, queue *Queue) *Server {
return &Server{
srv := &Server{
cfg: cfg,
queue: queue,
defaultOutDir: defaultOutDir,
shutdownSignal: make(chan struct{}),
}
srv.authToken = strings.TrimSpace(cfg.Auth_token)
if srv.authToken == "" && cfg.Auth_token_file != "" {
if token, err := os.ReadFile(cfg.Auth_token_file); err == nil {
srv.authToken = strings.TrimSpace(string(token))
} else {
log.Printf("failed to read auth token file %s: %v", cfg.Auth_token_file, err)
}
}
return srv
}
func (s *Server) Start(ctx context.Context) error {
@ -156,7 +170,7 @@ func (s *Server) handleStatus(w http.ResponseWriter, r *http.Request) {
}
func (s *Server) authorize(header string) bool {
required := strings.TrimSpace(s.cfg.Auth_token)
required := s.authToken
if required == "" {
return true
}

View file

@ -87,7 +87,13 @@ func TestHandleStatus(t *testing.T) {
t.Fatalf("new queue: %v", err)
}
s := NewServer(config.Http_api{Auth_token: "secret"}, "/videos", queue)
tmp := t.TempDir()
tokenPath := filepath.Join(tmp, "token.txt")
if err := os.WriteFile(tokenPath, []byte("secret"), 0o600); err != nil {
t.Fatalf("write token file: %v", err)
}
s := NewServer(config.Http_api{Auth_token_file: tokenPath}, "/videos", queue)
req := httptest.NewRequest(http.MethodGet, "/status", nil)
rec := httptest.NewRecorder()