feat: Implement OAuth2 endpoints (#3114)

* add OAuth2 routes

* Add oauth2 methods to rest

* Add rest manager methods, Add token params

* Add authorization headers

* Add auth to editUserApplicationRoleConnection

* fix logging header always displaying bot as auth

* Add OAuth2Scope enum

* Start testing ratelimit handling

* Fix now scopes are separated by a space

* move webhook object to DiscordAccessTokenResponse

* convert payload to snake_case

* fix some typings

* more types fixes

* add support for upserting commands with tokens

* handle correctly ratelimit and concurrently

* add guild to DiscordAccessTokenResponse

* Add oauth2 create link function

* Fix removeTokenPrefix to support Bearer tokens

* update jsdoc comment for removeTokenPrefix

* fix removeTokenPrefix unit tests

* fix see link on getMember and getCurrentMember

* add bot helpers and fix some types

* Use objects to pass the bearer tokens

* fix Deno issue with Buffer.from

* Merge 'upstream/main' into feat/oauth2 to fix merge conflict

* Fix debug queue logging

* keep only 1 route for current user

* add Bearer prefixed url to the rest of the logs

---------

Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com>
This commit is contained in:
Fleny
2023-09-19 16:23:22 +00:00
committed by GitHub
co-authored by Skillz4Killz
parent c92649029b
commit a7d645ec4b
12 changed files with 1140 additions and 85 deletions
+113 -18
View File
@@ -1,12 +1,18 @@
import type { CreateWebhook } from '@discordeno/rest'
import type {
AddDmRecipientOptions,
AddGuildMemberOptions,
ApplicationCommandPermissions,
AtLeastOne,
BeginGuildPrune,
BigString,
CamelizedDiscordAccessTokenResponse,
CamelizedDiscordApplicationRoleConnection,
CamelizedDiscordArchivedThreads,
CamelizedDiscordAuditLog,
CamelizedDiscordBan,
CamelizedDiscordConnection,
CamelizedDiscordCurrentAuthorization,
CamelizedDiscordFollowedChannel,
CamelizedDiscordGetGatewayBot,
CamelizedDiscordGuildPreview,
@@ -14,14 +20,19 @@ import type {
CamelizedDiscordInvite,
CamelizedDiscordInviteMetadata,
CamelizedDiscordModifyGuildWelcomeScreen,
CamelizedDiscordPartialGuild,
CamelizedDiscordPrunedCount,
CamelizedDiscordTokenExchange,
CamelizedDiscordTokenRevocation,
CamelizedDiscordVanityUrl,
CamelizedDiscordVoiceRegion,
CreateApplicationCommand,
CreateAutoModerationRuleOptions,
CreateChannelInvite,
CreateForumPostWithMessage,
CreateGlobalApplicationCommandOptions,
CreateGuild,
CreateGuildApplicationCommandOptions,
CreateGuildBan,
CreateGuildChannel,
CreateGuildEmoji,
@@ -44,7 +55,9 @@ import type {
EditScheduledEvent,
EditUserVoiceState,
ExecuteWebhook,
GetApplicationCommandPermissionOptions,
GetBans,
GetGroupDmOptions,
GetGuildAuditLog,
GetGuildPruneCountQuery,
GetInvite,
@@ -52,6 +65,7 @@ import type {
GetReactions,
GetScheduledEventUsers,
GetScheduledEvents,
GetUserGuilds,
GetWebhookMessageOptions,
InteractionCallbackData,
InteractionResponse,
@@ -69,6 +83,8 @@ import type {
SearchMembers,
StartThreadWithMessage,
StartThreadWithoutMessage,
UpsertGlobalApplicationCommandOptions,
UpsertGuildApplicationCommandOptions,
} from '@discordeno/types'
import { snakelize } from '@discordeno/utils'
import type { Bot } from './bot.js'
@@ -108,14 +124,14 @@ export function createBotHelpers(bot: Bot): BotHelpers {
createForumThread: async (channelId, options, reason) => {
return bot.transformers.channel(bot, { channel: snakelize(await bot.rest.createForumThread(channelId, options, reason)) })
},
createGlobalApplicationCommand: async (command) => {
return bot.transformers.applicationCommand(bot, snakelize(await bot.rest.createGlobalApplicationCommand(command)))
createGlobalApplicationCommand: async (command, options) => {
return bot.transformers.applicationCommand(bot, snakelize(await bot.rest.createGlobalApplicationCommand(command, options)))
},
createGuild: async (options) => {
return bot.transformers.guild(bot, { guild: snakelize(await bot.rest.createGuild(options)), shardId: 0 })
},
createGuildApplicationCommand: async (command, guildId) => {
return bot.transformers.applicationCommand(bot, snakelize(await bot.rest.createGuildApplicationCommand(command, guildId)))
createGuildApplicationCommand: async (command, guildId, options) => {
return bot.transformers.applicationCommand(bot, snakelize(await bot.rest.createGuildApplicationCommand(command, guildId, options)))
},
createGuildFromTemplate: async (templateCode, options) => {
return bot.transformers.guild(bot, { guild: snakelize(await bot.rest.createGuildFromTemplate(templateCode, options)), shardId: 0 })
@@ -235,11 +251,23 @@ export function createBotHelpers(bot: Bot): BotHelpers {
getApplicationInfo: async () => {
return bot.transformers.application(bot, snakelize(await bot.rest.getApplicationInfo()))
},
getApplicationCommandPermission: async (guildId, commandId) => {
return bot.transformers.applicationCommandPermission(bot, snakelize(await bot.rest.getApplicationCommandPermission(guildId, commandId)))
getCurrentAuthenticationInfo: async (bearerToken) => {
return await bot.rest.getCurrentAuthenticationInfo(bearerToken)
},
getApplicationCommandPermissions: async (guildId) => {
return (await bot.rest.getApplicationCommandPermissions(guildId)).map((res) =>
exchangeToken: async (options) => {
return await bot.rest.exchangeToken(options)
},
revokeToken: async (options) => {
return await bot.rest.revokeToken(options)
},
getApplicationCommandPermission: async (guildId, commandId, options) => {
const res = await bot.rest.getApplicationCommandPermission(guildId, commandId, options)
const snakedRes = snakelize(res)
return bot.transformers.applicationCommandPermission(bot, snakedRes)
},
getApplicationCommandPermissions: async (guildId, options) => {
return (await bot.rest.getApplicationCommandPermissions(guildId, options)).map((res) =>
bot.transformers.applicationCommandPermission(bot, snakelize(res)),
)
},
@@ -277,6 +305,9 @@ export function createBotHelpers(bot: Bot): BotHelpers {
getDmChannel: async (userId) => {
return bot.transformers.channel(bot, { channel: snakelize(await bot.rest.getDmChannel(userId)) })
},
getGroupDmChannel: async (options) => {
return bot.transformers.channel(bot, { channel: snakelize(await bot.rest.getGroupDmChannel(options)) })
},
getEmoji: async (guildId, emojiId) => {
return bot.transformers.emoji(bot, snakelize(await bot.rest.getEmoji(guildId, emojiId)))
},
@@ -298,6 +329,9 @@ export function createBotHelpers(bot: Bot): BotHelpers {
getGuild: async (guildId, options) => {
return bot.transformers.guild(bot, { guild: snakelize(await bot.rest.getGuild(guildId, options)), shardId: 0 })
},
getGuilds: async (bearerToken, options) => {
return await bot.rest.getGuilds(bearerToken, options)
},
getGuildApplicationCommand: async (commandId, guildId) => {
return bot.transformers.applicationCommand(bot, snakelize(await bot.rest.getGuildApplicationCommand(commandId, guildId)))
},
@@ -405,6 +439,15 @@ export function createBotHelpers(bot: Bot): BotHelpers {
getUser: async (id) => {
return bot.transformers.user(bot, snakelize(await bot.rest.getUser(id)))
},
getCurrentUser: async (bearerToken) => {
return bot.transformers.user(bot, snakelize(await bot.rest.getCurrentUser(bearerToken)))
},
getUserConnections: async (bearerToken) => {
return await bot.rest.getUserConnections(bearerToken)
},
getUserApplicationRoleConnection: async (bearerToken, applicationId) => {
return await bot.rest.getUserApplicationRoleConnection(bearerToken, applicationId)
},
getVanityUrl: async (guildId) => {
return await bot.rest.getVanityUrl(guildId)
},
@@ -449,11 +492,15 @@ export function createBotHelpers(bot: Bot): BotHelpers {
syncGuildTemplate: async (guildId) => {
return bot.transformers.template(bot, snakelize(await bot.rest.syncGuildTemplate(guildId)))
},
upsertGlobalApplicationCommands: async (commands) => {
return (await bot.rest.upsertGlobalApplicationCommands(commands)).map((res) => bot.transformers.applicationCommand(bot, snakelize(res)))
upsertGlobalApplicationCommands: async (commands, options) => {
return (await bot.rest.upsertGlobalApplicationCommands(commands, options)).map((res) =>
bot.transformers.applicationCommand(bot, snakelize(res)),
)
},
upsertGuildApplicationCommands: async (guildId, commands) => {
return (await bot.rest.upsertGuildApplicationCommands(guildId, commands)).map((res) => bot.transformers.applicationCommand(bot, snakelize(res)))
upsertGuildApplicationCommands: async (guildId, commands, options) => {
return (await bot.rest.upsertGuildApplicationCommands(guildId, commands, options)).map((res) =>
bot.transformers.applicationCommand(bot, snakelize(res)),
)
},
editBotMember: async (guildId, options, reason) => {
return bot.transformers.member(bot, snakelize(await bot.rest.editBotMember(guildId, options, reason)), guildId, bot.id)
@@ -464,6 +511,10 @@ export function createBotHelpers(bot: Bot): BotHelpers {
getMember: async (guildId, userId) => {
return bot.transformers.member(bot, snakelize(await bot.rest.getMember(guildId, userId)), guildId, userId)
},
getCurrentMember: async (guildId, bearerToken) => {
const res = await bot.rest.getCurrentMember(guildId, bearerToken)
return bot.transformers.member(bot, snakelize(res), guildId, bot.transformers.snowflake(res.user.id))
},
getMembers: async (guildId, options) => {
return (await bot.rest.getMembers(guildId, options)).map((res) =>
bot.transformers.member(bot, snakelize(res), guildId, bot.transformers.snowflake(res.user.id)),
@@ -490,6 +541,12 @@ export function createBotHelpers(bot: Bot): BotHelpers {
addThreadMember: async (channelId, userId) => {
return await bot.rest.addThreadMember(channelId, userId)
},
addDmRecipient: async (channelId, userId, options) => {
return await bot.rest.addDmRecipient(channelId, userId, options)
},
addGuildMember: async (guildId, userId, options) => {
return await bot.rest.addGuildMember(guildId, userId, options)
},
deleteAutomodRule: async (guildId, ruleId, reason) => {
return await bot.rest.deleteAutomodRule(guildId, ruleId, reason)
},
@@ -580,6 +637,9 @@ export function createBotHelpers(bot: Bot): BotHelpers {
editUserVoiceState: async (guildId, options) => {
return await bot.rest.editUserVoiceState(guildId, options)
},
editUserApplicationRoleConnection: async (bearerToken, applicationId, options) => {
return await bot.rest.editUserApplicationRoleConnection(bearerToken, applicationId, options)
},
joinThread: async (channelId) => {
return await bot.rest.joinThread(channelId)
},
@@ -595,6 +655,9 @@ export function createBotHelpers(bot: Bot): BotHelpers {
removeThreadMember: async (channelId, userId) => {
return await bot.rest.removeThreadMember(channelId, userId)
},
removeDmRecipient: async (channelId, userId) => {
return await bot.rest.removeDmRecipient(channelId, userId)
},
sendInteractionResponse: async (interactionId, token, options) => {
return await bot.rest.sendInteractionResponse(interactionId, token, options)
},
@@ -624,9 +687,13 @@ export interface BotHelpers {
createChannel: (guildId: BigString, options: CreateGuildChannel, reason?: string) => Promise<Channel>
createEmoji: (guildId: BigString, options: CreateGuildEmoji, reason?: string) => Promise<Emoji>
createForumThread: (channelId: BigString, options: CreateForumPostWithMessage, reason?: string) => Promise<Channel>
createGlobalApplicationCommand: (command: CreateApplicationCommand) => Promise<ApplicationCommand>
createGlobalApplicationCommand: (command: CreateApplicationCommand, options?: CreateGlobalApplicationCommandOptions) => Promise<ApplicationCommand>
createGuild: (options: CreateGuild) => Promise<Guild>
createGuildApplicationCommand: (command: CreateApplicationCommand, guildId: BigString) => Promise<ApplicationCommand>
createGuildApplicationCommand: (
command: CreateApplicationCommand,
guildId: BigString,
options?: CreateGuildApplicationCommandOptions,
) => Promise<ApplicationCommand>
createGuildFromTemplate: (templateCode: string, options: CreateGuildFromTemplate) => Promise<Guild>
createGuildSticker: (guildId: BigString, options: CreateGuildStickerOptions, reason?: string) => Promise<Sticker>
createGuildTemplate: (guildId: BigString, options: CreateTemplate) => Promise<Template>
@@ -673,12 +740,24 @@ export interface BotHelpers {
editWebhookWithToken: (webhookId: BigString, token: string, options: Omit<ModifyWebhook, 'channelId'>) => Promise<Webhook>
editWelcomeScreen: (guildId: BigString, options: CamelizedDiscordModifyGuildWelcomeScreen, reason?: string) => Promise<WelcomeScreen>
editWidgetSettings: (guildId: BigString, options: CamelizedDiscordGuildWidgetSettings, reason?: string) => Promise<GuildWidgetSettings>
editUserApplicationRoleConnection: (
bearerToken: string,
applicationId: BigString,
options: CamelizedDiscordApplicationRoleConnection,
) => Promise<CamelizedDiscordApplicationRoleConnection>
executeWebhook: (webhookId: BigString, token: string, options: ExecuteWebhook) => Promise<Message | undefined>
followAnnouncement: (sourceChannelId: BigString, targetChannelId: BigString) => Promise<CamelizedDiscordFollowedChannel>
getActiveThreads: (guildId: BigString) => Promise<{ threads: Channel[]; members: ThreadMember[] }>
getApplicationInfo: () => Promise<Application>
getApplicationCommandPermission: (guildId: BigString, commandId: BigString) => Promise<ApplicationCommandPermission>
getApplicationCommandPermissions: (guildId: BigString) => Promise<ApplicationCommandPermission[]>
getCurrentAuthenticationInfo: (bearerToken: string) => Promise<CamelizedDiscordCurrentAuthorization>
exchangeToken: (options: CamelizedDiscordTokenExchange) => Promise<CamelizedDiscordAccessTokenResponse>
revokeToken: (options: CamelizedDiscordTokenRevocation) => Promise<void>
getApplicationCommandPermission: (
guildId: BigString,
commandId: BigString,
options?: GetApplicationCommandPermissionOptions,
) => Promise<ApplicationCommandPermission>
getApplicationCommandPermissions: (guildId: BigString, options?: GetApplicationCommandPermissionOptions) => Promise<ApplicationCommandPermission[]>
getAuditLog: (guildId: BigString, options?: GetGuildAuditLog) => Promise<CamelizedDiscordAuditLog>
getAutomodRule: (guildId: BigString, ruleId: BigString) => Promise<AutoModerationRule>
getAutomodRules: (guildId: BigString) => Promise<AutoModerationRule[]>
@@ -690,6 +769,7 @@ export interface BotHelpers {
getChannels: (guildId: BigString) => Promise<Channel[]>
getChannelWebhooks: (channelId: BigString) => Promise<Webhook[]>
getDmChannel: (userId: BigString) => Promise<Channel>
getGroupDmChannel: (options: GetGroupDmOptions) => Promise<Channel>
getEmoji: (guildId: BigString, emojiId: BigString) => Promise<Emoji>
getEmojis: (guildId: BigString) => Promise<Emoji[]>
getFollowupMessage: (token: string, messageId: BigString) => Promise<Message>
@@ -697,6 +777,7 @@ export interface BotHelpers {
getGlobalApplicationCommand: (commandId: BigString) => Promise<ApplicationCommand>
getGlobalApplicationCommands: () => Promise<ApplicationCommand[]>
getGuild: (guildId: BigString, options?: { counts?: boolean }) => Promise<Guild>
getGuilds: (bearerToken: string, options?: GetUserGuilds) => Promise<CamelizedDiscordPartialGuild[]>
getGuildApplicationCommand: (commandId: BigString, guildId: BigString) => Promise<ApplicationCommand>
getGuildApplicationCommands: (guildId: BigString) => Promise<ApplicationCommand[]>
getGuildPreview: (guildId: BigString) => Promise<CamelizedDiscordGuildPreview>
@@ -732,6 +813,9 @@ export interface BotHelpers {
getThreadMembers: (channelId: BigString) => Promise<ThreadMember[]>
getReactions: (channelId: BigString, messageId: BigString, reaction: string, options?: GetReactions) => Promise<User[]>
getUser: (id: BigString) => Promise<User>
getCurrentUser: (bearerToken: string) => Promise<User>
getUserConnections: (bearerToken: string) => Promise<CamelizedDiscordConnection[]>
getUserApplicationRoleConnection: (bearerToken: string, applicationId: BigString) => Promise<CamelizedDiscordApplicationRoleConnection>
getVanityUrl: (guildId: BigString) => Promise<CamelizedDiscordVanityUrl>
getVoiceRegions: (guildId: BigString) => Promise<CamelizedDiscordVoiceRegion[]>
getWebhook: (webhookId: BigString) => Promise<Webhook>
@@ -746,11 +830,19 @@ export interface BotHelpers {
startThreadWithMessage: (channelId: BigString, messageId: BigString, options: StartThreadWithMessage, reason?: string) => Promise<Channel>
startThreadWithoutMessage: (channelId: BigString, options: StartThreadWithoutMessage, reason?: string) => Promise<Channel>
syncGuildTemplate: (guildId: BigString) => Promise<Template>
upsertGlobalApplicationCommands: (commands: CreateApplicationCommand[]) => Promise<ApplicationCommand[]>
upsertGuildApplicationCommands: (guildId: BigString, commands: CreateApplicationCommand[]) => Promise<ApplicationCommand[]>
upsertGlobalApplicationCommands: (
commands: CreateApplicationCommand[],
options?: UpsertGlobalApplicationCommandOptions,
) => Promise<ApplicationCommand[]>
upsertGuildApplicationCommands: (
guildId: BigString,
commands: CreateApplicationCommand[],
options?: UpsertGuildApplicationCommandOptions,
) => Promise<ApplicationCommand[]>
editBotMember: (guildId: BigString, options: EditBotMemberOptions, reason?: string) => Promise<Member>
editMember: (guildId: BigString, userId: BigString, options: ModifyGuildMember, reason?: string) => Promise<Member>
getMember: (guildId: BigString, userId: BigString) => Promise<Member>
getCurrentMember: (guildId: BigString, bearerToken: string) => Promise<Member>
getMembers: (guildId: BigString, options: ListGuildMembers) => Promise<Member[]>
pruneMembers: (guildId: BigString, options: BeginGuildPrune, reason?: string) => Promise<{ pruned: number | null }>
searchMembers: (guildId: BigString, query: string, options?: Omit<SearchMembers, 'query'>) => Promise<Member[]>
@@ -759,6 +851,8 @@ export interface BotHelpers {
addReactions: (channelId: BigString, messageId: BigString, reactions: string[], ordered?: boolean) => Promise<void>
addRole: (guildId: BigString, userId: BigString, roleId: BigString, reason?: string) => Promise<void>
addThreadMember: (channelId: BigString, userId: BigString) => Promise<void>
addDmRecipient: (channelId: BigString, userId: BigString, options: AddDmRecipientOptions) => Promise<void>
addGuildMember: (guildId: BigString, userId: BigString, options: AddGuildMemberOptions) => Promise<void>
deleteAutomodRule: (guildId: BigString, ruleId: BigString, reason?: string) => Promise<void>
deleteChannel: (channelId: BigString, reason?: string) => Promise<void>
deleteChannelPermissionOverride: (channelId: BigString, overwriteId: BigString, reason?: string) => Promise<void>
@@ -794,6 +888,7 @@ export interface BotHelpers {
leaveThread: (channelId: BigString) => Promise<void>
removeRole: (guildId: BigString, userId: BigString, roleId: BigString, reason?: string) => Promise<void>
removeThreadMember: (channelId: BigString, userId: BigString) => Promise<void>
removeDmRecipient: (channelId: BigString, userId: BigString) => Promise<void>
sendInteractionResponse: (interactionId: BigString, token: string, options: InteractionResponse) => Promise<void>
triggerTypingIndicator: (channelId: BigString) => Promise<void>
banMember: (guildId: BigString, userId: BigString, options?: CreateGuildBan, reason?: string) => Promise<void>