handlers.Params gets an optional Fetcher, marked optional for fx. When the app provides one, the handlers pass it to the image service, whose Fetcher option already existed for tests, instead of letting it build its own from the config. pixad provides none, so production builds its fetcher from the config exactly as before. A new test builds the handlers in an fx app that provides no fetcher, as pixad does, and checks that an allowlisted address in blocked_networks is refused with 403, which only the dialer that refuses internal addresses does. The comment on imgcache.ServiceConfig.FetcherConfig now says that its AllowHTTP and MaxResponseSize apply even when a fetcher is given. Model: opus-5-5
62 lines
1.9 KiB
Go
62 lines
1.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"net/netip"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"go.uber.org/fx"
|
|
"go.uber.org/fx/fxtest"
|
|
|
|
"sneak.berlin/go/pixa/internal/config"
|
|
"sneak.berlin/go/pixa/internal/database"
|
|
"sneak.berlin/go/pixa/internal/globals"
|
|
"sneak.berlin/go/pixa/internal/healthcheck"
|
|
"sneak.berlin/go/pixa/internal/logger"
|
|
)
|
|
|
|
// TestHandlersBuildTheirOwnFetcherWhenNoneIsProvided builds the handlers as
|
|
// pixad does, in an fx app that provides no fetcher, and requests an image
|
|
// from 192.0.2.10, which is on the allowlist and in blocked_networks. The URL
|
|
// check accepts that address; only the dialer that refuses internal
|
|
// addresses checks blocked_networks, so the answer is 403 only if the
|
|
// fetcher the handlers build from the config connects with that dialer. Any
|
|
// other dialer would try to connect until the upstream fetch timeout, which
|
|
// is short so that the test then fails quickly.
|
|
func TestHandlersBuildTheirOwnFetcherWhenNoneIsProvided(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const host = "192.0.2.10"
|
|
|
|
stateDir := t.TempDir()
|
|
cfg := &config.Config{
|
|
SigningKey: testSigningKey,
|
|
StateDir: stateDir,
|
|
DBURL: "file:" + filepath.Join(stateDir, "state.sqlite3"),
|
|
AllowlistHosts: []string{host},
|
|
BlockedNetworks: []netip.Prefix{netip.MustParsePrefix("192.0.2.0/24")},
|
|
UpstreamFetchTimeout: 2 * time.Second,
|
|
// With no connection slots, the fetch would fail before dialing.
|
|
UpstreamConnections: config.DefaultUpstreamConnections,
|
|
}
|
|
|
|
var h *Handlers
|
|
|
|
app := fxtest.New(t,
|
|
fx.Supply(cfg),
|
|
fx.Provide(globals.New, logger.New, database.New, healthcheck.New, New),
|
|
fx.Populate(&h),
|
|
)
|
|
app.RequireStart()
|
|
t.Cleanup(app.RequireStop)
|
|
|
|
r := chi.NewRouter()
|
|
r.Get("/v1/image/*", h.HandleImage())
|
|
|
|
rec := sendGet(t, r, photoURL(host))
|
|
checkErrorBody(t, rec, http.StatusForbidden, "forbidden")
|
|
}
|