From dcb07a9aaab4cc769c09df6214a06b574b539c4e Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Sun, 14 Mar 2021 15:12:05 +0530 Subject: [PATCH] x --- src/models/slashClient.ts | 32 ++++++++++++++++++++++++++++ src/structures/slash.ts | 2 ++ src/test/slash-http.ts | 44 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 src/test/slash-http.ts diff --git a/src/models/slashClient.ts b/src/models/slashClient.ts index 6917ce8..7e9b581 100644 --- a/src/models/slashClient.ts +++ b/src/models/slashClient.ts @@ -1,6 +1,7 @@ import { Guild } from '../structures/guild.ts' import { Interaction } from '../structures/slash.ts' import { + InteractionPayload, InteractionType, SlashCommandChoice, SlashCommandOption, @@ -369,6 +370,7 @@ export interface SlashOptions { } const encoder = new TextEncoder() +const decoder = new TextDecoder('utf-8') export class SlashClient { id: string | (() => string) @@ -503,6 +505,7 @@ export class SlashClient { cmd.handler(interaction) } + /** Verify HTTP based Interaction */ async verifyKey( rawBody: string | Uint8Array, signature: string | Uint8Array, @@ -521,6 +524,35 @@ export class SlashClient { return edverify(signature, fullBody, this.publicKey).catch(() => false) } + /** Verify [Deno Std HTTP Server Request](https://deno.land/std/http/server.ts) and return Interaction */ + async verifyServerRequest(req: { + headers: Headers + method: string + body: Deno.Reader + respond: (options: { + status?: number + body?: string | Uint8Array + }) => Promise + }): Promise { + if (req.method.toLowerCase() !== 'post') return false + + const signature = req.headers.get('x-signature-ed25519') + const timestamp = req.headers.get('x-signature-timestamp') + if (signature === null || timestamp === null) return false + + const rawbody = await Deno.readAll(req.body) + const verify = await this.verifyKey(rawbody, signature, timestamp) + if (!verify) return false + + try { + const payload: InteractionPayload = JSON.parse(decoder.decode(rawbody)) + const res = new Interaction(this as any, payload, {}) + return res + } catch (e) { + return false + } + } + async verifyOpineRequest(req: any): Promise { const signature = req.headers.get('x-signature-ed25519') const timestamp = req.headers.get('x-signature-timestamp') diff --git a/src/structures/slash.ts b/src/structures/slash.ts index 388aa56..a564a30 100644 --- a/src/structures/slash.ts +++ b/src/structures/slash.ts @@ -41,6 +41,7 @@ export interface InteractionResponse { } export class Interaction extends SnowflakeBase { + /** This will be `SlashClient` in case of `SlashClient#verifyServerRequest` */ client: Client type: number token: string @@ -50,6 +51,7 @@ export class Interaction extends SnowflakeBase { guild: Guild member: Member _savedHook?: Webhook + _respond?: (data: InteractionResponsePayload) => unknown constructor( client: Client, diff --git a/src/test/slash-http.ts b/src/test/slash-http.ts new file mode 100644 index 0000000..02f9836 --- /dev/null +++ b/src/test/slash-http.ts @@ -0,0 +1,44 @@ +import { SlashClient } from '../../mod.ts' +import { SLASH_ID, SLASH_PUB_KEY, SLASH_TOKEN } from './config.ts' +import { listenAndServe } from 'https://deno.land/std@0.90.0/http/server.ts' + +const slash = new SlashClient({ + id: SLASH_ID, + token: SLASH_TOKEN, + publicKey: SLASH_PUB_KEY +}) + +await slash.commands.bulkEdit([ + { + name: 'ping', + description: 'Just ping!' + } +]) + +const options = { port: 8000 } +console.log('Listen on port: ' + options.port.toString()) +listenAndServe(options, async (req) => { + const verify = await slash.verifyServerRequest(req) + if (verify === false) + return req.respond({ status: 401, body: 'not authorized' }) + + const respond = async (d: any): Promise => + req.respond({ + status: 200, + body: JSON.stringify(d), + headers: new Headers({ + 'content-type': 'application/json' + }) + }) + + const body = JSON.parse( + new TextDecoder('utf-8').decode(await Deno.readAll(req.body)) + ) + if (body.type === 1) return await respond({ type: 1 }) + await respond({ + type: 4, + data: { + content: 'Pong!' + } + }) +})