x
This commit is contained in:
		
							parent
							
								
									e65fa8fded
								
							
						
					
					
						commit
						dcb07a9aaa
					
				
					 3 changed files with 78 additions and 0 deletions
				
			
		|  | @ -1,6 +1,7 @@ | ||||||
| import { Guild } from '../structures/guild.ts' | import { Guild } from '../structures/guild.ts' | ||||||
| import { Interaction } from '../structures/slash.ts' | import { Interaction } from '../structures/slash.ts' | ||||||
| import { | import { | ||||||
|  |   InteractionPayload, | ||||||
|   InteractionType, |   InteractionType, | ||||||
|   SlashCommandChoice, |   SlashCommandChoice, | ||||||
|   SlashCommandOption, |   SlashCommandOption, | ||||||
|  | @ -369,6 +370,7 @@ export interface SlashOptions { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const encoder = new TextEncoder() | const encoder = new TextEncoder() | ||||||
|  | const decoder = new TextDecoder('utf-8') | ||||||
| 
 | 
 | ||||||
| export class SlashClient { | export class SlashClient { | ||||||
|   id: string | (() => string) |   id: string | (() => string) | ||||||
|  | @ -503,6 +505,7 @@ export class SlashClient { | ||||||
|     cmd.handler(interaction) |     cmd.handler(interaction) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   /** Verify HTTP based Interaction */ | ||||||
|   async verifyKey( |   async verifyKey( | ||||||
|     rawBody: string | Uint8Array, |     rawBody: string | Uint8Array, | ||||||
|     signature: string | Uint8Array, |     signature: string | Uint8Array, | ||||||
|  | @ -521,6 +524,35 @@ export class SlashClient { | ||||||
|     return edverify(signature, fullBody, this.publicKey).catch(() => false) |     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> { |   async verifyOpineRequest(req: any): Promise<boolean> { | ||||||
|     const signature = req.headers.get('x-signature-ed25519') |     const signature = req.headers.get('x-signature-ed25519') | ||||||
|     const timestamp = req.headers.get('x-signature-timestamp') |     const timestamp = req.headers.get('x-signature-timestamp') | ||||||
|  |  | ||||||
|  | @ -41,6 +41,7 @@ export interface InteractionResponse { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class Interaction extends SnowflakeBase { | export class Interaction extends SnowflakeBase { | ||||||
|  |   /** This will be `SlashClient` in case of `SlashClient#verifyServerRequest` */ | ||||||
|   client: Client |   client: Client | ||||||
|   type: number |   type: number | ||||||
|   token: string |   token: string | ||||||
|  | @ -50,6 +51,7 @@ export class Interaction extends SnowflakeBase { | ||||||
|   guild: Guild |   guild: Guild | ||||||
|   member: Member |   member: Member | ||||||
|   _savedHook?: Webhook |   _savedHook?: Webhook | ||||||
|  |   _respond?: (data: InteractionResponsePayload) => unknown | ||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
|     client: Client, |     client: Client, | ||||||
|  |  | ||||||
							
								
								
									
										44
									
								
								src/test/slash-http.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/test/slash-http.ts
									
										
									
									
									
										Normal 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!' | ||||||
|  |     } | ||||||
|  |   }) | ||||||
|  | }) | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue