we're running into a problem with websockets and Content-Security-Policy
when deploying our yada app to a staging environment:
sse.cljs:52 Refused to connect to '<wss://searchdev.doctorevidence.com/api/sse/ws>' because it violates the following Content Security Policy directive: "default-src https: data: 'unsafe-inline' 'unsafe-eval'". Note that 'connect-src' was not explicitly set, so 'default-src' is used as a fallback.
We don't send this header in nginx. Is yada sending a default for this?I do see a couple of issues around this: https://github.com/juxt/yada/issues/61
Yes.
You can change the CSP per-resource.
alright!
@dominicm I now have this:
(resource
system
{:swagger/tags ["app"]
:id :dre.resources/sse
:content-security-policy "default-src https: wss: data: 'unsafe-inline' 'unsafe-eval'"
:methods
{:get
{:consumes "application/json"
:produces "application/json"
:response
(fn [ctx]
(let [req (:request ctx)
conn (http/websocket-connection req)
user-id (auth/user-id (user-profile ctx))
sse (:dre.app.sse/sse system)
chan (sse/new-chan-for-user! sse user-id)
_ (-> conn (d/chain
(fn [socket]
(s/connect chan socket)))
(d/catch (fn [e]
(error e))))]
(sse/send-message-to-user sse user-id :sse/ack)
nil))}}})
but we're still getting something else back in the browser 😕something else than: :content-security-policy "default-src https: wss: data: 'unsafe-inline' 'unsafe-eval'"
I thought it went inside a map
https://juxt.pro/yada/manual/index.html#cross-origin-resource-sharing-cors access control
a map?
we used to have it on the top level of our yada resources like months or years ago:
:produces formats
:consumes formats
:content-security-policy content-security-policy
that seems to be the correct place: https://github.com/juxt/yada/blob/e92f35d1be6b8fabee65e280efebf71fae9c9b1b/src/yada/schema.clj#L518
Hmm. Yes.
hmm, adding :content-security-policy "default-src https: wss: data: 'unsafe-inline' 'unsafe-eval'"
on ALL resources works, but not when I only add it to the resource which produces the websocket:
(defn new-websocket-resource
[system]
(resource
system
{:swagger/tags ["app"]
:id :dre.resources/sse
:content-security-policy "default-src https: wss: data: 'unsafe-inline' 'unsafe-eval'"
:methods
{:get
{:consumes "application/json"
:produces "application/json"
:response
(fn [ctx]
(let [req (:request ctx)
conn (http/websocket-connection req)
user-id (auth/user-id (user-profile ctx))
sse (:dre.app.sse/sse system)
chan (sse/new-chan-for-user! sse user-id)
_ (-> conn (d/chain
(fn [socket]
(s/connect chan socket)))
(d/catch (fn [e]
(error e))))]
(sse/send-message-to-user sse user-id :sse/ack)
{}))}}}))
so what's up with that?
No idea 😹
Don't you need to adjust the csp elsewhere anyway?
You need to set the csp for your html pages to allow websockets.
Not on the websocket resource
oh I see
well, then it's fine I guess
Yeah.
I really don't care as long as this works
I'm not sure websockets supports headers, it isn't http
thanks for the help!