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 { VoiceChannel } from '../structures/guildVoiceChannel.ts' | ||||||
| import { Guild } from '../structures/guild.ts' | import { Guild } from '../structures/guild.ts' | ||||||
| import { HarmonyEventEmitter } from '../utils/events.ts' | import { HarmonyEventEmitter } from '../utils/events.ts' | ||||||
|  | import { decodeText } from '../utils/encoding.ts' | ||||||
| 
 | 
 | ||||||
| export interface RequestMembersOptions { | export interface RequestMembersOptions { | ||||||
|   limit?: number |   limit?: number | ||||||
|  | @ -89,7 +90,7 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> { | ||||||
|     } |     } | ||||||
|     if (data instanceof Uint8Array) { |     if (data instanceof Uint8Array) { | ||||||
|       data = unzlib(data) |       data = unzlib(data) | ||||||
|       data = new TextDecoder('utf-8').decode(data) |       data = decodeText(data) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const { op, d, s, t }: GatewayResponse = JSON.parse(data) |     const { op, d, s, t }: GatewayResponse = JSON.parse(data) | ||||||
|  | @ -385,8 +386,8 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> { | ||||||
|           channel === undefined |           channel === undefined | ||||||
|             ? null |             ? null | ||||||
|             : typeof channel === 'string' |             : typeof channel === 'string' | ||||||
|               ? channel |             ? channel | ||||||
|               : channel?.id, |             : channel?.id, | ||||||
|         self_mute: voiceOptions.mute === undefined ? false : voiceOptions.mute, |         self_mute: voiceOptions.mute === undefined ? false : voiceOptions.mute, | ||||||
|         self_deaf: voiceOptions.deaf === undefined ? false : voiceOptions.deaf |         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 { |   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) |     return this.websocket?.close(code, reason) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -19,7 +19,8 @@ import { RESTManager } from './rest.ts' | ||||||
| import { SlashModule } from './slashModule.ts' | import { SlashModule } from './slashModule.ts' | ||||||
| import { verify as edverify } from 'https://deno.land/x/ed25519@1.0.1/mod.ts' | import { verify as edverify } from 'https://deno.land/x/ed25519@1.0.1/mod.ts' | ||||||
| import { User } from '../structures/user.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 { | export class SlashCommand { | ||||||
|   slash: SlashCommandsManager |   slash: SlashCommandsManager | ||||||
|  | @ -94,8 +95,8 @@ function createSlashOption( | ||||||
|       data.choices === undefined |       data.choices === undefined | ||||||
|         ? undefined |         ? undefined | ||||||
|         : data.choices.map((e) => |         : 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 = | export type SlashBuilderOptionsData = | ||||||
|   | Array<SlashCommandOption | SlashOptionCallable> |   | Array<SlashCommandOption | SlashOptionCallable> | ||||||
|   | { |   | { | ||||||
|     [name: string]: |       [name: string]: | ||||||
|     | { |         | { | ||||||
|       description: string |             description: string | ||||||
|       type: SlashCommandOptionType |             type: SlashCommandOptionType | ||||||
|       options?: SlashCommandOption[] |             options?: SlashCommandOption[] | ||||||
|       choices?: SlashCommandChoice[] |             choices?: SlashCommandChoice[] | ||||||
|  |           } | ||||||
|  |         | SlashOptionCallable | ||||||
|     } |     } | ||||||
|     | SlashOptionCallable |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
| function buildOptionsArray( | function buildOptionsArray( | ||||||
|   options: SlashBuilderOptionsData |   options: SlashBuilderOptionsData | ||||||
|  | @ -155,10 +156,10 @@ function buildOptionsArray( | ||||||
|   return Array.isArray(options) |   return Array.isArray(options) | ||||||
|     ? options.map((op) => (typeof op === 'function' ? op(SlashOption) : op)) |     ? options.map((op) => (typeof op === 'function' ? op(SlashOption) : op)) | ||||||
|     : Object.entries(options).map((entry) => |     : Object.entries(options).map((entry) => | ||||||
|       typeof entry[1] === 'function' |         typeof entry[1] === 'function' | ||||||
|         ? entry[1](SlashOption) |           ? entry[1](SlashOption) | ||||||
|         : Object.assign(entry[1], { name: entry[0] }) |           : Object.assign(entry[1], { name: entry[0] }) | ||||||
|     ) |       ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Slash Command Builder */ | /** Slash Command Builder */ | ||||||
|  | @ -268,8 +269,8 @@ export class SlashCommandsManager { | ||||||
|       guild === undefined |       guild === undefined | ||||||
|         ? this.rest.api.applications[this.slash.getID()].commands |         ? this.rest.api.applications[this.slash.getID()].commands | ||||||
|         : this.rest.api.applications[this.slash.getID()].guilds[ |         : this.rest.api.applications[this.slash.getID()].guilds[ | ||||||
|           typeof guild === 'string' ? guild : guild.id |             typeof guild === 'string' ? guild : guild.id | ||||||
|         ].commands |           ].commands | ||||||
| 
 | 
 | ||||||
|     const payload = await route.post(data) |     const payload = await route.post(data) | ||||||
| 
 | 
 | ||||||
|  | @ -277,8 +278,8 @@ export class SlashCommandsManager { | ||||||
|       typeof guild === 'object' |       typeof guild === 'object' | ||||||
|         ? guild |         ? guild | ||||||
|         : guild === undefined |         : guild === undefined | ||||||
|           ? undefined |         ? undefined | ||||||
|           : await this.slash.client?.guilds.get(guild) |         : await this.slash.client?.guilds.get(guild) | ||||||
| 
 | 
 | ||||||
|     const cmd = new SlashCommand(this, payload, _guild) |     const cmd = new SlashCommand(this, payload, _guild) | ||||||
|     cmd._guild = |     cmd._guild = | ||||||
|  | @ -297,8 +298,8 @@ export class SlashCommandsManager { | ||||||
|       guild === undefined |       guild === undefined | ||||||
|         ? this.rest.api.applications[this.slash.getID()].commands[id] |         ? this.rest.api.applications[this.slash.getID()].commands[id] | ||||||
|         : this.rest.api.applications[this.slash.getID()].guilds[ |         : this.rest.api.applications[this.slash.getID()].guilds[ | ||||||
|           typeof guild === 'string' ? guild : guild.id |             typeof guild === 'string' ? guild : guild.id | ||||||
|         ].commands[id] |           ].commands[id] | ||||||
| 
 | 
 | ||||||
|     await route.patch(data) |     await route.patch(data) | ||||||
|     return this |     return this | ||||||
|  | @ -313,8 +314,8 @@ export class SlashCommandsManager { | ||||||
|       guild === undefined |       guild === undefined | ||||||
|         ? this.rest.api.applications[this.slash.getID()].commands[id] |         ? this.rest.api.applications[this.slash.getID()].commands[id] | ||||||
|         : this.rest.api.applications[this.slash.getID()].guilds[ |         : this.rest.api.applications[this.slash.getID()].guilds[ | ||||||
|           typeof guild === 'string' ? guild : guild.id |             typeof guild === 'string' ? guild : guild.id | ||||||
|         ].commands[id] |           ].commands[id] | ||||||
| 
 | 
 | ||||||
|     await route.delete() |     await route.delete() | ||||||
|     return this |     return this | ||||||
|  | @ -326,8 +327,8 @@ export class SlashCommandsManager { | ||||||
|       guild === undefined |       guild === undefined | ||||||
|         ? this.rest.api.applications[this.slash.getID()].commands[id] |         ? this.rest.api.applications[this.slash.getID()].commands[id] | ||||||
|         : this.rest.api.applications[this.slash.getID()].guilds[ |         : this.rest.api.applications[this.slash.getID()].guilds[ | ||||||
|           typeof guild === 'string' ? guild : guild.id |             typeof guild === 'string' ? guild : guild.id | ||||||
|         ].commands[id] |           ].commands[id] | ||||||
| 
 | 
 | ||||||
|     const data = await route.get() |     const data = await route.get() | ||||||
| 
 | 
 | ||||||
|  | @ -335,8 +336,8 @@ export class SlashCommandsManager { | ||||||
|       typeof guild === 'object' |       typeof guild === 'object' | ||||||
|         ? guild |         ? guild | ||||||
|         : guild === undefined |         : guild === undefined | ||||||
|           ? undefined |         ? undefined | ||||||
|           : await this.slash.client?.guilds.get(guild) |         : await this.slash.client?.guilds.get(guild) | ||||||
| 
 | 
 | ||||||
|     return new SlashCommand(this, data, _guild) |     return new SlashCommand(this, data, _guild) | ||||||
|   } |   } | ||||||
|  | @ -350,8 +351,8 @@ export class SlashCommandsManager { | ||||||
|       guild === undefined |       guild === undefined | ||||||
|         ? this.rest.api.applications[this.slash.getID()].commands |         ? this.rest.api.applications[this.slash.getID()].commands | ||||||
|         : this.rest.api.applications[this.slash.getID()].guilds[ |         : this.rest.api.applications[this.slash.getID()].guilds[ | ||||||
|           typeof guild === 'string' ? guild : guild.id |             typeof guild === 'string' ? guild : guild.id | ||||||
|         ].commands |           ].commands | ||||||
| 
 | 
 | ||||||
|     await route.put(cmds) |     await route.put(cmds) | ||||||
| 
 | 
 | ||||||
|  | @ -378,9 +379,6 @@ export interface SlashOptions { | ||||||
|   publicKey?: string |   publicKey?: string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const encoder = new TextEncoder() |  | ||||||
| const decoder = new TextDecoder('utf-8') |  | ||||||
| 
 |  | ||||||
| // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
 | // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
 | ||||||
| export type SlashClientEvents = { | export type SlashClientEvents = { | ||||||
|   interaction: [Interaction] |   interaction: [Interaction] | ||||||
|  | @ -439,13 +437,14 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | ||||||
|       options.client === undefined |       options.client === undefined | ||||||
|         ? options.rest === undefined |         ? options.rest === undefined | ||||||
|           ? new RESTManager({ |           ? new RESTManager({ | ||||||
|             token: this.token |               token: this.token | ||||||
|           }) |             }) | ||||||
|           : options.rest |           : options.rest | ||||||
|         : options.client.rest |         : options.client.rest | ||||||
| 
 | 
 | ||||||
|     this.client?.on('interactionCreate', async (interaction) => |     this.client?.on( | ||||||
|       await this._process(interaction) |       'interactionCreate', | ||||||
|  |       async (interaction) => await this._process(interaction) | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     this.commands = new SlashCommandsManager(this) |     this.commands = new SlashCommandsManager(this) | ||||||
|  | @ -490,20 +489,20 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | ||||||
|       const groupMatched = |       const groupMatched = | ||||||
|         e.group !== undefined && e.parent !== undefined |         e.group !== undefined && e.parent !== undefined | ||||||
|           ? i.options |           ? i.options | ||||||
|             .find( |               .find( | ||||||
|               (o) => |                 (o) => | ||||||
|                 o.name === e.group && |                   o.name === e.group && | ||||||
|                 o.type === SlashCommandOptionType.SUB_COMMAND_GROUP |                   o.type === SlashCommandOptionType.SUB_COMMAND_GROUP | ||||||
|             ) |               ) | ||||||
|             ?.options?.find((o) => o.name === e.name) !== undefined |               ?.options?.find((o) => o.name === e.name) !== undefined | ||||||
|           : true |           : true | ||||||
|       const subMatched = |       const subMatched = | ||||||
|         e.group === undefined && e.parent !== undefined |         e.group === undefined && e.parent !== undefined | ||||||
|           ? i.options.find( |           ? i.options.find( | ||||||
|             (o) => |               (o) => | ||||||
|               o.name === e.name && |                 o.name === e.name && | ||||||
|               o.type === SlashCommandOptionType.SUB_COMMAND |                 o.type === SlashCommandOptionType.SUB_COMMAND | ||||||
|           ) !== undefined |             ) !== undefined | ||||||
|           : true |           : true | ||||||
|       const nameMatched1 = e.name === i.name |       const nameMatched1 = e.name === i.name | ||||||
|       const parentMatched = hasGroupOrParent ? e.parent === i.name : true |       const parentMatched = hasGroupOrParent ? e.parent === i.name : true | ||||||
|  | @ -533,7 +532,9 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | ||||||
|     if (cmd === undefined) return |     if (cmd === undefined) return | ||||||
| 
 | 
 | ||||||
|     await this.emit('interaction', interaction) |     await this.emit('interaction', interaction) | ||||||
|     try { await cmd.handler(interaction) } catch (e) { |     try { | ||||||
|  |       await cmd.handler(interaction) | ||||||
|  |     } catch (e) { | ||||||
|       await this.emit('interactionError', e) |       await this.emit('interactionError', e) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | @ -548,10 +549,8 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | ||||||
|       throw new Error('Public Key is not present') |       throw new Error('Public Key is not present') | ||||||
| 
 | 
 | ||||||
|     const fullBody = new Uint8Array([ |     const fullBody = new Uint8Array([ | ||||||
|       ...(typeof timestamp === 'string' |       ...(typeof timestamp === 'string' ? encodeText(timestamp) : timestamp), | ||||||
|         ? encoder.encode(timestamp) |       ...(typeof rawBody === 'string' ? encodeText(rawBody) : rawBody) | ||||||
|         : timestamp), |  | ||||||
|       ...(typeof rawBody === 'string' ? encoder.encode(rawBody) : rawBody) |  | ||||||
|     ]) |     ]) | ||||||
| 
 | 
 | ||||||
|     return edverify(signature, fullBody, this.publicKey).catch(() => false) |     return edverify(signature, fullBody, this.publicKey).catch(() => false) | ||||||
|  | @ -561,7 +560,7 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | ||||||
|   async verifyServerRequest(req: { |   async verifyServerRequest(req: { | ||||||
|     headers: Headers |     headers: Headers | ||||||
|     method: string |     method: string | ||||||
|     body: Deno.Reader | Uint8Array, |     body: Deno.Reader | Uint8Array | ||||||
|     respond: (options: { |     respond: (options: { | ||||||
|       status?: number |       status?: number | ||||||
|       headers?: Headers |       headers?: Headers | ||||||
|  | @ -574,12 +573,13 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | ||||||
|     const timestamp = req.headers.get('x-signature-timestamp') |     const timestamp = req.headers.get('x-signature-timestamp') | ||||||
|     if (signature === null || timestamp === null) return false |     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) |     const verify = await this.verifyKey(rawbody, signature, timestamp) | ||||||
|     if (!verify) return false |     if (!verify) return false | ||||||
| 
 | 
 | ||||||
|     try { |     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?
 |       // TODO: Maybe fix all this hackery going on here?
 | ||||||
|       const res = new Interaction(this as any, payload, { |       const res = new Interaction(this as any, payload, { | ||||||
|  | @ -600,7 +600,8 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | ||||||
|         await req.respond({ |         await req.respond({ | ||||||
|           status: 200, |           status: 200, | ||||||
|           headers: new Headers({ |           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) |           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 */ |   /** 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.bodyUsed === true) throw new Error('Request Body already used') | ||||||
|     if (req.body === null) return false |     if (req.body === null) return false | ||||||
|     const body = (await req.body.getReader().read()).value |     const body = (await req.body.getReader().read()).value | ||||||
|  | @ -623,11 +630,13 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> { | ||||||
|       body, |       body, | ||||||
|       method: req.method, |       method: req.method, | ||||||
|       respond: async (options) => { |       respond: async (options) => { | ||||||
|         await respondWith(new Response(options.body, { |         await respondWith( | ||||||
|           headers: options.headers, |           new Response(options.body, { | ||||||
|           status: options.status, |             headers: options.headers, | ||||||
|         })) |             status: options.status | ||||||
|       }, |           }) | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ import { MessageReactionsManager } from '../managers/messageReactions.ts' | ||||||
| import { MessageSticker } from './messageSticker.ts' | import { MessageSticker } from './messageSticker.ts' | ||||||
| import { Emoji } from './emoji.ts' | import { Emoji } from './emoji.ts' | ||||||
| import { InteractionType } from '../types/slash.ts' | import { InteractionType } from '../types/slash.ts' | ||||||
|  | import { encodeText } from '../utils/encoding.ts' | ||||||
| 
 | 
 | ||||||
| type AllMessageOptions = MessageOptions | Embed | 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 */ | /** Message Attachment that can be sent while Creating Message */ | ||||||
| export class MessageAttachment { | export class MessageAttachment { | ||||||
|   name: string |   name: string | ||||||
|  | @ -228,7 +227,7 @@ export class MessageAttachment { | ||||||
|     this.name = name |     this.name = name | ||||||
|     this.blob = |     this.blob = | ||||||
|       typeof blob === 'string' |       typeof blob === 'string' | ||||||
|         ? new Blob([encoder.encode(blob)]) |         ? new Blob([encodeText(blob)]) | ||||||
|         : blob instanceof Uint8Array |         : blob instanceof Uint8Array | ||||||
|         ? new Blob([blob]) |         ? new Blob([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…
	
	Add table
		Add a link
		
	
		Reference in a new issue