From 2b46b389085748f4d9fb443dcda8d38cdab43530 Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Sun, 4 Apr 2021 10:21:39 +0530 Subject: [PATCH] encoding util --- src/gateway/index.ts | 13 ++-- src/models/slashClient.ts | 131 ++++++++++++++++++++------------------ src/structures/message.ts | 5 +- src/utils/encoding.ts | 10 +++ 4 files changed, 91 insertions(+), 68 deletions(-) create mode 100644 src/utils/encoding.ts diff --git a/src/gateway/index.ts b/src/gateway/index.ts index 1d672af..f80dfa5 100644 --- a/src/gateway/index.ts +++ b/src/gateway/index.ts @@ -18,6 +18,7 @@ import { delay } from '../utils/delay.ts' import { VoiceChannel } from '../structures/guildVoiceChannel.ts' import { Guild } from '../structures/guild.ts' import { HarmonyEventEmitter } from '../utils/events.ts' +import { decodeText } from '../utils/encoding.ts' export interface RequestMembersOptions { limit?: number @@ -89,7 +90,7 @@ export class Gateway extends HarmonyEventEmitter { } if (data instanceof Uint8Array) { data = unzlib(data) - data = new TextDecoder('utf-8').decode(data) + data = decodeText(data) } const { op, d, s, t }: GatewayResponse = JSON.parse(data) @@ -385,8 +386,8 @@ export class Gateway extends HarmonyEventEmitter { channel === undefined ? null : typeof channel === 'string' - ? channel - : channel?.id, + ? channel + : channel?.id, self_mute: voiceOptions.mute === undefined ? false : voiceOptions.mute, self_deaf: voiceOptions.deaf === undefined ? false : voiceOptions.deaf } @@ -427,7 +428,11 @@ export class Gateway extends HarmonyEventEmitter { } close(code: number = 1000, reason?: string): void { - this.debug(`Closing with code ${code}${reason !== undefined && reason !== '' ? ` and reason ${reason}` : ''}`) + this.debug( + `Closing with code ${code}${ + reason !== undefined && reason !== '' ? ` and reason ${reason}` : '' + }` + ) return this.websocket?.close(code, reason) } diff --git a/src/models/slashClient.ts b/src/models/slashClient.ts index acc38c7..0ff8c42 100644 --- a/src/models/slashClient.ts +++ b/src/models/slashClient.ts @@ -19,7 +19,8 @@ import { RESTManager } from './rest.ts' import { SlashModule } from './slashModule.ts' import { verify as edverify } from 'https://deno.land/x/ed25519@1.0.1/mod.ts' import { User } from '../structures/user.ts' -import { HarmonyEventEmitter } from "../utils/events.ts" +import { HarmonyEventEmitter } from '../utils/events.ts' +import { encodeText, decodeText } from '../utils/encoding.ts' export class SlashCommand { slash: SlashCommandsManager @@ -94,8 +95,8 @@ function createSlashOption( data.choices === undefined ? undefined : data.choices.map((e) => - typeof e === 'string' ? { name: e, value: e } : e - ) + typeof e === 'string' ? { name: e, value: e } : e + ) } } @@ -139,15 +140,15 @@ export type SlashOptionCallable = (o: typeof SlashOption) => SlashCommandOption export type SlashBuilderOptionsData = | Array | { - [name: string]: - | { - description: string - type: SlashCommandOptionType - options?: SlashCommandOption[] - choices?: SlashCommandChoice[] + [name: string]: + | { + description: string + type: SlashCommandOptionType + options?: SlashCommandOption[] + choices?: SlashCommandChoice[] + } + | SlashOptionCallable } - | SlashOptionCallable - } function buildOptionsArray( options: SlashBuilderOptionsData @@ -155,10 +156,10 @@ function buildOptionsArray( return Array.isArray(options) ? options.map((op) => (typeof op === 'function' ? op(SlashOption) : op)) : Object.entries(options).map((entry) => - typeof entry[1] === 'function' - ? entry[1](SlashOption) - : Object.assign(entry[1], { name: entry[0] }) - ) + typeof entry[1] === 'function' + ? entry[1](SlashOption) + : Object.assign(entry[1], { name: entry[0] }) + ) } /** Slash Command Builder */ @@ -268,8 +269,8 @@ export class SlashCommandsManager { guild === undefined ? this.rest.api.applications[this.slash.getID()].commands : this.rest.api.applications[this.slash.getID()].guilds[ - typeof guild === 'string' ? guild : guild.id - ].commands + typeof guild === 'string' ? guild : guild.id + ].commands const payload = await route.post(data) @@ -277,8 +278,8 @@ export class SlashCommandsManager { typeof guild === 'object' ? guild : guild === undefined - ? undefined - : await this.slash.client?.guilds.get(guild) + ? undefined + : await this.slash.client?.guilds.get(guild) const cmd = new SlashCommand(this, payload, _guild) cmd._guild = @@ -297,8 +298,8 @@ export class SlashCommandsManager { guild === undefined ? this.rest.api.applications[this.slash.getID()].commands[id] : this.rest.api.applications[this.slash.getID()].guilds[ - typeof guild === 'string' ? guild : guild.id - ].commands[id] + typeof guild === 'string' ? guild : guild.id + ].commands[id] await route.patch(data) return this @@ -313,8 +314,8 @@ export class SlashCommandsManager { guild === undefined ? this.rest.api.applications[this.slash.getID()].commands[id] : this.rest.api.applications[this.slash.getID()].guilds[ - typeof guild === 'string' ? guild : guild.id - ].commands[id] + typeof guild === 'string' ? guild : guild.id + ].commands[id] await route.delete() return this @@ -326,8 +327,8 @@ export class SlashCommandsManager { guild === undefined ? this.rest.api.applications[this.slash.getID()].commands[id] : this.rest.api.applications[this.slash.getID()].guilds[ - typeof guild === 'string' ? guild : guild.id - ].commands[id] + typeof guild === 'string' ? guild : guild.id + ].commands[id] const data = await route.get() @@ -335,8 +336,8 @@ export class SlashCommandsManager { typeof guild === 'object' ? guild : guild === undefined - ? undefined - : await this.slash.client?.guilds.get(guild) + ? undefined + : await this.slash.client?.guilds.get(guild) return new SlashCommand(this, data, _guild) } @@ -350,8 +351,8 @@ export class SlashCommandsManager { guild === undefined ? this.rest.api.applications[this.slash.getID()].commands : this.rest.api.applications[this.slash.getID()].guilds[ - typeof guild === 'string' ? guild : guild.id - ].commands + typeof guild === 'string' ? guild : guild.id + ].commands await route.put(cmds) @@ -378,9 +379,6 @@ export interface SlashOptions { publicKey?: string } -const encoder = new TextEncoder() -const decoder = new TextDecoder('utf-8') - // eslint-disable-next-line @typescript-eslint/consistent-type-definitions export type SlashClientEvents = { interaction: [Interaction] @@ -439,13 +437,14 @@ export class SlashClient extends HarmonyEventEmitter { options.client === undefined ? options.rest === undefined ? new RESTManager({ - token: this.token - }) + token: this.token + }) : options.rest : options.client.rest - this.client?.on('interactionCreate', async (interaction) => - await this._process(interaction) + this.client?.on( + 'interactionCreate', + async (interaction) => await this._process(interaction) ) this.commands = new SlashCommandsManager(this) @@ -490,20 +489,20 @@ export class SlashClient extends HarmonyEventEmitter { const groupMatched = e.group !== undefined && e.parent !== undefined ? i.options - .find( - (o) => - o.name === e.group && - o.type === SlashCommandOptionType.SUB_COMMAND_GROUP - ) - ?.options?.find((o) => o.name === e.name) !== undefined + .find( + (o) => + o.name === e.group && + o.type === SlashCommandOptionType.SUB_COMMAND_GROUP + ) + ?.options?.find((o) => o.name === e.name) !== undefined : true const subMatched = e.group === undefined && e.parent !== undefined ? i.options.find( - (o) => - o.name === e.name && - o.type === SlashCommandOptionType.SUB_COMMAND - ) !== undefined + (o) => + o.name === e.name && + o.type === SlashCommandOptionType.SUB_COMMAND + ) !== undefined : true const nameMatched1 = e.name === i.name const parentMatched = hasGroupOrParent ? e.parent === i.name : true @@ -533,7 +532,9 @@ export class SlashClient extends HarmonyEventEmitter { if (cmd === undefined) return await this.emit('interaction', interaction) - try { await cmd.handler(interaction) } catch (e) { + try { + await cmd.handler(interaction) + } catch (e) { await this.emit('interactionError', e) } } @@ -548,10 +549,8 @@ export class SlashClient extends HarmonyEventEmitter { throw new Error('Public Key is not present') const fullBody = new Uint8Array([ - ...(typeof timestamp === 'string' - ? encoder.encode(timestamp) - : timestamp), - ...(typeof rawBody === 'string' ? encoder.encode(rawBody) : rawBody) + ...(typeof timestamp === 'string' ? encodeText(timestamp) : timestamp), + ...(typeof rawBody === 'string' ? encodeText(rawBody) : rawBody) ]) return edverify(signature, fullBody, this.publicKey).catch(() => false) @@ -561,7 +560,7 @@ export class SlashClient extends HarmonyEventEmitter { async verifyServerRequest(req: { headers: Headers method: string - body: Deno.Reader | Uint8Array, + body: Deno.Reader | Uint8Array respond: (options: { status?: number headers?: Headers @@ -574,12 +573,13 @@ export class SlashClient extends HarmonyEventEmitter { const timestamp = req.headers.get('x-signature-timestamp') if (signature === null || timestamp === null) return false - const rawbody = req.body instanceof Uint8Array ? req.body : await Deno.readAll(req.body) + const rawbody = + req.body instanceof Uint8Array ? req.body : 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 payload: InteractionPayload = JSON.parse(decodeText(rawbody)) // TODO: Maybe fix all this hackery going on here? const res = new Interaction(this as any, payload, { @@ -600,7 +600,8 @@ export class SlashClient extends HarmonyEventEmitter { await req.respond({ status: 200, headers: new Headers({ - 'content-type': d instanceof FormData ? 'multipart/form-data' : 'application/json' + 'content-type': + d instanceof FormData ? 'multipart/form-data' : 'application/json' }), body: d instanceof FormData ? d : JSON.stringify(d) }) @@ -612,7 +613,13 @@ export class SlashClient extends HarmonyEventEmitter { } /** Verify FetchEvent (for Service Worker usage) and return Interaction if valid */ - async verifyFetchEvent({ request: req, respondWith }: { respondWith: CallableFunction, request: Request }): Promise { + async verifyFetchEvent({ + request: req, + respondWith + }: { + respondWith: CallableFunction + request: Request + }): Promise { if (req.bodyUsed === true) throw new Error('Request Body already used') if (req.body === null) return false const body = (await req.body.getReader().read()).value @@ -623,11 +630,13 @@ export class SlashClient extends HarmonyEventEmitter { body, method: req.method, respond: async (options) => { - await respondWith(new Response(options.body, { - headers: options.headers, - status: options.status, - })) - }, + await respondWith( + new Response(options.body, { + headers: options.headers, + status: options.status + }) + ) + } }) } diff --git a/src/structures/message.ts b/src/structures/message.ts index c0cbb9e..92b4bbe 100644 --- a/src/structures/message.ts +++ b/src/structures/message.ts @@ -21,6 +21,7 @@ import { MessageReactionsManager } from '../managers/messageReactions.ts' import { MessageSticker } from './messageSticker.ts' import { Emoji } from './emoji.ts' import { InteractionType } from '../types/slash.ts' +import { encodeText } from '../utils/encoding.ts' type AllMessageOptions = MessageOptions | Embed @@ -217,8 +218,6 @@ export class Message extends SnowflakeBase { } } -const encoder = new TextEncoder() - /** Message Attachment that can be sent while Creating Message */ export class MessageAttachment { name: string @@ -228,7 +227,7 @@ export class MessageAttachment { this.name = name this.blob = typeof blob === 'string' - ? new Blob([encoder.encode(blob)]) + ? new Blob([encodeText(blob)]) : blob instanceof Uint8Array ? new Blob([blob]) : blob diff --git a/src/utils/encoding.ts b/src/utils/encoding.ts new file mode 100644 index 0000000..04ce231 --- /dev/null +++ b/src/utils/encoding.ts @@ -0,0 +1,10 @@ +const encoder = new TextEncoder() +const decoder = new TextDecoder('utf-8') + +export function encodeText(str: string): Uint8Array { + return encoder.encode(str) +} + +export function decodeText(bytes: Uint8Array): string { + return decoder.decode(bytes) +}