itschasa/Discord-Backup

Linux Support - Puppeteer for Token Fetching

Novattz opened this issue · 3 comments

Collect discord tokens with puppeteer for linux users.

Install these in the same directory as Discord-Backup!

  • npm install puppeteer @gilgames/discord-detours

Make a javascript file in the same directory as Discord-Backup.

  • sudo nano index.js

Initial login script

  • Place this script in index.js and log in to discord via a non-headless browser:
let puppeteer = require('puppeteer');
const detours = require("@gilgames/discord-detours");

(async () => {
    const browser = await puppeteer.launch({ userDataDir: './user_data', headless: false });
    const page = await browser.newPage();
    await page.goto('https://discord.com/channels/@me');
    await page.setViewport({ width: 1080, height: 1024 });
    const serializedAPI = detours.serializeModule(detours.api);
    await page.evaluate(detours.injectModule, serializedAPI);
    const token = await page.evaluate(() => window.discordDetours.findFunctionByName("getToken")());
    console.log(token);
    await browser.close(); 
})();
  • After logging in, replace the initial login script in index.js with this one to automatically fetch the token on subsequent runs:
let puppeteer = require('puppeteer');
const detours = require("@gilgames/discord-detours");

(async () => {
    const browser = await puppeteer.launch({ userDataDir: './user_data' });
    const page = await browser.newPage();
    await page.goto('https://discord.com/channels/@me');
    await page.setViewport({ width: 1080, height: 1024 });
    const serializedAPI = require("@gilgames/discord-detours").serializeModule(require("@gilgames/discord-detours").api);
    await page.evaluate(detours.injectModule, serializedAPI);
    const token = await page.evaluate(() => window.discordDetours.findFunctionByName("getToken")());
    const user_info = await page.evaluate(() => {
        const usernameElement = document.querySelector('span[class="text-gray-400 font-semibold"]');
        const username = usernameElement ? usernameElement.innerText.split('#')[0] : 'Unknown';
        const discriminator = usernameElement ? usernameElement.innerText.split('#')[1] : '0000';
        return { username, discriminator };
    });
    console.log(JSON.stringify({ token, username: user_info.username, discriminator: user_info.discriminator }));
    await browser.close();
})();
  • Modified fetch_tokens.py
import subprocess
import json

def fetch():
    try:
        result = subprocess.run(['node', 'index.js'], capture_output=True, text=True, check=True)
        token_data = json.loads(result.stdout)
        return [[token_data['token'], f"{token_data['username']}#{token_data['discriminator']}", token_data['token'], "Discord"]]
    except subprocess.CalledProcessError as e:
        print(f"Failed to execute script: {e}")
        return []
    except json.JSONDecodeError as e:
        print(f"Error decoding JSON from script output: {e}")
        return []
  • This will now allow you to automatically backup and restore using the built in choices in main.py without having to manually get your token.

this does not have to be done in javascript, id rather keep all the code in the same language for something like this, so a single binary can be used with ease

this does not have to be done in javascript, id rather keep all the code in the same language for something like this, so a single binary can be used with ease

Interacting with the keyring that stores the token is outside of what i was able to do and i settled for this instead. while i do know its not an ideal approach its better then having nothing at all for a program that is really useful for users.

Alternative approach if people would like to only use python:

import os
import plyvel

DATABASE_PATH = os.path.expanduser('~/.config/discord/Local Storage/leveldb/')

def open_db():
    try:
        db = plyvel.DB(DATABASE_PATH, create_if_missing=False)
        return db
    except Exception as e:
        raise Exception(f"Error opening database: {e}")

def get_token():
    try:
        db = open_db()
        key = b'\x5f\x68\x74\x74\x70\x73\x3a\x2f\x2f\x64\x69\x73\x63\x6f\x72\x64\x61\x70\x70\x2e\x63\x6f\x6d\x00\x01\x74\x6f\x6b\x65\x6e'
        token = db.get(key)
        if token is None:
            raise KeyError("Token not found in database")
        return token.decode('utf-8')
    finally:
        db.close()

def fetch():
    try:
        print(get_token())
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    fetch()

Although doing token checking wasn't something i was able to figure out. Requires plyvel