Created
May 7, 2024 21:20
-
-
Save glyzinie/52122bdd0d1834238f94c4121afce158 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Hono } from 'hono'; | |
import { InteractionType, InteractionResponseType } from 'discord-api-types/v9'; | |
// Function to convert a hex string to binary format | |
function hex2bin(hex: string): Uint8Array { | |
const buf = new Uint8Array(Math.ceil(hex.length / 2)); | |
for (let i = 0; i < buf.length; i++) { | |
buf[i] = parseInt(hex.substr(i * 2, 2), 16); | |
} | |
return buf; | |
} | |
// Function to import the ED25519 public key | |
async function importPublicKey(publicKeyHex: string): Promise<CryptoKey> { | |
const publicKeyData = hex2bin(publicKeyHex); | |
return crypto.subtle.importKey( | |
'raw', | |
publicKeyData, | |
{ | |
name: 'NODE-ED25519', | |
namedCurve: 'NODE-ED25519', | |
public: true, | |
}, | |
true, | |
['verify'] | |
); | |
} | |
// Function to verify the ED25519 signature | |
async function verifySignature( | |
publicKey: CryptoKey, | |
signature: Uint8Array, | |
timestamp: string, | |
body: string | |
): Promise<boolean> { | |
const encoder = new TextEncoder(); | |
const data = encoder.encode(timestamp + body); | |
return crypto.subtle.verify( | |
'NODE-ED25519', | |
publicKey, | |
signature, | |
data | |
); | |
} | |
const PUBLIC_KEY_HEX = 'YOUR_DISCORD_PUBLIC_KEY_HEX'; | |
const publicKeyPromise = importPublicKey(PUBLIC_KEY_HEX); | |
// Initialize the Hono app | |
const app = new Hono(); | |
// Middleware to verify the request signature | |
app.use('/interactions', async (c, next) => { | |
const signature = c.req.header('X-Signature-Ed25519'); | |
const timestamp = c.req.header('X-Signature-Timestamp'); | |
const body = await c.req.text(); | |
if (!signature || !timestamp) { | |
return c.text('Missing signature or timestamp', 401); | |
} | |
const isVerified = await verifySignature( | |
await publicKeyPromise, | |
hex2bin(signature), | |
timestamp, | |
body | |
); | |
if (!isVerified) { | |
return c.text('Invalid request signature', 401); | |
} | |
// Store the parsed body for use in the next middleware or handler | |
c.req.body = JSON.parse(body); | |
return next(); | |
}); | |
// Route handler | |
app.post('/interactions', async (c) => { | |
const data = c.req.body; | |
if (data.type === InteractionType.Ping) { | |
return c.json({ type: InteractionResponseType.Pong }); | |
} | |
return c.text('Invalid request', 400); | |
}); | |
// Export the fetch method of the app | |
export default { | |
fetch: app.fetch.bind(app), | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment