encoding util
This commit is contained in:
parent
38b11f4076
commit
2b46b38908
4 changed files with 91 additions and 68 deletions
|
@ -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<GatewayTypedEvents> {
|
|||
}
|
||||
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<GatewayTypedEvents> {
|
|||
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<GatewayTypedEvents> {
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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<SlashCommandOption | SlashOptionCallable>
|
||||
| {
|
||||
[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<SlashClientEvents> {
|
|||
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<SlashClientEvents> {
|
|||
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<SlashClientEvents> {
|
|||
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<SlashClientEvents> {
|
|||
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<SlashClientEvents> {
|
|||
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<SlashClientEvents> {
|
|||
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<SlashClientEvents> {
|
|||
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<SlashClientEvents> {
|
|||
}
|
||||
|
||||
/** Verify FetchEvent (for Service Worker usage) and return Interaction if valid */
|
||||
async verifyFetchEvent({ request: req, respondWith }: { respondWith: CallableFunction, request: Request }): Promise<false | Interaction> {
|
||||
async verifyFetchEvent({
|
||||
request: req,
|
||||
respondWith
|
||||
}: {
|
||||
respondWith: CallableFunction
|
||||
request: Request
|
||||
}): Promise<false | Interaction> {
|
||||
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<SlashClientEvents> {
|
|||
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
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
10
src/utils/encoding.ts
Normal file
10
src/utils/encoding.ts
Normal file
|
@ -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)
|
||||
}
|
Loading…
Reference in a new issue