This commit is contained in:
DjDeveloperr 2021-03-14 15:12:05 +05:30
parent e65fa8fded
commit dcb07a9aaa
3 changed files with 78 additions and 0 deletions

View File

@ -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<void>
}): Promise<boolean | Interaction> {
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<boolean> {
const signature = req.headers.get('x-signature-ed25519')
const timestamp = req.headers.get('x-signature-timestamp')

View File

@ -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,

44
src/test/slash-http.ts Normal file
View File

@ -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<void> =>
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!'
}
})
})