Ctrl K
ComunidadGuías…

pkg/safehttp/client_test.go

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package safehttp

import (
	"testing"

	build "github.com/cozy/cozy-stack/pkg/config"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestDefaultClient(t *testing.T) {
	build.BuildMode = build.ModeProd

	res, err := DefaultClient.Get("https://github.com/")
	require.NoError(t, err)
	defer res.Body.Close()

	_, err = DefaultClient.Get("http://192.168.0.1/")
	require.Error(t, err)
	assert.Contains(t, err.Error(), "is not a public IP address")

	_, err = DefaultClient.Get("http://1.2.3.4:5984/")
	require.Error(t, err)
	assert.Contains(t, err.Error(), "is not a safe port")
}

func TestSetTrustedPrivateNetworks(t *testing.T) {
	t.Run("invalid CIDR returns error", func(t *testing.T) {
		err := SetTrustedPrivateNetworks([]string{"not-a-cidr"})
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "invalid trusted private network CIDR")
	})

	t.Run("valid CIDRs are accepted", func(t *testing.T) {
		err := SetTrustedPrivateNetworks([]string{"10.0.0.0/8", "192.168.0.0/16"})
		assert.NoError(t, err)
		t.Cleanup(resetTrustedNetworks)
	})

	t.Run("invalid CIDR does not change existing allowlist", func(t *testing.T) {
		err := SetTrustedPrivateNetworks([]string{"10.0.0.0/8"})
		require.NoError(t, err)
		require.Len(t, loadTrustedNetworks(), 1)

		err = SetTrustedPrivateNetworks([]string{"bad"})
		require.Error(t, err)
		// The previous valid config is still in place.
		assert.Len(t, loadTrustedNetworks(), 1)
		t.Cleanup(resetTrustedNetworks)
	})

	t.Run("empty list clears allowlist", func(t *testing.T) {
		err := SetTrustedPrivateNetworks([]string{"10.0.0.0/8"})
		require.NoError(t, err)

		err = SetTrustedPrivateNetworks([]string{})
		require.NoError(t, err)
		assert.Empty(t, loadTrustedNetworks())
	})
}

func resetTrustedNetworks() {
	_ = SetTrustedPrivateNetworks(nil)
}

func TestSafeControlTransitionAddresses(t *testing.T) {
	build.BuildMode = build.ModeProd
	t.Cleanup(resetTrustedNetworks)
	require.NoError(t, SetTrustedPrivateNetworks([]string{"::/0"}))
	for _, host := range []string{
		"64:ff9b::a9fe:a9fe", "64:ff9b::7f00:1", "64:ff9b::a00:1",
		"64:ff9b:1::a9fe:a9fe", "64:ff9b:1:1234::1",
		"2002:c0a8:101::1", "2001:0:4136:e378:8000:63bf:3fff:fdd2",
	} {
		t.Run(host, func(t *testing.T) {
			assert.Error(t, safeControl("tcp6", "["+host+"]:80", nil))
		})
	}
	for _, host := range []string{"2606:4700:4700::1111", "2001:4860:4860::8888", "64:ff9b:2::1", "64:ff9b::808:808"} {
		assert.NoError(t, safeControl("tcp6", "["+host+"]:443", nil), host)
	}
	assert.Error(t, safeControl("tcp6", "[64:ff9b::808:808]:8080", nil))
}

func TestSafeControl(t *testing.T) {
	build.BuildMode = build.ModeProd
	t.Cleanup(resetTrustedNetworks)

	t.Run("private IP blocked by default", func(t *testing.T) {
		err := safeControl("tcp4", "192.168.1.1:80", nil)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "is not a public IP address")
	})

	t.Run("loopback blocked by default", func(t *testing.T) {
		err := safeControl("tcp4", "127.0.0.1:80", nil)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "is not a public IP address")
	})

	t.Run("private IP allowed when inside configured CIDR", func(t *testing.T) {
		require.NoError(t, SetTrustedPrivateNetworks([]string{"192.168.0.0/16"}))
		err := safeControl("tcp4", "192.168.1.1:80", nil)
		assert.NoError(t, err)
	})

	t.Run("private IP on non-standard port allowed when inside configured CIDR", func(t *testing.T) {
		require.NoError(t, SetTrustedPrivateNetworks([]string{"10.0.0.0/8"}))
		err := safeControl("tcp4", "10.0.0.1:8080", nil)
		assert.NoError(t, err)
	})

	t.Run("private IP outside configured CIDR remains blocked", func(t *testing.T) {
		require.NoError(t, SetTrustedPrivateNetworks([]string{"10.0.0.0/8"}))
		err := safeControl("tcp4", "192.168.1.1:80", nil)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "is not a public IP address")
	})

	t.Run("loopback allowed only if explicitly configured", func(t *testing.T) {
		require.NoError(t, SetTrustedPrivateNetworks([]string{"192.168.0.0/16"}))
		err := safeControl("tcp4", "127.0.0.1:80", nil)
		assert.Error(t, err)

		require.NoError(t, SetTrustedPrivateNetworks([]string{"127.0.0.0/8"}))
		err = safeControl("tcp4", "127.0.0.1:80", nil)
		assert.NoError(t, err)
	})

	t.Run("link-local remains blocked even with trusted networks", func(t *testing.T) {
		require.NoError(t, SetTrustedPrivateNetworks([]string{"0.0.0.0/0"}))
		err := safeControl("tcp4", "169.254.1.1:80", nil)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "is not a valid IP address")
	})

	t.Run("unspecified address remains blocked even with trusted networks", func(t *testing.T) {
		require.NoError(t, SetTrustedPrivateNetworks([]string{"0.0.0.0/0"}))
		err := safeControl("tcp4", "0.0.0.0:80", nil)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "is not a valid IP address")
	})

	t.Run("unsupported network type rejected", func(t *testing.T) {
		err := safeControl("udp", "10.0.0.1:80", nil)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "is not a safe network type")
	})

	t.Run("public IP on non-standard port still blocked", func(t *testing.T) {
		require.NoError(t, SetTrustedPrivateNetworks([]string{"10.0.0.0/8"}))
		err := safeControl("tcp4", "8.8.8.8:8080", nil)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "is not a safe port number")
	})

	t.Run("public IP on non-standard port blocked even with broad trusted CIDR", func(t *testing.T) {
		require.NoError(t, SetTrustedPrivateNetworks([]string{"0.0.0.0/0"}))
		err := safeControl("tcp4", "8.8.8.8:8080", nil)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "is not a safe port number")
	})

	t.Run("IPv6 private address with matching CIDR", func(t *testing.T) {
		require.NoError(t, SetTrustedPrivateNetworks([]string{"::1/128"}))
		err := safeControl("tcp6", "[::1]:8080", nil)
		assert.NoError(t, err)
	})
}