commit ff10334a23bdf31cb936764e2ee8877a70d85bb1 Author: Domenico Testa Date: Wed May 6 00:11:40 2026 +0200 Initial revision diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a567309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env +/pz8-relay diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..81b5692 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM golang:1.26.2 AS build + +WORKDIR /code + +COPY go.mod ./ +RUN go mod download + +COPY . . +RUN CGO_ENABLED=0 go build -v -ldflags="-s -w" -o /usr/bin/app ./... + +FROM gcr.io/distroless/static:nonroot +EXPOSE 8080 +COPY --from=build /usr/bin/app /app +ENTRYPOINT ["/app"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..d3decd4 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# PZ8 relay + +A simple utility for my iptv needs. +Upstream links change frequently and need to be updated on devices, which is annoying. +This is a simple web service that will accept an HTTP request with basic authentication +and will act as a proxy against a configured HTTP link. + +The proxied URL is configured via an environment variable. diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..8886238 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module ktmrt.org/domenico/pz8-relay + +go 1.26.2 diff --git a/main.go b/main.go new file mode 100644 index 0000000..be0d755 --- /dev/null +++ b/main.go @@ -0,0 +1,54 @@ +package main + +import ( + "crypto/subtle" + "log" + "net/http" + "net/http/httputil" + "net/url" + "os" +) + +func main() { + target := mustEnv("PZ8_RELAY_TARGET_URL") + username := mustEnv("PZ8_RELAY_USERNAME") + password := mustEnv("PZ8_RELAY_PASSWORD") + + addr := os.Getenv("PZ8_RELAY_LISTEN_ADDR") + if addr == "" { + addr = ":8080" + } + + targetURL, err := url.Parse(target) + if err != nil { + log.Fatalf("invalid PZ8_RELAY_TARGET_URL: %v", err) + } + + proxy := &httputil.ReverseProxy{ + Rewrite: func(preq *httputil.ProxyRequest) { + preq.SetURL(targetURL) + }, + } + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + u, p, ok := r.BasicAuth() + if !ok || subtle.ConstantTimeCompare([]byte(u), []byte(username)) != 1 || + subtle.ConstantTimeCompare([]byte(p), []byte(password)) != 1 { + w.Header().Set("WWW-Authenticate", `Basic realm="pz8-relay"`) + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + proxy.ServeHTTP(w, r) + }) + + log.Printf("pz8-relay listening on %s, proxying to %s", addr, targetURL.Redacted()) + log.Fatal(http.ListenAndServe(addr, nil)) +} + +func mustEnv(key string) string { + v := os.Getenv(key) + if v == "" { + log.Fatalf("missing required env var: %s", key) + } + return v +}