JodelRaccoons / jodel_api

Unoffical Python Interface to the Jodel API
https://github.com/nborrmann/jodel_api
MIT License
18 stars 7 forks source link

Signed request expected / All Accounts banned at creation #26

Closed ExTBH closed 2 years ago

ExTBH commented 2 years ago

Issue

Secret key got changed ...

Environment

If you're reporting a bug, please attach the output of the following commands:

7.35
b'rYKfoeKQOwMHtBNTrCgvXEvgJBdwAHeZJFVqsBYh'
ExTBH commented 2 years ago

new secret: SlkXamhFfBJmlCyNlEuoqgoRSIWMRvOEhbgHBPKs version: 7.44

i've managed to get the new ones for IOS but all accounts get insta banned no matter what

edit: there seems to be a new Key in /v2/users which is ['apple_device_token'] which authenticate the App before creating an account, which change on each new account(Coule be Apple APN)

for future if anyone wants to update this and have a Jailbroken Iphone this will extract the keys and log them in SYS log

Unbrick commented 2 years ago

You might want to give this key a try, I just extracted it from the Android-Version 7.37.1:

bGXTsUrGsQXlBpRxXjTIRvMAlDIQbweoOJDDAJMP

Moreover, please remember to change the client type from ios_ to android_.

ExTBH commented 2 years ago

Thanks, tried it still accounts are banned, Unfortunately i don't have an android Phone neither a Windows machine to check the requests for any change, if u can check them and gonna try

for IOS there is a 1 time request when you open the app for the first time, one you open the app and click continue it gets called if it lets you set Age then your phone is verified with Apple, they couldve implemented the same with Android.

I will try to race the method on IOS to get more info and maybe a way to fake the token.

Unbrick commented 2 years ago

Maybe you want to try @springjools solutions from issue #19, as far as I recall he got it working back then. If I get to it I'll take a closer look tomorrow and intercept some of the traffic.

springjools commented 2 years ago

Yes, but my accounts also get instabanned. But the first time you check for ban, it reports false. But when you immediately check again, it reports true.

ExTBH commented 2 years ago

I've found the Token its server to server check https://developer.apple.com/documentation/devicecheck?language=objc

idk if its possible to spoof it or trick it could be wrong one

edit2: found the method and was able to generate

ExTBH commented 2 years ago

I've figured everything and its not good :( Since Version 7.40(in my tests) and up Jodel team Introduced new way to ban accounts by using DCDevice Token. This token is per-device per-developerAccount and provides two 1 bit fields bit1: 0, bit2: 0 and the developer can assign any value for them.

So if someone tries to make an account with the API, they first need to get a token from their iPhone and make a request with it, if this new account got banned Jodel team have a copy of the token in their server(it doesn't expire) and they will update apple servers with something like this bit1: 1, bit2: 0, now when you try to make a new account on your phone or by the API, Jodel will receive a new token from you and send it to apple and they see bit1: 1 and the new account is banned before its made.

So you need to wait until Jodel servers update apple servers and switch it back to bit1: 0 after you ban has expired to use a new account.

If the token that got sent to Jodel is wrong apple will respond with HTTP Code 400 and this account also get banned.

springjools commented 2 years ago

Ok, I think it's difficult to circumvent a DCDevice token, since if I understand it correctly, it's a server to server thing. But I understand this only applies to ios. What about the procedure on android? Something similar there?

Unbrick commented 2 years ago

Just took a look into the application, there seems to be an alternative route to register iOS devices which do not support the device check:

image
ExTBH commented 2 years ago

I've set isSupported to False and it created a new account without DCDevice but i got 7-10 day ban, i think im banned by device_uid i'll try to spoof it

can i ask what decompiler you use, it looks alot better than Ghidra

edit: this device_uid token is weird it changes every time i register, It looks Base64 but when i decrypt it it looks like this ољ Lзнѓkr:іҐ¤zЙq not like a UUID.

ExTBH commented 2 years ago

I've spoofed the UUID before it gets hashed but still getting insta ban

if anyone wants to try build this with Theos, it'll randomize it when called

is there a chance that Jodel just bans all accounts as precaution?

Unbrick commented 2 years ago

I use IDA as a decompiler for Jodel.

The Apple reference of DeviceCheck says the application must check whether DeviceCheck is supported by the device before using it. Maybe older iPhones do not support DeviceCheck. If we can find an Jodel-Version for e.g. iPhone 6 (iOS 12 is the last supported version) we could try using this version and HMAC-Key to register a user. This might circumvent the DeviceCheck entirely.

ExTBH commented 2 years ago

to my testing, jodel allows accounts made with old version to work in the old version, but trying to create an account with older version fails and says Please update the app, if you know the last supported version number on iPhone 6 i will downgrade to it and see

ExTBH commented 2 years ago

Think i made a mistake, I've downloaded Version 7.10 and checked the http request there is the same DCDevice token, it's not new they using it for over a year now

ExTBH commented 2 years ago

random 3 AM idea might worth it, i noticed on the app that when opening a link to a post it wont open in the app if i got nextDNS enabled, thats because Branch.io is integrated in the app and nexDNS blocks all requests to it. googling Branch.io shows

Branch's attribution technology is designed specifically for the world where universal identifiers such as IDFA and GAID don’t exist.

what if the accounts get banned because of Branch's stuff as its requests aren't implemented here?

we should try to create an account with Branch's HTTPS requests and see if its banned.

when i spoofed UUID before it was for jodel HTTPS requests, but i didn't check if branch's is logging any tokens or anything

im going to sleep now i will follow with this when i wake up.

Unbrick commented 2 years ago

Might be definitely worth a try but I thing i tested this some time ago and it did not have any effect.

ExTBH commented 2 years ago

my basic analysis when creating a new account after wiping the app data Branch makes 1 request to https://api2.branch.io/v1/install most of it is tracking garbage except a couple. we care about the token and good stuff

1st token apple_receipt : Apple Docs, looks useless .

2nd apple_attribution_token : Apple Docs, another useless one for ads.

3rd ios_vendor_id & hardware_id : Apple Docs, looks like the only interesting thing only here. and it gives a response :

Numbers are changed.

{
  "session_id": "10134534657934677872",
  "link": "https://shared.jodel.com/a/key_live_jcESXFnKwxb53gafuWSRFijozto4BLB5?%24randomized_bundle_token=1066931657934513952",
  "data": "{\"+clicked_branch_link\":false,\"+is_first_session\":false}",
  "randomized_device_token": "1059087119560141413",
  "randomized_bundle_token": "1066931657934513952",
  "invoke_register_app": true
}

not very useful but they got 1 thing right, not my first session so im in the system and probably tagged banned if Jodel really integrates with them

ExTBH commented 2 years ago

Might be helpful iPhone 6 iOS 12.5.5 last supported version is 4.139 https://github.com/ExTBH/bug-free-repo/blob/main/IPAs/Jodel_4.139_iOSGods.com.ipa

Unbrick commented 2 years ago

Thank you very much @ExTBH!

Just updated the keys to the 4.139 version, for me most of the tests are currently passing, you might want to give it a try!

ExTBH commented 2 years ago

Out of home now without my mac, will be back in 9 hours and test, if this works i might use it for another project that i can't fix because of DeviceCheck, thanks

ExTBH commented 2 years ago

accounts banned for me, what are your results? edit: maybe the endpoints are different? image

springjools commented 2 years ago

I also updated with git pull and it resolves the signed request expected-error. But accounts are still blocked. You need to test it like this:

`Python 3.10.1 (tags/v3.10.1:2cd268a, Dec 6 2021, 19:10:37) [MSC v.1929 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information.

import jodel_api lat, lng, city = 48.148434, 11.567867, "Munich" j = jodel_api.JodelAccount(lat=lat, lng=lng, city=city) Creating new account. Creating account with data {'location': {'country': 'DE', 'city': 'Munich', 'loc_coordinates': {'lat': 48.148434, 'lng': 11.567867}, 'loc_accuracy': 15.457}, 'device_uid': 'e9e0b5fd04b0852d374a2206c877612b7393f12084289536083ad46b2b4644ac', 'language': 'de-DE', 'client_id': 'cd871f92-a23f-4afc-8fff-51ff9dc9184e'} status, response = j.get_user_config() print(status) 200 blocked = response.get('user_blocked') print (blocked) True`

Moreover, I rememberthat previously the first call used to return False, and any second call to get the same information used to return True.

Also before there was a case when the status of the blocked-variable depended on the lat and lon-coordinates you fed to the function, ie I think geo-fence of some sort.

Unbrick commented 2 years ago

Not sure what is going on, just tested the requests with updated keys (iOS, 7.51) and the response looks good for me!

Key is as follows:

    secret = 'YEKawcOEwzigovvWEFkBVWPIsgHhnIFmfMtfjYLS'.encode('ascii')
    version = '7.51'

And the corresponding requests i performed are:

import json
import time

if __name__ == "__main__":
    import jodel_api

    lat, lng, city = 48.123456, 11.987654, "Munich"
    j = jodel_api.JodelAccount(lat=lat, lng=lng, city=city)
    status, response = j.get_user_config()
    print("Blocked ", response.get('user_blocked'))
    time.sleep(1)
    print("Karma", j.get_karma())
    time.sleep(1)
    print("Blocked ", response.get('user_blocked'))

which lead to the following output:

Creating new account.
Creating account with data [...]
Blocked  False
Karma (200, {'karma': 100})
Blocked  False

Could you please verify this on your end? If it works i'll update the keys accordingly

springjools commented 2 years ago

Weird. I updated the secret and version in L30-31 in jodel_api, ran setup build and setup install --user. I get this:

PS > python .\test.py Creating new account. Creating account with data {'location': {'country': 'DE', 'city': 'Munich', 'loc_coordinates': {'lat': 48.123456, 'lng': 11.987654}, 'loc_accuracy': 15.457}, 'device_uid': 'b32937fd1e430b55090b264cc657f6d8a3f06e81de0eb3eacc86902b86a421db', 'language': 'de-DE', 'client_id': 'cd871f92-a23f-4afc-8fff-51ff9dc9184e'} Blocked True Karma (200, {'karma': 100}) Blocked True

test.py is copy paste of the code you posted

Unbrick commented 2 years ago

Try altering the account creation to the following line to ensure the correct secret and version are used:

    j = jodel_api.JodelAccount(lat=lat, lng=lng, city=city, _secret='YEKawcOEwzigovvWEFkBVWPIsgHhnIFmfMtfjYLS', _version='7.51')

Additionally you might want to modify the coordinates to a random value, some bans seem to be based on coordinates.

springjools commented 2 years ago

But we used the same coordinates...

Unbrick commented 2 years ago

If accounts with the same coordinates are created from different IP addresses, they might detect it and ban them. Therefore a randomisation of coordinates might be necessary.

ExTBH commented 2 years ago

for a minute i thought Jodel team disabled this shit :(

edit: @Unbrick could you make another account and check to make sure?

lat, lng, city, country = 26.4591484, 50.117690, "Saar", "BH"

j = jodel_api.JodelAccount(lat=lat, lng=lng, city=city, country=country)
time.sleep(5)
status, response = j.get_user_config()
print("Blocked ", response.get('user_blocked'))
time.sleep(1)
print("Karma", j.get_karma())
time.sleep(1)
print("Blocked ", response.get('user_blocked'))
Creating new account.
Creating account with data {'location': {'country': 'BH', 'city': 'Saar', 'loc_coordinates': {'lat': 26.4591484, 'lng': 50.11769}, 'loc_accuracy': 15.457}, 'device_uid': 'b9c0f5eb867c835e0430ea4c2523afe06b2c141509bf8361ab0bf3b3fd771d80', 'language': 'bh-BH', 'client_id': 'cd871f92-a23f-4afc-8fff-51ff9dc9184e'}
Blocked  True
Karma (200, {'karma': 200})
Blocked  True
Unbrick commented 2 years ago

Just checked, the block seems to dependant on the IP address. You might want to try residential proxies, i tested now with two different, one got me blocked, the other one worked like a charm!

Edit: Pushed the current version state to master now.

ExTBH commented 2 years ago

i'll check with my cellular IP, something is not right..

Edit: My cellular looks to be banned too

Edit2: in this Lib API URL is set to "https://api.go-tellm.com/api{}" in the app its https://api.jodelapis.com/api{} how would we know the first isn't blacklisted

IsakNyberg commented 2 years ago

For what it is worth, I have tried this with a vpn from several locations (changing coordinates, city and country input every time) and i am also banned every time i make an account. I've tried with both "https://api.go-tellm.com/api{}" and "https://api.jodelapis.com/api{}".

ExTBH commented 2 years ago

What about switching to Android version? Does Android implement something like DeviceCheck? +Android is bigger, so if there any its probably bypassed.

Unbrick commented 2 years ago

I'll perform more tests tomorrow regarding IP address and location. @ExTBH the Android version requires email verification which would require a mail server to verify the account.

Unbrick commented 2 years ago

Sadly i now can replicate your issue, account seems to be banned instantly.

ExTBH commented 2 years ago

Guess that was a bug on their servers.. I see 2 options to get this working, if anyone has anything please say

  1. We figure out how to bypass DeviceCheck which will take ALOT of time and probably wont bypass it
  2. We switch to Android version and be limited by google accounts mail server
Unbrick commented 2 years ago

Defeating DeviceCheck is no possible option from my point of view. Leaving us with the email verification.

I recorded the required requests and documented the (hopefully) complete process here.

Now in theory all it needs is a mail server which allows API access. I tested OpenTrashmail which seems to do just fine. All it takes now is plugging it all together.

ExTBH commented 2 years ago

i can think of one problem here, Google banning domains after it notices a bunch of accounts made with it.

2 AM for me now, i'll check with a public mail provider tomorrow since i don't have a VPS to work with.

if this work i've got an idea to solve iOS bans for good, basic idea is, MITM the IOS app calling the api, replace the requests to android stuff, get the responses, convert them to something the iOS app understand

i don't see CORS headers also, should be possible for me to make a web client for the app with this

ExTBH commented 2 years ago

Oki I've followed the steps above but haven't tested step 4, the rest works.

I tried https://www.mohmal.com/ this email service and made a script to make it in 2 steps, should be able to use a free mail with API and work also.

from typing import Union
import requests

#Used by all methods here
baseURL = "https://www.googleapis.com"
querystring = {"key":"AIzaSyDFUC30aJbUREs-vKefE6QmvoVL0qqOv60"}

headers = {
    "X-Android-Package": "com.tellm.android.app",
    "X-Android-Cert": "A4A8D4D7B09736A0F65596A868CC6FD620920FB0",
    "X-Client-Version": "Android/Fallback/X21000001/FirebaseCore-Android",
}

def requestLogin(email: str) -> Union[bool, str]:
    url = f"{baseURL}/identitytoolkit/v3/relyingparty/getOobConfirmationCode"

    payload = {
        "requestType": 6,
        "email": f"{email}",
        "androidInstallApp": True,
        "canHandleCodeInApp": True,
        "continueUrl": "https://jodel.com/app/magic-link-fallback",
        "androidPackageName": "com.tellm.android.app",
        "androidMinimumVersion": "5.116.0"
    }

    response = requests.post(url=url, json=payload, headers=headers, params=querystring)

    if response.json()['kind'] == 'identitytoolkit#GetOobConfirmationCodeResponse' and response.status_code == 200:
        return True
    return f"{response.status_code} | Failed to create account | {response.text}"

def extractOob(link: str) -> Union[bool, str]:
    try:
        url = requests.utils.unquote(link)
        start = 'oobCode='
        end = '&continueUrl'
        return(url[url.find(start)+len(start):url.rfind(end)])
    except:
        return False

def redeemOob(oobCode: str, email: str) -> Union[str, dict]:

    url = f"{baseURL}/identitytoolkit/v3/relyingparty/emailLinkSignin"

    payload = {
        "email": f"{email}",
        "oobCode": f"{oobCode}"
    }

    response = requests.post(url, json=payload, headers=headers, params=querystring)
    responseJsoned = response.json()

    if response.status_code == 200 and responseJsoned['kind'] == 'identitytoolkit#EmailLinkSigninResponse':
        return {
            'idToken': responseJsoned['idToken'],
            'refreshToken': responseJsoned['refreshToken'],
            'expiresIn': responseJsoned['expiresIn'],
            'localId': responseJsoned['localId'],
        }
    return f"{response.status_code} | Failed to redeem Oob | {response.text}"

def refreshTokens(refreshToken: str) -> Union[str, dict]:
    url = "https://securetoken.googleapis.com/v1/token"

    payload = {
        "grantType": "refresh_token",
        "refreshToken": f"{refreshToken}"
    }

    response = requests.post(url, json=payload, headers=headers, params=querystring)
    responseJsoned = response.json()

    if response.status_code == 200:
        return {
            'access_token': responseJsoned['access_token'],
            'expires_in': responseJsoned['expires_in'],
            'refresh_token': responseJsoned['refresh_token'],
            'user_id': responseJsoned['user_id'],
            'project_id': responseJsoned['project_id']
        }
    return f"{response.status_code} | Failed to refresh tokens | {response.text}"

email = '<Your@mail.com>'

if requestLogin(email):
    oob = extractOob(input("Paste URL from Email: "))
    if oob == False:
        print("\n\nCan't extract OobCode")
        exit()

    oobTokens = redeemOob(oob, email) 
    if type(oobTokens) != dict:
        print('\n\n' + oobTokens)
        exit()

    refreshedTokens = refreshTokens(oobTokens['refreshToken'])
    if type(refreshedTokens) != dict:
        print('\n\n' + refreshedTokens)
        exit()
    print(refreshedTokens)
Unbrick commented 2 years ago

@ExTBH please check out the android_mail_auth branch. For me the registration using email works like a charm:

Requested email verification for [...]
Obtained oob token [...] for email [...]
Creating new account.
Creating account with data {'firebase_uid': 'jtNECbcwmfPGgQVuyKVPpsW8UIE3', 'firebaseJWT': 'eyJhbGciO[...]
Blocked  False
Karma (200, {'karma': 100})
Posts [200, {"posts": [{"message": "Podcast recs? I'm in to true crime " [...]
Blocked  False

Edit: I used a good portion of your code for the verification, i hope you are fine with this :)

ExTBH commented 2 years ago

Out of home, will check when im back.

Im all in FOSS so yeah im ok

Unbrick commented 2 years ago

Quick update: Seems like they have a absolutely brilliant bot prevention system. Even though verifying by mail my accounts are now blocked. And quick code update, you can now either pass a mail address and mail fetch handler directly in the constructor or leave them out. Leaving them out prompts you for manual input.

The fetch_handler requires one parameter (the email address argument) and should return a text containig the oobCode. The code is extracted automatically afterwards.

Code example with handler:

import json
import time
import jodel_api
import requests

def email_fetcher(email_address):
    email = None
    while not email:
        response = requests.get(f"https://your.email.service/{email_address}").text
        if "oobCode" in response:
            return response
        else:
            time.sleep(1)

if __name__ == "__main__":
    lat, lng, city = 48.834875, 2.344962, "Paris"
    j = jodel_api.JodelAccount(lat=lat, lng=lng, city=city, email_fetch=email_fetcher, email_address="test@mail.com")

Example without handler (interactive mode):

Python 3.9.7 (tags/v3.9.7:1016ef3, Aug 30 2021, 20:19:38) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from jodel_api import jodel_api
>>> lat, lng, city = 48.834875, 2.344962, "Paris"
>>> j = jodel_api.JodelAccount(lat=lat, lng=lng, city=city)
No email address is given, please enter it manually: bojeme2191@logodez.com
No email fetch handler registered, using manual mode
Requested email verification for bojeme2191@logodez.com
Please enter the link found in the email: https://ae3ts.app.goo.gl/?link=https://tellm-android.firebaseapp.com/__/auth/action?apiKey%3DAIzaSyBC5AfciIsT15NSwrfhLhsLG5UtFisbeSA%26mode%3DsignIn%26oobCode%3D4W6H43itna23hqunAKTIvh6MdHrHoeJm1Oton9LRz0oAAAGCRn7CPg%26continueUrl%3Dhttps://jodel.com/app/magic-link-fallback%26lang%3Den&apn=com.tellm.android.app&amv=5.116.0
Obtained oob token 4W6H43itna23hqunAKTIvh6MdHrHoeJm1Oton9LRz0oAAAGCRn7CPg for email bojeme2191@logodez.com
Creating new account.
Creating account with data [...]
>>> status, response = j.get_user_config()
>>> print(response.get('user_blocked')) 
True
ExTBH commented 2 years ago

my attempt with the new branch

edit1: email seems to be sensitive to spaces, it needs to be stripped from spaces that comes after the .[tld] part edit2; tried different temp mail, also banned

edit3: In here, client_id is "client_id": "81e8a76e-1e02-4d17-9ba0-8a7020261b26", however in the logs below 'client_id': 'cd871f92-a23f-4afc-8fff-51ff9dc9184e'.

I think API's are separated now, every platform has different keys, we should probably fill all the fields filled in the logged requests

lat, lng, city, country =  23.175, 50.1486, "Manama", "BH"

j = jodel_api.JodelAccount(lat=lat, lng=lng, city=city, country=country)
time.sleep(5)
response = j.get_user_config()
print("Blocked ", response.get('user_blocked'))
time.sleep(1)
print("Karma", j.get_karma())
time.sleep(1)
print("Blocked ", response.get('user_blocked'))
No email address is given, please enter it manually:26291aa179@catdogmail.live
No email fetch handler registered, using manual mode
Requested email verification for 26291aa179@catdogmail.live
Please enter the link found in the email:<link>
Obtained oob token 7s2ezDQlh1vE2PnK-1lusERUvO-U-K8-03XzbpKFnYMAAAGCRppLOg for email 26291aa179@catdogmail.live
Creating new account.
Creating account with data {'firebase_uid': 'jtNECbcwmfPGgQVuyKVPpsW8UIE3', 'firebaseJWT': '<JWT>', 'location': {'country': 'BH', 'city': 'Manama', 'loc_coordinates': {'lat': 23.175, 'lng': 50.1486}, 'loc_accuracy': 15.457}, 'device_uid': '<RandomString>', 'language': 'de-DE', 'client_id': 'cd871f92-a23f-4afc-8fff-51ff9dc9184e'}
Blocked  True
Karma (200, {'karma': 100})
Blocked  True
Unbrick commented 2 years ago

Your third edit really did the trick for me there! Using the correct client_id, the accounts do not seem to be banned anymore.

Just pushed the changes, does it work for you?

ExTBH commented 2 years ago

im installing with

pip3 install git+https://github.com/JodelRaccoons/jodel_api.git@android_mail_auth#egg=jodel-api

but it doesn't allow me to set the email now, using same code as before, it just creates an account by itself which is bananed

seems like im getting the main branch, it says ver 7.51 and the iOS client_id

Unbrick commented 2 years ago

I split the accounts into iOSJodelAccount and AndroidJodelAccount. The current default is iOSJodelAccount as it is more easy to use for read only access. Try to use the AndroidJodelAccount like mentioned in the branches readme

Edit: Codeexample

lat, lng, city = 48.834875, 2.344962, "Paris"
 j = jodel_api.AndroidJodelAccount(lat=lat, lng=lng, city=city)
ExTBH commented 2 years ago

works! i get False now, i'll test making a post and update

edit: endpoint might be different

print(j.create_post(message="Test The Jodel_API.", imgpath=None, b64img=None, color=None, ancestor=None, channel=""))

returns, with unbananed account

(477, {'error': 'error', 'metadata': None})
Unbrick commented 2 years ago

477 sounds to me like the request signing is somehow broken. I'll check that tomorrow and will try to verify the signing mechanism.

ExTBH commented 2 years ago

calling below works fine, don't think its signing, i dont own an Android to check

j.get_posts_recent(skip=0, limit=60, after=None, mine=False, hashtag=None, channel=None)

iOS post Request looks like the below link: https://api.jodelapis.com/api/v3/posts?hasDrawing=false&hasHashtag=false

{
  "location" : {
    "loc_coordinates" : {
      "lat" : 26.213154187145772,
      "lng" : 50.557814349952793
    },
    "loc_accuracy" : 3639.623509412248,
    "country" : "BH",
    "city" : "Manama",
    "name" : "unknown"
  },
  "color" : "A867E9",
  "test" : false,
  "channel_id" : "5f8ebbb3fd37e500256f7a67",
  "to_home" : false,
  "section" : "Main",
  "promoted_link" : "",
  "message" : "..."
}
Unbrick commented 2 years ago

Somehow the HMAC calculation seems off. I tested the same requests in BurpSuite (using the HMAC calculator extension) and they work just fine. Even using BurpSuite as a proxy for the python_api works flawlessly. But i can't spot the difference between the two requests:

Signed by BurpSuite:

POST /api/v3/posts/?explorer=False HTTP/1.1
Host: api.jodelapis.com
Accept: */*
Connection: close
User-Agent: Jodel/8.0.1 Dalvik/2.1.0 (Linux; U; Android 16; Pixel 9 Build/AAAA.123456.789)
X-Location: 52.504062;13.386062
X-Timestamp: 2022-07-29T09:54:56Z
Content-Type: application/json; charset=UTF-8
Authorization: Bearer 88495644-abe900e3-ab95baad-b3db-47a4-bee1-ba8e4092bc1a
X-Api-Version: 0.2
X-Client-Type: android_8.0.1
Content-Length: 238
Accept-Encoding: gzip, deflate
X-Authorization: HMAC 50951DEC80310EA812391D5A82A568DAF72E0C73

{"color": "8ABDB0", "location": {"country": "DE", "city": "Berlin", "loc_coordinates": {"lat": 52.504062, "lng": 13.386062}, "loc_accuracy": 15.457}, "ancestor": null, "message": "Hallo zusammen", "channel_id": "5f8ebbb3fd37e500256f7a67"}

which is signed using the following HMAC input parameters:

[+] Signing request to https://api.jodelapis.com:443/api/v3/posts/
    [+] URL parameters: 
    explorer=False
    [+] Timestamp: 2022-07-29T09:54:56Z
    [+] Access token: Bearer 88495644-abe900e3-ab95baad-b3db-47a4-bee1-ba8e4092bc1a
    [+] Location: 52.504062;13.386062
    [+] Constructed HMAC String: POST%api.jodelapis.com%443%/api/v3/posts/%88495644-abe900e3-ab95baad-b3db-47a4-bee1-ba8e4092bc1a%52.504062;13.386062%2022-07-29T09:54:56Z%explorer%False%{"color": "8ABDB0", "location": {"country": "DE", "city": "Berlin", "loc_coordinates": {"lat": 52.504062, "lng": 13.386062}, "loc_accuracy": 15.457}, "ancestor": null, "message": "Hallo zusammen", "channel_id": "5f8ebbb3fd37e500256f7a67"}
    [+] New header:
        Host: api.jodelapis.com
        Accept: */*
        Connection: close
        User-Agent: Jodel/8.0.1 Dalvik/2.1.0 (Linux; U; Android 16; Pixel 9 Build/AAAA.123456.789)
        X-Location: 52.504062;13.386062
        X-Timestamp: 2022-07-29T09:54:56Z
        Content-Type: application/json; charset=UTF-8
        Authorization: Bearer 88495644-abe900e3-ab95baad-b3db-47a4-bee1-ba8e4092bc1a
        X-Api-Version: 0.2
        X-Client-Type: android_8.0.1
        Content-Length: 238
        Accept-Encoding: gzip, deflate
        X-Authorization: HMAC 50951DEC80310EA812391D5A82A568DAF72E0C73

which successfully creates a post. Performing the same request from python:

POST /api/v3/posts/?explorer=False HTTP/1.1
Host: api.jodelapis.com
User-Agent: python-requests / jodel_api 8.0.1 (https://github.com/JodelRaccoons/jodel_api/)
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Authorization: Bearer 88778679-920de650-805418a1-07b7-40ab-9452-d7fb26cf140c
X-Location: 52.5041;13.3861
X-Client-Type: android_8.0.1
X-Api-Version: 0.2
X-Timestamp: 2022-07-29T09:59:39Z
X-Authorization: HMAC ADDE3B615AFE80B6B2610BEEED98DD138F123F5D
Content-Type: application/json; charset=UTF-8
Content-Length: 238

{"color": "8ABDB0", "location": {"country": "DE", "city": "Berlin", "loc_coordinates": {"lat": 52.504062, "lng": 13.386062}, "loc_accuracy": 15.457}, "ancestor": null, "message": "Hallo zusammen", "channel_id": "5f8ebbb3fd37e500256f7a67"}

with the following input parameters:

HMAC String: POST%api.jodelapis.com%443%/api/v3/posts/%88778679-920de650-805418a1-07b7-40ab-9452-d7fb26cf140c%52.5041;13.3861%2022-07-29T09:59:39Z%explorer%false%{"color": "8ABDB0", "location": {"country": "DE", "city": "Berlin", "loc_coordinates": {"lat": 52.504062, "lng": 13.386062}, "loc_accuracy": 15.457}, "ancestor": null, "message": "Hallo zusammen", "channel_id": "5f8ebbb3fd37e500256f7a67"}
Requesting https://api.jodelapis.com/api/v3/posts/
     Endpoint: /v3/posts/
     Payload: {'color': '8ABDB0', 'location': {'country': 'DE', 'city': 'Berlin', 'loc_coordinates': {'lat': 52.504062, 'lng': 13.386062}, 'loc_accuracy': 15.457}, 'ancestor': None, 'message': 'Hallo zusammen', 'channel_id': '5f8ebbb3fd37e500256f7a67'}
     Method: POST
     Headers: {'User-Agent': 'python-requests / jodel_api 8.0.1 (https://github.com/JodelRaccoons/jodel_api/)', 'Authorization': 'Bearer 88778679-920de650-805418a1-07b7-40ab-9452-d7fb26cf140c', 'X-Location': '52.5041;13.3861', 'X-Client-Type': 'android_8.0.1', 'X-Api-Version': '0.2', 'X-Timestamp': '2022-07-29T09:59:39Z', 'X-Authorization': 'HMAC ADDE3B615AFE80B6B2610BEEED98DD138F123F5D', 'Content-Type': 'application/json; charset=UTF-8', 'Accept-Encoding': 'gzip, deflate'}
     Parameters: {'explorer': False}

returns the 477 unknown.

ExTBH commented 2 years ago

can't think of anything for this as i don't know anything about HMAC