Requesting obfs4 bridges using the /moat/fetch interface via bridges.torproject.org in Python does not work

74 Views Asked by At

I have implemented the following Python function according to the documentation https://github.com/tladesignz/bridgedb?tab=readme-ov-file#accessing-the-moat-interface:

import requests

MOAT_SERVER_URL = "https://bridges.torproject.org"

def request_bridges():
    transports = ["obfs4"]
    payload = {
        "data": [{
            "version": "0.1.0",
            "type": "client-transports",
            "supported": transports,
        }]
    }

    headers = {
        "Content-Type": "application/json"
    }

    response = requests.post(f"{MOAT_SERVER_URL}/moat/fetch", json=payload, headers=headers)

    if response.status_code == 200:
        json_data = response.json()
        moat_data = json_data["data"][0] # <- Error
        if "challenge" in moat_data:
            # captcha_challenge(moat_data)
        else:
            pass # FIXME: Error Handling
    else:
        pass # FIXME: Error Handling

But the request does not seem to be correct because json_data has the following value:

{
   "errors":[
      {
         "id":"0",
         "type":"",
         "version":"0.1.0",
         "code":415,
         "status":"Unsupported Media Type",
         "detail":""
      }
   ]
}

The code should request bridges for the user via BridgeDB, so that the user can then solve the captcha which should be present in moat_data. (Just like the Tor Browser does)

I have already tried to send the payload as data instead of json:

import requests

MOAT_SERVER_URL = "https://bridges.torproject.org"

def request_bridges():
    transports = ["obfs4"]
    payload = {
        "data": [{
            "version": "0.1.0",
            "type": "client-transports",
            "supported": transports,
        }]
    }

    headers = {
        "Content-Type": "application/x-www-form-urlencoded"
    }

    response = requests.post(f"{MOAT_SERVER_URL}/moat/fetch", data=payload, headers=headers)
    # Rest of the code

I have also tried using Curl to check if the Python user agent might be blocked:

curl -X POST -H "Content-Type: application/json" -d '{"data": [{"version": "0.1.0", "type": "client-transports", "supported": ["obfs4"]}]}' https://bridges.torproject.org/moat/fetch

But this all returns the same JSON code as above.

1

There are 1 best solutions below

0
TN3W On BEST ANSWER

As I found out myself, the BridgeDB uses the standard https://jsonapi.org/ which prescribes the content type "application/vnd.api+json".

Here is the correct code for this function:

import requests

MOAT_SERVER_URL = "https://bridges.torproject.org"

def request_bridges():
    transports = ["obfs4"]
    payload = {
        "data": [{
            "version": "0.1.0",
            "type": "client-transports",
            "supported": transports,
        }]
    }

    headers = {
        "Content-Type": "application/vnd.api+json"
    }

    response = requests.post(f"{MOAT_SERVER_URL}/moat/fetch", json=payload, headers=headers)

    if response.status_code == 200:
        json_data = response.json()
        moat_data = json_data["data"][0] # <- Error
        if "challenge" in moat_data:
            # captcha_challenge(moat_data)
        else:
            pass # FIXME: Error Handling
    else:
        pass # FIXME: Error Handling