# cors handling in eyre Eyre lets the outside world interact with Urbit. The outside world sometimes does safety checks. Eyre currently ignores those. It should respond to them properly. ## overview of cors CORS (Cross-Origin Resource Sharing) is a security mechanism that lets browsers and servers interact, to determine whether it is safe to allow a cross-origin request. This negotiation is implemented through HTTP headers and (sometimes) the OPTIONS method. Below we take a simplified look at the two different CORS flows. For more detailed explanations, see the references at the bottom of this document. [1][2][3] ### simple cors For HTTP requests that simply read from the destination (think GET requests), CORS simply adds an Origin header to the request. The server may then either reject the request with an error, or respond as normal and include a header that acknowledges the requesting origin as allowed to read the given response. Note that if the origin isn't explicitly acknowledged (as would be the case for a server unaware of CORS), then the browser will block the response on its end. ### preflight cors For HTTP requests that can modify data (think PUT requests), a "preflight" request is sent before the cross-origin request proper. This preflight request uses the OPTIONS method and contains HTTP headers that specify the original request method and which headers it uses. The server then responds, either giving an error, or acknowledging the origin as allowed to send the request and specifying the allowed method and headers. If this exchange completes successfully, the original request is sent, and proceeds as the "simple CORS" flow described above. ## a simple cors-registry Minimum viable CORS handling is easy to implement: allow all origins. In addition to being minimally viable, this is minimally secure. Here we propose a mechanism by which Eyre can know how to respond to CORS requests based on their Origin header. Consider the addition of cors-registry to Eyre's server-state, and two new Eyre tasks: ```hoon +$ origin @torigin :: +$ cors-registry $: requests=(set origin) approved=(set origin) rejected=(set origin) == :: +$ task:able:eyre $% ... :: start responding positively to cors requests from origin :: [%approve-origin =origin] :: start responding negatively to cors requests from origin :: [%reject-origin =origin] == ``` ### changes to incoming request flow For every incoming HTTP request, Eyre checks the headers. If there is an Origin header, the following CORS logic comes into play. If the origin is not in the approved set, pass the request on to the registered handler, and send the response out unmodified. If the origin is not in the rejected set either, add it to the requests set. If the origin is in the approved set, and it is a preflight CORS request, handle it on the spot, sending back a 204 response that allows the origin, the use of credentials, and all methods and headers. (Fine-grained control over what specific methods and headers to allow seems unnecessary at this time.) If the origin is in the approved set, and it is a simple CORS request, pass the request on to the registered handler. When the %start event comes back into Eyre, append headers that allow the origin and the use of credentials. (Perhaps it might be better to phrase this as "when Eyre gets sent a %start http-event, check the Origin of the matching inbound-request". In any case, existing Eyre state can be leveraged for this logic.) ### new scry endpoints To make the above more discoverable, add new scry endpoints to Eyre. Being able to retrieve the cors-registry state will be useful later on. ``` full scry path produces value of type /ex/=//=/cors cors-registry /ex/=//=/cors/requests (set origin) /ex/=//=/cors/approved (set origin) /ex/=//=/cors/approved/[origin] ? /ex/=//=/cors/rejected (set origin) /ex/=//=/cors/rejected/[origin] ? ``` ## user-facing controls At the very least, the above should be paired with the addition of |approve-origin and |reject-origin generators. These can be called by the user themselves, or by hosting providers wanting their fleet to trust the platform they've built. The set of requests is a prominent candidate for exposure to the user. Either the user tried to use their urbit from some website and need to approve this to achieve a functional experience, or some website tried to use their urbit behind their back and needs to be reported to the authorities. Eventually, a more sophisticated userspace layer can be built on top of the proposed Eyre interface. In addition to exposing the cors-registry itself, it might allow for features like expiring approval after a certain amount of time. [1]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS [2]: https://www.moesif.com/blog/technical/cors/Authoritative-Guide-to-CORS-Cross-Origin-Resource-Sharing-for-REST-APIs/ [3]: https://httptoolkit.tech/will-it-cors/