Skip to content

Commit

Permalink
feat(Client): enforce passing scopes to generateInvite (#6024)
Browse files Browse the repository at this point in the history
Co-authored-by: Antonio Román <kyradiscord@gmail.com>
Co-authored-by: SpaceEEC <spaceeec@yahoo.com>
  • Loading branch information
3 people committed Jul 4, 2021
1 parent 9e08b02 commit c6e5521
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 15 deletions.
37 changes: 23 additions & 14 deletions src/client/Client.js
Expand Up @@ -375,10 +375,10 @@ class Client extends BaseClient {
/**
* Options for {@link Client#generateInvite}.
* @typedef {Object} InviteGenerationOptions
* @property {InviteScope[]} scopes Scopes that should be requested
* @property {PermissionResolvable} [permissions] Permissions to request
* @property {GuildResolvable} [guild] Guild to preselect
* @property {boolean} [disableGuildSelect] Whether to disable the guild selection
* @property {InviteScope[]} [additionalScopes] Whether any additional scopes should be requested
*/

/**
Expand All @@ -387,11 +387,17 @@ class Client extends BaseClient {
* @returns {string}
* @example
* const link = client.generateInvite({
* scopes: ['applications.commands'],
* });
* console.log(`Generated application invite link: ${link}`);
* @example
* const link = client.generateInvite({
* permissions: [
* Permissions.FLAGS.SEND_MESSAGES,
* Permissions.FLAGS.MANAGE_GUILD,
* Permissions.FLAGS.MENTION_EVERYONE,
* ],
* scopes: ['bot'],
* });
* console.log(`Generated bot invite link: ${link}`);
*/
Expand All @@ -401,9 +407,24 @@ class Client extends BaseClient {

const query = new URLSearchParams({
client_id: this.application.id,
scope: 'bot',
});

const { scopes } = options;
if (typeof scopes === 'undefined') {
throw new TypeError('INVITE_MISSING_SCOPES');
}
if (!Array.isArray(scopes)) {
throw new TypeError('INVALID_TYPE', 'scopes', 'Array of Invite Scopes', true);
}
if (!scopes.some(scope => ['bot', 'applications.commands'].includes(scope))) {
throw new TypeError('INVITE_MISSING_SCOPES');
}
const invalidScope = scopes.find(scope => !InviteScopes.includes(scope));
if (invalidScope) {
throw new TypeError('INVALID_ELEMENT', 'Array', 'scopes', invalidScope);
}
query.set('scope', scopes.join(' '));

if (options.permissions) {
const permissions = Permissions.resolve(options.permissions);
if (permissions) query.set('permissions', permissions);
Expand All @@ -419,18 +440,6 @@ class Client extends BaseClient {
query.set('guild_id', guildId);
}

if (options.additionalScopes) {
const scopes = options.additionalScopes;
if (!Array.isArray(scopes)) {
throw new TypeError('INVALID_TYPE', 'additionalScopes', 'Array of Invite Scopes', true);
}
const invalidScope = scopes.find(scope => !InviteScopes.includes(scope));
if (invalidScope) {
throw new TypeError('INVALID_ELEMENT', 'Array', 'additionalScopes', invalidScope);
}
query.set('scope', ['bot', ...scopes].join(' '));
}

return `${this.options.http.api}${this.api.oauth2.authorize}?${query}`;
}

Expand Down
2 changes: 2 additions & 0 deletions src/errors/Messages.js
Expand Up @@ -132,6 +132,8 @@ const Messages = {
INTERACTION_EPHEMERAL_REPLIED: 'Ephemeral responses cannot be fetched or deleted.',
INTERACTION_FETCH_EPHEMERAL: 'Ephemeral responses cannot be fetched.',

INVITE_MISSING_SCOPES: 'At least one valid scope must be provided for the invite',

NOT_IMPLEMENTED: (what, name) => `Method ${what} not implemented on ${name}.`,
};

Expand Down
1 change: 1 addition & 0 deletions src/util/Constants.js
Expand Up @@ -328,6 +328,7 @@ exports.InviteScopes = [
'applications.commands',
'applications.entitlements',
'applications.store.update',
'bot',
'connections',
'email',
'identity',
Expand Down
2 changes: 1 addition & 1 deletion typings/index.d.ts
Expand Up @@ -3696,7 +3696,7 @@ declare module 'discord.js' {
permissions?: PermissionResolvable;
guild?: GuildResolvable;
disableGuildSelect?: boolean;
additionalScopes?: InviteScope[];
scopes: InviteScope[];
}

interface CreateInviteOptions {
Expand Down

0 comments on commit c6e5521

Please sign in to comment.