feat: add routes to upload and download binaries
This MR adds support for managing binaries. It allows the user to:
- get the base 64 representation of a file in RQL requests. Note that this adds a ~30% binary size overhead due to the encoding.
- directly download the file using the route
/binary?eid=<EID>&attribute=<ATTRIBUTE>
. While it requires a dedicated request, it does not add any overhead and is more suited for large files. - upload binaries using the
/rql
inmultipart/form-data
OpenAPI limitations
Due to a bug in openapi-core, we were not able to make OpenApi validation work on the multipart form data using from the specification file (see code comments).
Instead, we manually decode the multipart data and run the JSON validation on the decoded data. The drawback is that the parameters format is not available from the OpenAPI spec (but is described in the description).
Security
The route using multipart/form-data
is vulnerable to CSRF attacks so it needs proper protection.
As we don't want to restrict usage of the API to HTML forms, we can't use CSRF Tokens.
We use instead CSRF custom headers:
This defense relies on the browser's same-origin policy (SOP) restriction that only JavaScript can be used to add a custom header, and only within its origin. By default, browsers do not allow JavaScript to make cross origin requests with custom headers. Only JavaScript that you serve from your origin can add these headers
The MR thus requires the X-Client-Type: <YOUR_CLIENT>
header parameter (where <YOUR_CLIENT> can be anything) to be present on all routes, JSON and multipart alike. Even if JSON POST and GET routes do not need it, I felt it was easier to understand if every route requires the custom header.