mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
I modified the proxy host cache we already had and were using for websocket csp headers to also include the wildcard app host, then used those for frame-src policies. I did not add frame-ancestors, since if I understand correctly, those would go on the app, and this middleware does not come into play there. Maybe we will want to add it on workspace apps like we do with cors, if we find apps are setting it to `none` or something. Closes https://github.com/coder/internal/issues/684
68 lines
1.8 KiB
Go
68 lines
1.8 KiB
Go
package httpmw_test
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/coder/coder/v2/coderd/httpmw"
|
|
"github.com/coder/coder/v2/coderd/proxyhealth"
|
|
"github.com/coder/coder/v2/codersdk"
|
|
)
|
|
|
|
func TestCSP(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
proxyHosts := []*proxyhealth.ProxyHost{
|
|
{
|
|
Host: "test.com",
|
|
AppHost: "*.test.com",
|
|
},
|
|
{
|
|
Host: "coder.com",
|
|
AppHost: "*.coder.com",
|
|
},
|
|
{
|
|
// Host is not added because it duplicates the host header.
|
|
Host: "example.com",
|
|
AppHost: "*.coder2.com",
|
|
},
|
|
}
|
|
expectedMedia := []string{"media.com", "media2.com"}
|
|
|
|
expected := []string{
|
|
"frame-src 'self' *.test.com *.coder.com *.coder2.com",
|
|
"media-src 'self' media.com media2.com",
|
|
strings.Join([]string{
|
|
"connect-src", "'self'",
|
|
// Added from host header.
|
|
"wss://example.com", "ws://example.com",
|
|
// Added via proxy hosts.
|
|
"wss://test.com", "ws://test.com", "https://test.com", "http://test.com",
|
|
"wss://coder.com", "ws://coder.com", "https://coder.com", "http://coder.com",
|
|
}, " "),
|
|
}
|
|
|
|
// When the host is empty, it uses example.com.
|
|
r := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
rw := httptest.NewRecorder()
|
|
|
|
httpmw.CSPHeaders(codersdk.Experiments{
|
|
codersdk.ExperimentAITasks,
|
|
}, false, func() []*proxyhealth.ProxyHost {
|
|
return proxyHosts
|
|
}, map[httpmw.CSPFetchDirective][]string{
|
|
httpmw.CSPDirectiveMediaSrc: expectedMedia,
|
|
})(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
rw.WriteHeader(http.StatusOK)
|
|
})).ServeHTTP(rw, r)
|
|
|
|
require.NotEmpty(t, rw.Header().Get("Content-Security-Policy"), "Content-Security-Policy header should not be empty")
|
|
for _, e := range expected {
|
|
require.Contains(t, rw.Header().Get("Content-Security-Policy"), e)
|
|
}
|
|
}
|