AdmiralGT / botc-scripts

Blood on the Clocktower Script Database
https://botc-scripts.azurewebsites.net/
MIT License
19 stars 10 forks source link

Feature: JSON script links should work with official BOTC app and similar clients #420

Closed dgfranklin closed 2 weeks ago

dgfranklin commented 1 month ago

Description Today if you click the JSON button on a script page, you get a link like: http://botcscripts.com/api/scripts/6669/json/

If you then paste that link into the official Blood on the Clocktower app (https://botc.app/), you'll see an error saying "Failed to Fetch" and if you look in the logs, you'll see an error message like:

Mixed Content: The page at 'https://botc.app/play' was loaded over HTTPS, but requested an insecure resource 'http://botcscripts.com/api/scripts/6669/json/'. This request has been blocked; the content must be served over HTTPS.

If you manually change the link to https:// , the script will still fail to load, but this time with the error message

Access to fetch at 'https://botc-scripts.azurewebsites.net/api/scripts/6669/json/' from origin 'https://botc.app' has been blocked by CORS policy: 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.

Manually adding the header Access-Control-Allow-Origin: * via Chrome Dev Tools and repeating fetch again results in the script loading, suggesting those are the only two issues.

Implementation proposal

Additional context

AdmiralGT commented 3 weeks ago

I believe this has been resolved. The use of a load balancer was resulting in the request.scheme always being set to http so per your PR, set this to always be https.

I've also fixed some incorrect CORS configuration which I believe was causing the issue of not being able to load the JSON from the official app. I've tested this and it now works but please do report problems with other cases if there are still issues.

dgfranklin commented 3 weeks ago

Thanks for getting that in! I can confirm it does seem to have fixed for the official app (botc.app)!

I do see that I still get CORS error on https://www.pocketgrimoire.co.uk/ . The response headers show Access-Control-Allow-Origin is being set (correctly) on the requests originating from botc.app, but there is no such header on the one from https://www.pocketgrimoire.co.uk. I haven't looked carefully yet at what the difference in the request headers, but I'd guess they might hint at the difference. I'll take a more detailed look in the next few days.

At least in my opinion, getting it working in the official app was the much bigger deal, so I don't think the remaining issue is a critical thing to fix. But if we can identify a simple fix to get it working in more places, it would be nice.

AdmiralGT commented 2 weeks ago

Ah, sad to hear it doesn't work with the Pocket Grimoire. I only tested with the official app so I'll take a look at the pocket grimoire tonight. I have a feeling this is related to my CORS configuration on the Azure App

dgfranklin commented 2 weeks ago

I just looked into this a little further. I copied the request the official app makes as curl and got:

curl -v 'https://botcscripts.com/api/scripts/6669/json/' \
  -H 'Accept: */*' \
  -H 'Accept-Language: en-US,en;q=0.9' \
  -H 'Cache-Control: no-cache' \
  -H 'Connection: keep-alive' \
  -H 'Origin: https://botc.app' \
  -H 'Pragma: no-cache' \
  -H 'Referer: https://botc.app/' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Site: cross-site' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: "Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"'

The response headers correctly show show Access-Control-Allow-Origin set and it's working as expected.

Then, before even looking at comparing to the actual request from Pocket Grimoire, I tried substituting the domain in the existing curl request above - i.e changing the Origin Header and Referer Header to https://www.pocketgrimoire.co.uk. Interestingly, just that change is enough that the response does not contain the expected Access-Control-Allow-Origin. This makes me think that somewhere botc.app is explicitly allow-listed and https://www.pocketgrimoire.co.uk is not?

I don't know how easily Azure allows you to do this, but for the JSON and perhaps other things that are (effectively) static public files, you should be fine to set the CORS policy something open, like setting 'Access-Control-Allow-Origin: *". And then for the rest of the site, I'd actually probably restrict it even more than it currently is. (e.g. there's no real reason botc.app should be able to make CORS requests to every API route)

AdmiralGT commented 2 weeks ago

Thanks. I think pocketgrimoire now also works (although I've not been able to confirm on the official app since I don't have a subscription).

Annoyingly there are 2 CORS controls. Azure just allows me to define origins and I had both botc.app and *, essentially I wanted to allow all but document things I had explicitly given permission. Sadly that doesn't work and seems to limit to the precise terms so I've now just set it to *.

However, the Azure app doesn't know what endpoints I have so that has to be configured in Django. It's currently configured to allow GETs on all API routes which I'm fairly happy with since the GET APIs are open access. If I need to lock down that down further I can.

dgfranklin commented 2 weeks ago

Looks like you're busy with some other fires 🔥 , but I can confirm this appears to be working in both the official app and Pocket Grimoire (and presumably elsewhere)! Thank you for iterating on this - it will be really handy! Thank you for maintaining this tool, and please let me know if I can ever be of assistance in the future, especially around any frontend-y things.