diff --git a/README.md b/README.md index 2286084..cc1a877 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Image-heavy web applications need a fast, caching reverse proxy that can resize and transcode images on the fly. pixa fills that role as a single, self-contained binary with no external runtime dependencies beyond libvips. It supports HMAC-SHA256 signed URLs with expiration to -prevent abuse, and whitelisted source hosts for open access. +prevent abuse, and allowlisted source hosts for open access. ## Design @@ -61,7 +61,7 @@ Images are only fetched from origins using TLS with valid certificates. ### Source Hosts -Source hosts may be whitelisted in the configuration. Non-whitelisted +Source hosts may be allowlisted in the configuration. Non-allowlisted hosts require an HMAC-SHA256 signature. #### Signature Specification @@ -99,7 +99,7 @@ expiration 1704067200: 4. URL: `/v1/image/cdn.example.com/photos/cat.jpg/800x600.webp?sig=&exp=1704067200` -**Whitelist patterns:** +**Allowlist patterns:** - **Exact match**: `cdn.example.com` — matches only that host - **Suffix match**: `.example.com` — matches `cdn.example.com`, @@ -110,7 +110,7 @@ expiration 1704067200: Configured via YAML file (`--config`). Key settings: - `access_control_allow_origin` — CORS origin -- `source_host_whitelist` — list of allowed upstream hosts +- `allowlist_hosts` — list of allowed upstream hosts - `upstream_fetch_timeout` — timeout for origin requests - `upstream_max_response_size` — max origin response size - `downstream_timeout` — client response timeout diff --git a/config.example.yml b/config.example.yml index 1660cb4..d4295f6 100644 --- a/config.example.yml +++ b/config.example.yml @@ -9,13 +9,13 @@ maintenance_mode: false state_dir: ./data # Image proxy settings -# HMAC signing key for URL signatures (leave empty to require whitelist for all requests) +# HMAC signing key for URL signatures (leave empty to require allowlist for all requests) # Generate with: openssl rand -base64 32 signing_key: "CHANGE_ME_generate_with_openssl_rand_base64_32" # Hosts that don't require signatures # Use "." prefix for wildcard subdomain matching (e.g., ".example.com" matches "cdn.example.com") -whitelist_hosts: +allowlist_hosts: - s3.sneak.cloud - static.sneak.cloud - sneak.berlin diff --git a/internal/config/config.go b/internal/config/config.go index 3eb1bc2..a2c3778 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -41,7 +41,7 @@ type Config struct { // Image proxy settings SigningKey string // HMAC signing key for URL signatures - WhitelistHosts []string // Hosts that don't require signatures + AllowlistHosts []string // Hosts that don't require signatures AllowHTTP bool // Allow non-TLS upstream (testing only) UpstreamConnectionsPerHost int // Max concurrent connections per upstream host } @@ -69,7 +69,7 @@ func New(_ fx.Lifecycle, params Params) (*Config, error) { MetricsUsername: getString(sc, "metrics.username", ""), MetricsPassword: getString(sc, "metrics.password", ""), SigningKey: getString(sc, "signing_key", ""), - WhitelistHosts: getStringSlice(sc, "whitelist_hosts"), + AllowlistHosts: getStringSlice(sc, "allowlist_hosts"), AllowHTTP: getBool(sc, "allow_http", false), UpstreamConnectionsPerHost: getInt(sc, "upstream_connections_per_host", DefaultUpstreamConnectionsPerHost), } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index c3c7f7c..f0d927e 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -14,7 +14,7 @@ func TestGetStringSlice_YAMLList(t *testing.T) { configPath := filepath.Join(tmpDir, "config.yml") yamlContent := ` -whitelist_hosts: +allowlist_hosts: - static.sneak.cloud - sneak.berlin - s3.sneak.cloud @@ -31,7 +31,7 @@ whitelist_hosts: } // Test that getStringSlice correctly parses YAML list - hosts := getStringSlice(sc, "whitelist_hosts") + hosts := getStringSlice(sc, "allowlist_hosts") if len(hosts) != 3 { t.Errorf("expected 3 hosts, got %d: %v", len(hosts), hosts) @@ -54,7 +54,7 @@ func TestGetStringSlice_CommaSeparated(t *testing.T) { tmpDir := t.TempDir() configPath := filepath.Join(tmpDir, "config.yml") - yamlContent := `whitelist_hosts: "static.sneak.cloud, sneak.berlin, s3.sneak.cloud"` + yamlContent := `allowlist_hosts: "static.sneak.cloud, sneak.berlin, s3.sneak.cloud"` err := os.WriteFile(configPath, []byte(yamlContent), 0644) if err != nil { @@ -66,7 +66,7 @@ func TestGetStringSlice_CommaSeparated(t *testing.T) { t.Fatalf("failed to load config: %v", err) } - hosts := getStringSlice(sc, "whitelist_hosts") + hosts := getStringSlice(sc, "allowlist_hosts") if len(hosts) != 3 { t.Errorf("expected 3 hosts, got %d: %v", len(hosts), hosts) @@ -100,7 +100,7 @@ func TestGetStringSlice_Empty(t *testing.T) { t.Fatalf("failed to load config: %v", err) } - hosts := getStringSlice(sc, "whitelist_hosts") + hosts := getStringSlice(sc, "allowlist_hosts") if hosts != nil && len(hosts) != 0 { t.Errorf("expected nil or empty slice, got %v", hosts) diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index c9796f5..e243c18 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -84,7 +84,7 @@ func (s *Handlers) initImageService() error { Cache: cache, FetcherConfig: fetcherCfg, SigningKey: s.config.SigningKey, - Allowlist: s.config.WhitelistHosts, + Allowlist: s.config.AllowlistHosts, Logger: s.log, }) if err != nil { diff --git a/scripts/manual-test.sh b/scripts/manual-test.sh index 514f378..b0118a3 100755 --- a/scripts/manual-test.sh +++ b/scripts/manual-test.sh @@ -97,8 +97,8 @@ else fail "No encrypted URL to test" fi -# Test 7: Fetch image via whitelisted host (direct proxy) -echo "--- Test 7: Fetch image via direct proxy (whitelisted host) ---" +# Test 7: Fetch image via allowlisted host (direct proxy) +echo "--- Test 7: Fetch image via direct proxy (allowlisted host) ---" # URL format: /v1/image///. PROXY_PATH="/v1/image/s3.sneak.cloud/sneak-public/2021/2021-04-18.untitled.a7r4.07723.jpg/400x300.jpeg" HTTP_CODE=$(curl -sf -o /dev/null -w "%{http_code}" "$BASE_URL$PROXY_PATH")