npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

insomnia-plugin-discord-auth

v1.0.1

Published

When making WebHook requests to a Discord App, the Discord service signs the requests using the [Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519) digital signature scheme. See [Discord Security and Authorization](https://discord.com/developers/docs/

Downloads

2

Readme

Insomnia Plugin Discord Auth

When making WebHook requests to a Discord App, the Discord service signs the requests using the Ed25519 digital signature scheme. See Discord Security and Authorization.

This Plugin makes it easy to test your Discord server, by automatically signing API requests using the Ed25519 scheme and a given secret.

Discord don't share their signing secret with you, so I've also included the code required to generate a new secret/public key pair to use for testing.

And some sample code that would run on your Discord server to validate the signature.

🚀 Installation

  • In Insomnia, Access the Application / Preferences menu and then select the Plugins tab, enter the plugin name insomnia-plugin-discord-auth and click Install Plugin.

  • After installing the plugin click on Enable

Enable Plugin

Generating a Key Pair

Discord do not share their secret key, so for testing you will need to generate your own key pair. A helper NodeJS app generate-keypair.js is included:

> node generate-keypair.js
secretKey: cdc8d007d9d4e181f94a0c2a224c6848b1c1896c9c6645c867b2ddbe965a844b07f3be2df0be6b4befca007f190468c3c1a640dbb4d50beaa8d98e4671c0e9db
publicKey: 07f3be2df0be6b4befca007f190468c3c1a640dbb4d50beaa8d98e4671c0e9db

Adding Environment Var

  • Create an Environment variable called ED25519_SECRET_KEY with a valid hex-encoded secret from a ED25519 key-pair. It is recommended that you put this in a Private Environment so that the key isn't exported or synced by Insomnia.

Add Env Var

Add Header to each Request

  • Add a custom Header called x-signature-ed25519 with the value of #DISCORD#. This tells the plug-in to intercept this request, and add the required signing header

Add Header

Send a Request

  • Click on Send, and the plug-in will intercept the request, add the required x-signature-ed25519 and x-signature-timestamp headers, before the request is sent to the destination server

Send Request

View Logs

You can see from the Timeline view that the plug-in is successfully adding the signature and timestamp headers to the request

Request Log

Example Bot Code

I'm also including some sample code for the Bot server receiving this request. It requires the testing secret key that you generated above, and also the secret from the Discord App web pages. You then run it with an environment variable of ENV=DEV for testing, or remove the variable for production.

- Sorry - This is cut-paste from my app code, and hasn't been run/tested as a standalone app

const express = require('express');
const dfcbp = require('./dfc-bot-plus.js')
const nacl = require('tweetnacl');

// Constants
const PORT = 8080;
const HOST = '0.0.0.0';

// App
const app = express();

// Discord enumerations
const InteractionResponseType = {
    Pong: 1,
    ChannelMessageWithSource: 4,
    DeferredChannelMessageWithSource: 5
  };

const InteractionType = {
    Ping: 1,
    ApplicationCommand: 2
};

// Use the Raw handler, as we need to create/compare the signature of the raw body
app.use(express.raw({"type":"*/*"}));

// Main POST handler
app.post('/discord-bot/', async (req,res) => {
  const signatureEd25519 = req.get('x-signature-ed25519');
  const signatureTimestamp = req.get('x-signature-timestamp');
  const requestBody = req.body.toString('utf8');

  try {
    res.status(200).send(
      await discordHandler(requestBody, signatureEd25519, signatureTimestamp));

  } catch (err) {
    res.status(500).send(err.message)
  }
});

// Start the listener
app.listen(PORT, HOST);

console.log(`Running on http://${HOST}:${PORT}`);

// Main Discord Request Handler
async discordHandler(requestBody, signatureEd25519, signatureTimestamp){

    // Validate Input
    if (signatureEd25519 == null ||
        signatureTimestamp == null ||
        requestBody == null)
    {
        throw new Error("Invalid Parameters");
    }

    // Parse the Body
    const body = JSON.parse(requestBody);
    const discordRequestType = body.type;
    const bodyData = body.data;

    // Validate Body
    if (discordRequestType == null || 
        !Number.isInteger(discordRequestType))
    {
        throw new Error("Invalid Discord Request Type");
    }

    if (process.env.ENV == "DEV") {
        // ############## THE DEVELOPMENT PUBLIC KEY YOU GENERATED  ABOVE ##########################
        var signaturePublicKey = "07f3be2df0be6b4befca007f190468c3c1a640dbb4d50beaa8d98e4671c0e9db";
    } else {
        // ############## THE PRODUCTION PUBLIC KEY FROM DISCORD  ##################################
        var signaturePublicKey = "NEED TO REPLACE";
    }

    var isVerified = nacl.sign.detached.verify(
        Buffer.from(signatureTimestamp + requestBody),
        Buffer.from(signatureEd25519, 'hex'),
        Buffer.from(signaturePublicKey, 'hex')
    );

    if (!isVerified) {
        console.debug("Signature FAILED verification"); 
        throw new Error("Invalid Request Signature");
    }
    else {
        console.debug("Signing verified"); 
    }

    // Handle Events
    switch (discordRequestType) {

        // === PING Response
        case InteractionType.Ping:
            return JSON.stringify({"type": InteractionResponseType.Pong});

        // === Normal Response
        case InteractionType.ApplicationCommand:
            // DO SOMETHING ELSE
            return "";
    }
}