Skip to content

Instantly share code, notes, and snippets.

@vanyle
Last active November 9, 2024 23:01
Show Gist options
  • Save vanyle/edbdd0c28a0150af3b905b99a4c48f00 to your computer and use it in GitHub Desktop.
Save vanyle/edbdd0c28a0150af3b905b99a4c48f00 to your computer and use it in GitHub Desktop.
Modding the Discord client

Modding the discord client

Disclaimer: Modding the discord client is against Discord's term of service. I'm not responsible if any action is taken against you.

Why modding ?

Modding the client will allow you to customize to:

  • change the appearance of the discord client
  • have script to automaticaly send messages at specific times
  • log messages from a chat into a local file

This guide will explain how to inject js code into the discord client and send messages. I'm assuming you know you to write javascript code and are using Windows. Most of this will also work on Linux and Mac but the directories will not be the same

How to mod discord ?

First install npm and asar

npm can be installed from here: https://nodejs.org/en/ (it's bundled with nodejs)

asar can when be installed with npm install asar -g

Then go to the following directory: %LocalAppData%/Discord/app-<some version>/modules/discord_desktop_core-<number>/discord_desktop_core/ You will find a file named core.asar

asar files work find of like zip files. You should make a backup of the file as we are going to modify it.

To unpack the file, run asar extract core.asar unpacked This will create an unpacked folder. Inside, search for app/mainScreen.js. This is the js file we will edit to inject js code into Discord.

I suggest adding the following lines (but you could add anything else depending on the feature you want):

At line ~350, inside the object mainWindowOptions.webPreferences add the property: nodeIntegration: true. This will allow you to access node js functions from inside discord to write files for example.

At line ~440, in the scope of launchMainAppWindow, add:

const fs = require('fs');
mainWindow.webContents.on('dom-ready', () => {
  setTimeout(() => {
    mainWindow.webContents.executeJavaScript(fs.readFileSync('C:/discord.js') + "");
  }, 3000);
});

This will load the file located at C:/discord.js into the discord client. You can change this path to any path convenient to you.

You will then need to repack this code into the asar file. To do this, run:

asar pack unpacked core.asar

This will override the core.asar file so making a backup is important here.

When, create the js file at C:/discord.js and add the following inside: (You can customize this to do other stuff)

// Discord requires a authorization token to send messages.
// We will fetch this token by listening to request discord makes
let authTokenObtained = false;
let insideChannelRequest = false;
let authToken = "";
let xsuperToken = "";

// We override the default AJAX request to listen to the requests discord makes.
var proxied1 = window.XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function() {
	console.log(arguments[1]);
	if(arguments[1].startsWith('https://discordapp.com/api/v6/channels')){
		if(!authTokenObtained){
			insideChannelRequest = true;
		}
		(function(url){
			setTimeout(function(){ // wait for the ui to update.
				let elements = document.getElementsByTagName('h3');
       				// We update the UI to display the channel name.
				if(elements.length >= 1 && elements[0].style.userSelect !== "text"){ // add channel URL to name
					elements[0].style.userSelect = "text";
					elements[0].innerHTML += " | "+url.substring("https://discordapp.com/api/v6/channels".length);
				}
			},1000);
		})(arguments[1]);
	}
	return proxied1.apply(this, [].slice.call(arguments));
};

let proxied2 = window.XMLHttpRequest.prototype.setRequestHeader;
window.XMLHttpRequest.prototype.setRequestHeader = function() {
	if(insideChannelRequest && !authTokenObtained && arguments[0] === "Authorization"){
		authToken = arguments[1];
		authTokenObtained = true;
		console.log("Token Obtained.");
	}
	if(insideChannelRequest && arguments[0] == "X-Super-Properties"){
		xsuperToken = arguments[1];
		console.log("X-Super-Properties updated.")
	}
	// console.log( arguments );
	return proxied2.apply(this, [].slice.call(arguments));
};

// We can now define a sendMessage function that behaves exactly like discord:
function sendMessage(msg,channel){
	if(!authTokenObtained){
		console.log("Unable to send message without authToken.");
		console.log("Try typing something in a chat to obtain the token.");
	}
	channel_url = `https://discordapp.com/api/v6/channels/${channel}/messages`;

	request = new XMLHttpRequest();
	request.withCredentials = true;
	request.open("POST", channel_url);
	request.setRequestHeader("Content-Type", "application/json");
	request.setRequestHeader("Authorization", authToken);
	request.setRequestHeader("X-Super-Properties", xsuperToken);
	request.send(JSON.stringify({ content: msg, tts: false }));
}

Now, once you reload discord, you can see the channel id name of somebody next to their username. Also, when opening the console (with Ctrl+Shift+I) inside discord, you can run: sendMessage("<your message here>","<the channel id here>"); which will send a message in the corresponding channel.

You can use the same stuff to listen to incomming messages (you override the AJAX request callbacks to get access to the messages fetched by discord) You can also edit the discord.js file to change the css. The code above already does that to make usernames selectable.

Now, you can write in the console something like for example:

setTimeout(function(){
  sendMessage("I'm still online, I am not afk","<the channel id>");
},1000 * 60 * 60);

to send a message in one hour. You can get creative and do all sort of stuff with this.

This concludes this guide. Have fun.

@Trebossalol
Copy link

Does still work

@Paradox-77
Copy link

Paradox-77 commented Jan 9, 2022

The dom-ready event never seems to trigger for me, any idea why?
I have placed it at the end of the the launchMainAppWindow function

@Trebossalol
Copy link

Just follow the instruction, that'll work. When it works, you can edit stuff.
Oh and btw, if you want the authtoken collected in the variable, that won't work for some reason (at least I experienced that), but if you set the variable insideChannelRequest by default to true you will get the authtoken at some point after sending a message. Happy hacking

@whoisShepherd
Copy link

Is there any documentation for the different kinds of requests that can be made? I'm trying to alter the discord.js file to change my current status.

@Paradox-77
Copy link

The CSP (Content Security Policy) allows you to access the discord API. You should have no problem doing that.

@whoisShepherd
Copy link

I looked through the CSP API, but I wasn't able to find a way to set a custom status using a XMLHttpRequest. How would I modify

        request = new XMLHttpRequest();
	request.withCredentials = true;
	request.open("POST", channel_url);
	request.setRequestHeader("Content-Type", "application/json");
	request.setRequestHeader("Authorization", authToken);
	request.setRequestHeader("X-Super-Properties", xsuperToken);
	request.send(JSON.stringify({ content: msg, tts: false }));

To change my status instead of sending a message?

@goesbyabhi
Copy link

Just follow the instruction, that'll work. When it works, you can edit stuff. Oh and btw, if you want the authtoken collected in the variable, that won't work for some reason (at least I experienced that), but if you set the variable insideChannelRequest by default to true you will get the authtoken at some point after sending a message. Happy hacking

Is it still working for you?

@Trebossalol
Copy link

Just follow the instruction, that'll work. When it works, you can edit stuff. Oh and btw, if you want the authtoken collected in the variable, that won't work for some reason (at least I experienced that), but if you set the variable insideChannelRequest by default to true you will get the authtoken at some point after sending a message. Happy hacking

Is it still working for you?

Yes it is still working for me, and I don't think discord will patch this anytime. But I am sorry I can not provide any help with this.

@goesbyabhi
Copy link

Just follow the instruction, that'll work. When it works, you can edit stuff. Oh and btw, if you want the authtoken collected in the variable, that won't work for some reason (at least I experienced that), but if you set the variable insideChannelRequest by default to true you will get the authtoken at some point after sending a message. Happy hacking

Is it still working for you?

Yes it is still working for me, and I don't think discord will patch this anytime. But I am sorry I can not provide any help with this.

No it's dwdw i figured it out

@kumina-dev
Copy link

Hello, I got an error saying "A fatal Javascript error occured"
"TypeError: Cannot read property 'webContents' of null"

@kumina-dev
Copy link

Hello, I got an error saying "A fatal Javascript error occured" "TypeError: Cannot read property 'webContents' of null"

Got it fixed by rearranging the code in mainScreen.js

@dec04
Copy link

dec04 commented May 27, 2022

Hello. core.asar is electron wrapper and app.asar is app front? I understand correctly?

@dec04
Copy link

dec04 commented May 27, 2022

How i can send request to another domain, not discord? I get cors error, when i try to send request to another domain, like google . com

@aindrigo
Copy link

aindrigo commented Jun 9, 2022

why doesn't require or import work? i enabled nodeIntegration and it did nothing

@vwv-source
Copy link

Could anyone help? require doesn't work and i can't write files even after enabling nodeIntegration

@dec04
Copy link

dec04 commented Oct 5, 2022

For me, import or require dont work, after enable nodeIntegration: true

@ProxxDev2
Copy link

I keep getting this error, please help.
image

@ProxxDev2
Copy link

nevermind i fixed it

@dec04
Copy link

dec04 commented Oct 5, 2022

what fix? you can share with us?

@ProxxDev2
Copy link

@dec04 I removed the dom-ready thing and it works, by the way i put it out of the if platform linux thing scope

@FunWithAlbiYT
Copy link

FunWithAlbiYT commented Oct 22, 2022

Make sure to put the code that runs the code from discord.js at line ~470
image

@FunWithAlbiYT
Copy link

If you are getting error code 401 when trying to send a message, replace discordapp.com with discord.com.

@FunWithAlbiYT
Copy link

Make sure to replace v6 with v9 too.

@MissingReports
Copy link

can someone give me an example on how to listen for messages using this? also is it possible to edit the message contents that's showing up?

@DanMitchel
Copy link

Antoine, how I contact you? I’d pay for your service help

@vanyle
Copy link
Author

vanyle commented Oct 26, 2023

Hi Dan! I see you just created your account. Could you prove to me that you are not a bot ? We can chat using Telegram, I just need your telegram handle to contact you.

@DanMitchel
Copy link

hi Antoine, lol I’m not bot, I just created GitHub account when I read your code post so I did to contact you, you might help me with the coding I wanna do. Send me your telegram link so I can add you.

@DanMitchel
Copy link

here’s my telegram https://t.me/Dan_mitchel

@oulol
Copy link

oulol commented Dec 6, 2023

great, now how do i access node fuctions when i want to write a file for example?

@LazerW33nie
Copy link

LazerW33nie commented Jan 25, 2024

To address everyone's issues:

  • Inject your script from the very bottom of mainScreenPreload.js instead of mainScreen.js. This allows you to use require()
  • Change v6 to v9 and discordapp to discord.
  • DO NOT repack core.asar without ending the Discord process first. Make sure its not running in the background.

The updated load event you'll need for mainScreenPreload.js:

window.addEventListener('DOMContentLoaded', () => {
  setTimeout(() => {
    const fs = require('fs');
    const script = fs.readFileSync('C:/Discord.js, 'utf8');
    eval(script);
  }, 3000);
});

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