Skip to content

Instantly share code, notes, and snippets.

@Redict
Last active May 5, 2024 04:25
Show Gist options
  • Save Redict/f6aa178890ef2e4f0f1e821d04d88773 to your computer and use it in GitHub Desktop.
Save Redict/f6aa178890ef2e4f0f1e821d04d88773 to your computer and use it in GitHub Desktop.
WolframAlpha Pro free and unlimited access to API
import requests
from hashlib import md5
from urllib.parse import urlsplit, urlencode, unquote_plus
headers = {"User-Agent": "Wolfram Android App"}
APPID = "3H4296-5YPAGQUJK7" # Mobile app AppId
SERVER = "api.wolframalpha.com"
SIG_SALT = "vFdeaRwBTVqdc5CL" # Mobile app salt
s = requests.Session()
s.headers.update(headers)
def calc_sig(query):
"""
Calculates WA sig value(md5(salt + concatenated_query)) with pre-known salt
@query
In format of "input=...&arg1=...&arg2=..."
"""
params = list(filter(lambda x: len(x) > 1, list(map(lambda x: x.split("="), query.split("&"))))) # split string by & and = and remove empty strings
params.sort(key = lambda x: x[0]) # sort by the key
s = SIG_SALT
# Concatenate query together
for key, val in params:
s += key + val
s = s.encode("utf-8")
return md5(s).hexdigest().upper()
def craft_signed_url(url):
"""
Craft valid signed URL if parameters known
@query
In format of "https://server/path?input=...&arg1=...&arg2=..."
"""
(scheme, netloc, path, query, _) = urlsplit(url)
_query = {"appid": APPID}
_query.update(dict(list(filter(lambda x: len(x) > 1, list(map(lambda x: list(map(lambda y: unquote_plus(y), x.split("="))), query.split("&")))))))
query = urlencode(_query)
_query.update({"sig": calc_sig(query)}) # Calculate signature of all query before we set "sig" up.
return f"{scheme}://{netloc}{path}?{urlencode(_query)}"
def basic_test(query_part):
"""
Simple PoC
@query_part
Example is "input=%url_encoded_string%&arg1=...&arg2=..."
https://products.wolframalpha.com/api/documentation/#formatting-input
"""
r = s.get(craft_signed_url(f"https://{SERVER}/v2/query.jsp?{query_part}"))
if r.status_code == 200:
return r.text
else:
raise Exception(f"Error({r.status_code}) happened!\n{r.text}")
if __name__ == "__main__":
print(basic_test("input=y%27+%3D+y%2F%28x%2By%5E3%29&podstate=Solution__Step-by-step+solution&format=plaintext&output=json"))
@AngeloD2022
Copy link

How did you obtain the salt value? Not sure if they've obfuscated it since, but from looking at it, it's not clearly defined. Anyhow, your script still works and thank you.

@Redict
Copy link
Author

Redict commented Feb 11, 2021

@AngeloD2022 it is located as plaintext in apk file

@Wowzerf
Copy link

Wowzerf commented Feb 20, 2021

Hello! New here I was wondering how do I set it up once I downloaded the zip file on my computer?

@Redict
Copy link
Author

Redict commented Feb 20, 2021

Hello! New here I was wondering how do I set it up once I downloaded the zip file on my computer?

There is my website for it, but it's currently not working, i'll fix it as soon as possible

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment