Hi everybody,
have bought the API Addon in order to sync Tickets to my ninoxdb database . It allows me to start a request from inside the browser to Freescout API. However I obviously run into cross origin resource sharing problems. So I would like you guys to let me specify in my Freescout API Addon which hosts are allowed to share resources with and which headers.
We will check what can be done.
Meanwhile see:
https://serverfault.com/questions/162429/how-do-i-add-access-control-allow-origin-in-nginx
https://enable-cors.org/server_nginx.html
Which headers you need to specify in the module?
Those admissible for using the API. Authorization, X-Freescout-API-Key
Unfortunately it seems the nginx configuration is beyond my control, because Freescout is served from a vendor supplied container image, by Cloudron ( https://www.cloudron.io/ ). I have no idea whether they have one Http Server running for all the apps (which Freescout is one of) or one for every app.
The thing is that the API is designed to accessed from the server, not from the browser as you are exposing your API credentials.
In our case that is ok though, because it is login protected. Is there a way to get the conversations+time tracking+custom fields info as a csv/json?
So I‘ve asked for a solution in the cloudron forum and they are of the opinion that it should be the app devs call whether to implement this feature: https://forum.cloudron.io/topic/3830/enable-cors-in-freescout-api/2
Yes. We will add it to the module.
Hi I'm one of the Cloudron devs, @freescout-helpdesk let us know if you need assistance to reproduce/test this on Cloudron.
"Allowed CORS Hosts" option is available now in API & Webhooks Module v1.0.3

It doesn't work with ninoxdb.
Is this covered by a unit test?
Nope. You may need to find out the reason by yourself.
Wrote a test @ https://poc.ma-en.de/:
(function makeRequest(apiEndpoint, apiKey) {
fetch(apiEndpoint, {
method: "GET",
cors: "cors",
headers: {
"X-FreeScout-API-Key": apiKey
}
}).then(console.log)
})(window.prompt("Enter FreeScout API endpoint"), window.prompt("Enter FreeScout API Key"))
Browser dev tools network tab output
Request URL: https://ticket.paridata.net/api/conversations/[ticket id removed]
Request Method: OPTIONS
Status Code: 200
Remote Address: 45.9.61.129:443
Referrer Policy: strict-origin-when-cross-origin
allow: GET,HEAD
cache-control: max-age=0, must-revalidate, no-cache, no-store, private
content-length: 0
content-type: text/html; charset=UTF-8
date: Mon, 07 Dec 2020 14:04:28 GMT
pragma: no-cache
referrer-policy: no-referrer-when-downgrade
server: nginx
strict-transport-security: max-age=15768000
x-content-type-options: nosniff
x-download-options: noopen
x-permitted-cross-domain-policies: none
x-xss-protection: 1; mode=block
:authority: ticket.paridata.net
:method: OPTIONS
:path: /api/conversations/[ticket id removed]
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: de,de-DE;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
access-control-request-headers: x-freescout-api-key
access-control-request-method: GET
origin: https://poc.ma-en.de
referer: https://poc.ma-en.de/
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.55
Console.log output:
Access to fetch at 'https://ticket.paridata.net/api/conversations/[ticket id removed]/' from origin 'https://poc.ma-en.de' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I'm no pro at this stuff, so please advise, if the test is inadequate. Can you reproduce this with your own Freescout server?
With the inputs:
endpoint: https://demo.freescout.net/api/conversations/12
apikey: c2ba609c687a3425402b9d881e5075db
Browser dev tools Network tab:
Request URL: https://demo.freescout.net/api/conversations/12
Request Method: OPTIONS
Status Code: 200 OK
Remote Address: 82.196.10.232:443
Referrer Policy: strict-origin-when-cross-origin
Allow: GET,HEAD
Cache-Control: max-age=0, must-revalidate, no-cache, no-store, private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html; charset=UTF-8
Date: Mon, 07 Dec 2020 14:38:14 GMT
Pragma: no-cache
Server: nginx/1.14.0 (Ubuntu)
Transfer-Encoding: chunked
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: de,de-DE;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Access-Control-Request-Headers: x-freescout-api-key
Access-Control-Request-Method: GET
Connection: keep-alive
Host: demo.freescout.net
Origin: https://poc.ma-en.de
Referer: https://poc.ma-en.de/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.55
Browser console output:
Access to fetch at 'https://demo.freescout.net/api/conversations/12' from origin 'https://poc.ma-en.de' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I also noticed that when saving a new host in the 'Allowed CORS Hosts' field, the page re-loads, but the value is reverted to original one. Only when manually reloading the page, the new value appears. Should I file a new bug?

It kind of looks like there is something wrong with the pre-flight OPTIONS request. Running a request from within the freescout.net domain (which seems to be the one which is allowed in that demo instance) results in the following:
fetch(new Request('https://demo.freescout.net/api/conversations/12?api_key=c2ba609c687a3425402b9d881e5075db'))
Promise { <state>: "pending" }
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://demo.freescout.net/api/conversations/12?api_key=c2ba609c687a3425402b9d881e5075db. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘freescout.net’).
As far as I can tell the response to the OPTIONS request misses those CORS headers:
» curl -X OPTIONS 'https://demo.freescout.net/api/conversations/12?api_key=c2ba609c687a3425402b9d881e5075db' -v [04:27:23]
* Trying 82.196.10.232:443...
* Connected to demo.freescout.net (82.196.10.232) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: CN=demo.freescout.net
* start date: Oct 19 02:45:04 2020 GMT
* expire date: Jan 17 02:45:04 2021 GMT
* subjectAltName: host "demo.freescout.net" matched cert's "demo.freescout.net"
* issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL certificate verify ok.
> OPTIONS /api/conversations/12?api_key=c2ba609c687a3425402b9d881e5075db HTTP/1.1
> Host: demo.freescout.net
> User-Agent: curl/7.73.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.14.0 (Ubuntu)
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Allow: GET,HEAD
< Cache-Control: max-age=0, must-revalidate, no-cache, no-store, private
< Date: Mon, 07 Dec 2020 15:27:26 GMT
< Pragma: no-cache
<
* Connection #0 to host demo.freescout.net left intact
When passing ?api_key=.... in the request url I get the correct output with Access-Control-Allow and so on. However, when doing the request without ?api_key in the url, only passing "X-FreeScout-API-Key" header, the response does not have Access-Control-Allow-X headers. I can continue with my project, it works in ninoxdb like this as well, however, I feel this should be patched.
OPTIONS method is not supported for now. Only GET and POST.
X-FreeScout-Api-Key header works fine:

I am not sure but I think we seem to talk past each other here. To be on the same page, so in my understanding, if a website starts a request to another origin, the browser will first send a pre-flight request (that is an OPTIONS method request). The server then has to answer with the CORS headers to tell the browser if the intended request (usually the GET or POST) are allowed for this website.
So what I see missing is the headers in the OPTIONS request to tell the browser that the followup GET/POST will be ok.
We will check.
Fixed in API & Webhooks Module v1.0.4