Native NodeJS Code
Plugins run in the browser sandbox by default. This means they only have access to web APIs as if they were running in a regular web browser.
Sometimes plugins may need access to the NodeJS environment. Some examples include
- Bypassing Content Security Policy (CSP) or Cross-Origin Resource Sharing (CORS) restrictions
- Interfacing with other programs
- Reading specific files from the filesystem
However, this should only be used as a last resort if no other alternatives are available! For example, the following are not valid use cases:
- Storing data — Instead, use Vencord Settings or IndexedDB (via DataStore API)
- Reading or writing arbitrary files — This poses severe security risks. Use web file picker/saving instead
Defining Native Plugin Code
Section titled “Defining Native Plugin Code”Plugin Natives are defined via the native.ts file in your plugin folder. This file will be ran in the NodeJS environment. This file can export functions to make them available via IPC.
Any function exported from here
- will be callable via VencordNative as demonstrated below
- will always return a Promise
- will receive the invoke event as first argument. You do not pass this event from the browser code.
export function add(event: IpcMainInvokeEvent, x: number, y: number) { return x + y;}import definePlugin, { PluginNative } from "@utils/types";
const Native = VencordNative.pluginHelpers.MyPluginName as PluginNative<typeof import("./native")>;
export default definePlugin({ name: "MyPluginName", async start() { console.log(await Native.add(1, 2)); // logs 3 }})Bypassing Content Security Policy (CSP) and Cross-Origin Resource Sharing (CORS)
Section titled “Bypassing Content Security Policy (CSP) and Cross-Origin Resource Sharing (CORS)”CSP and CORS are web security mechanisms that restrict which resources can be loaded and from which websites.
They are pretty similar with one key difference:
- CSP is set by the current website and enforced by the Browser. Discord tells the Browser “only allow resources from discord.com, tenor.com, …”. Then if code tries to load
example.com, the browser blocks it - CORS is set by the server hosting the resource and enforced by the Browser. The server at
example.comsays “only allow example.com to access my resources”. Then the browser blocks discord.com from requesting it.
In other words, CSP is controlled by us, while CORS is controlled by the server hosting the resource.
To bypass CSP, just add the target server to the CspPolicies in your native.ts file:
import { ConnectSrc, CspPolicies } from "@main/csp";
CspPolicies["example.com"] = ConnectSrc; // or MediaSrc, etcconst res = await fetch("https://example.com/endpoint"); // now allowedCORS however cannot be modified by us, as the Server controls it. Instead, you must send the request from your native code, as NodeJS does not enforce CORS:
const API_HOST = "https://example.com";
export async function fetchCoolAPI(_event, endpoint: string) { // endpoint argument is untrusted! Validate it before using it. const url = new URL(endpoint, API_HOST); if (url.origin !== API_HOST) { throw new Error("Invalid endpoint"); }
const res = await fetch(url.toString()); return await res.json();}import definePlugin, { PluginNative } from "@utils/types";
const Native = VencordNative.pluginHelpers.MyPluginName as PluginNative<typeof import("./native")>;
export default definePlugin({ name: "MyPluginName", async start() { console.log(await Native.fetchCoolAPI("/some-endpoint")); // logs the JSON response from https://example.com/some-endpoint }})