133 lines
4.5 KiB
Python

#!/usr/bin/env python3
"""
This is a simple script wrapper for the "remote-auth" discord protocol.
It lets you generate a new discord session on command.
It was made quickly and is very crude and not very clean.
Docs on the protocol: https://github.com/discord-userdoccers/discord-userdoccers/blob/master/pages/remote-authentication/mobile.mdx
Author: https://github.com/bytequill
Made as part of https://github.com/bytequill/smallscripts series
"""
try:
import os, sys, json
import dotenv, requests
from rich.console import Console
except ImportError as e:
print("✘ Could not find package "+e.name+". Please install it from the "+sys.argv[0]+".requirements or if unavailable. use the requirements provided below:\n"+"""requests==2.32.3
rich==14.0.0
python-dotenv==1.1.0""")
exit(1)
API_URL="https://discord.com/api/v9"
DC_TOKEN: str
P_ERR = "[red]✘[/red] "
P_CHK = "[green]✓[/green] "
P_INF = "[blue]I[/blue] "
P_INP = "[yellow]/[/yellow] "
def prompt_bool(con: Console, msg: str, default: bool) -> bool:
yn: str
if default:
yn = "- Y/n "
else:
yn = "- y/N "
res = con.input(msg+yn)
if res == "":
return default
elif res.lower() == "y":
return True
elif res.lower() == "n":
return False
else:
con.print(P_ERR+"Invalid value. Please use '' or y or n")
return prompt_bool(con, msg, default)
def contentfulInput(con: Console, msg: str) -> str:
i = con.input(msg + ": ")
if i and len(i) > 0:
return i
else:
con.print(P_ERR+"Please enter a value. It cannot be blank")
return contentfulInput(con, msg)
def do_dcAPIreq(s: requests.Session, endpoint: str, method: str, body: dict) -> tuple[int, dict]:
r = requests.Request(method, API_URL+endpoint)
if body: r.data = json.dumps(body)
r = r.prepare()
r.headers["authorization"] = DC_TOKEN
if body: r.headers["Content-Type"] = "application/json"
res = s.send(r)
if res.status_code != 204:
try:
return (res.status_code, res.json())
except Exception as e:
return (500, {"err": e})
else:
return (res.status_code, None)
def main():
global DC_TOKEN
con = Console()
s = requests.Session()
dotenv.load_dotenv()
DC_TOKEN = os.getenv("DC_TOKEN")
if DC_TOKEN and len(DC_TOKEN) > 0:
con.print(P_CHK+"Got token from env")
else:
con.print(P_ERR+"Could not get token from env. Create a .env with the variable DC_TOKEN")
DC_TOKEN = con.input(P_INP+"[yellow]Fallback[/yellow] Please enter the token manually. It is reccomended to verify it: ")
if not DC_TOKEN and len(DC_TOKEN) == 0:
exit(1)
con.print(P_INF+"Token is "+DC_TOKEN)
res = prompt_bool(con,P_INP+"Do you want to verify token?", False)
if res:
rcode, rdata = do_dcAPIreq(s, "/users/@me", "GET", None)
if rcode != 200:
con.print(P_ERR+"Could not verify token. Status="+str(rcode))
exit(1)
else:
con.print(P_CHK+"Token verified as working. Username="+rdata["username"]+" id="+rdata["id"])
fingerprint = contentfulInput(con,P_INP+"Please enter remote auth fingerprint")
con.print(P_INF+"Fingerprint is "+fingerprint)
rcode, rdata = do_dcAPIreq(s, "/users/@me/remote-auth", "POST", {"fingerprint": fingerprint})
handshake: str
if rcode != 200:
con.print(P_ERR+"Invalid respose from discord. Status="+str(rcode)+" rdata="+str(rdata))
exit(1)
if rdata["handshake_token"] and len(rdata["handshake_token"]) > 0:
handshake = rdata["handshake_token"]
else:
con.print(P_ERR+"Invalid handshake_token respose from discord. rdata="+str(rdata))
exit(1)
if prompt_bool(con, P_INP+"Are you sure you want to [green]accept[/green] the creation of a new session", True):
rcode, rdata = do_dcAPIreq(s, "/users/@me/remote-auth/finish", "POST", {"handshake_token": handshake, "temporary_token": False})
if rcode != 204:
con.print(P_ERR+"Could not create a new session. status="+str(rcode)+" rdata="+str(rdata))
exit(1)
else:
rcode, rdata = do_dcAPIreq(s, "/users/@me/remote-auth/cancel", "POST", {"handshake_token": handshake})
if rcode != 204:
con.print(P_ERR+"Could not cancel succesfully. status="+str(rcode)+" rdata="+str(rdata))
exit(1)
con.print(P_CHK+"done")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
pass
except Exception:
Console().print_exception()