itschasa / Discord-Backup

Backup and Restore your Discord Account (Servers, Friends + more) in minutes!
GNU General Public License v3.0
270 stars 19 forks source link

Linux Support - Puppeteer for Token Fetching #35

Open Novattz opened 5 months ago

Novattz commented 5 months ago

Collect discord tokens with puppeteer for linux users.

Install these in the same directory as Discord-Backup!

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

Initial login script

(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:
```javascript
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();
})();

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.
itschasa commented 5 months ago

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

Novattz commented 5 months ago

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.

Novattz commented 5 months ago

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