diff --git a/package.json b/package.json index 5f1af9a..bdf9019 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "discord.js-selfbot-v13", - "version": "0.2.3", + "version": "0.2.4", "description": "A unofficial discord.js fork for creating selfbots [Based on discord.js v13]", "main": "./src/index.js", "types": "./typings/index.d.ts", diff --git a/src/structures/User.js b/src/structures/User.js index 762dfcb..c4d76d4 100644 --- a/src/structures/User.js +++ b/src/structures/User.js @@ -13,167 +13,170 @@ const TextBasedChannel = require('./interfaces/TextBasedChannel'); * @extends {Base} */ class User extends Base { - constructor(client, data) { - super(client); + constructor(client, data) { + super(client); - /** - * The user's id - * @type {Snowflake} - */ - this.id = data.id; + /** + * The user's id + * @type {Snowflake} + */ + this.id = data.id; - this.bot = null; + this.bot = null; - this.system = null; + this.system = null; - this.flags = null; + this.flags = null; - this.friend = client.friends.cache.has(this.id); + this.friend = client.friends.cache.has(this.id); - this.blocked = client.blocked.cache.has(this.id); + this.blocked = client.blocked.cache.has(this.id); - // Code written by https://github.com/aiko-chan-ai - this.connectedAccounds = []; - this.premiumSince = null; - this.premiumGuildSince = null; - this.mutualGuilds = new Collection(); + // Code written by https://github.com/aiko-chan-ai + this.connectedAccounds = []; + this.premiumSince = null; + this.premiumGuildSince = null; + this.mutualGuilds = new Collection(); - this._patch(data); - } + this._patch(data); + } - _patch(data) { - if ('username' in data) { - /** - * The username of the user - * @type {?string} - */ - this.username = data.username; - } else { - this.username ??= null; - } + _patch(data) { + if ('username' in data) { + /** + * The username of the user + * @type {?string} + */ + this.username = data.username; + } else { + this.username ??= null; + } - if ('bot' in data) { - /** - * Whether or not the user is a bot - * @type {?boolean} - */ - this.bot = Boolean(data.bot); - } else if (!this.partial && typeof this.bot !== 'boolean') { - this.bot = false; - } + if ('bot' in data) { + /** + * Whether or not the user is a bot + * @type {?boolean} + */ + this.bot = Boolean(data.bot); + } else if (!this.partial && typeof this.bot !== 'boolean') { + this.bot = false; + } - if ('discriminator' in data) { - /** - * A discriminator based on username for the user - * @type {?string} - */ - this.discriminator = data.discriminator; - } else { - this.discriminator ??= null; - } + if ('discriminator' in data) { + /** + * A discriminator based on username for the user + * @type {?string} + */ + this.discriminator = data.discriminator; + } else { + this.discriminator ??= null; + } - if ('avatar' in data) { - /** - * The user avatar's hash - * @type {?string} - */ - this.avatar = data.avatar; - } else { - this.avatar ??= null; - } + if ('avatar' in data) { + /** + * The user avatar's hash + * @type {?string} + */ + this.avatar = data.avatar; + } else { + this.avatar ??= null; + } - if ('banner' in data) { - /** - * The user banner's hash - * The user must be force fetched for this property to be present or be updated - * @type {?string} - */ - this.banner = data.banner; - } else if (this.banner !== null) { - this.banner ??= undefined; - } + if ('banner' in data) { + /** + * The user banner's hash + * The user must be force fetched for this property to be present or be updated + * @type {?string} + */ + this.banner = data.banner; + } else if (this.banner !== null) { + this.banner ??= undefined; + } - if ('accent_color' in data) { - /** - * The base 10 accent color of the user's banner - * The user must be force fetched for this property to be present or be updated - * @type {?number} - */ - this.accentColor = data.accent_color; - } else if (this.accentColor !== null) { - this.accentColor ??= undefined; - } + if ('accent_color' in data) { + /** + * The base 10 accent color of the user's banner + * The user must be force fetched for this property to be present or be updated + * @type {?number} + */ + this.accentColor = data.accent_color; + } else if (this.accentColor !== null) { + this.accentColor ??= undefined; + } - if ('system' in data) { - /** - * Whether the user is an Official Discord System user (part of the urgent message system) - * @type {?boolean} - */ - this.system = Boolean(data.system); - } else if (!this.partial && typeof this.system !== 'boolean') { - this.system = false; - } + if ('system' in data) { + /** + * Whether the user is an Official Discord System user (part of the urgent message system) + * @type {?boolean} + */ + this.system = Boolean(data.system); + } else if (!this.partial && typeof this.system !== 'boolean') { + this.system = false; + } - if ('public_flags' in data) { - /** - * The flags for this user - * @type {?UserFlagsBitField} - */ - this.flags = new UserFlagsBitField(data.public_flags); - } - } + if ('public_flags' in data) { + /** + * The flags for this user + * @type {?UserFlagsBitField} + */ + this.flags = new UserFlagsBitField(data.public_flags); + } + } - // Code written by https://github.com/aiko-chan-ai - _ProfilePatch(data) { - if(!data) return; + // Code written by https://github.com/aiko-chan-ai + _ProfilePatch(data) { + if (!data) return; - if(data.connected_accounts.length > 0) this.connectedAccounds = data.connected_accounts; + if (data.connected_accounts.length > 0) + this.connectedAccounds = data.connected_accounts; - if('premium_since' in data) { - const date = new Date(data.premium_since); - this.premiumSince = date.getTime(); - } + if ('premium_since' in data) { + const date = new Date(data.premium_since); + this.premiumSince = date.getTime(); + } - if('premium_guild_since' in data) { - const date = new Date(data.premium_guild_since); - this.premiumGuildSince = date.getTime(); - } + if ('premium_guild_since' in data) { + const date = new Date(data.premium_guild_since); + this.premiumGuildSince = date.getTime(); + } - this.mutualGuilds = new Collection(data.mutual_guilds.map((obj) => [obj.id, obj])); - } + this.mutualGuilds = new Collection( + data.mutual_guilds.map((obj) => [obj.id, obj]), + ); + } - /** - * Get profile from Discord, if client is in a server with the target. - *
Code written by https://github.com/aiko-chan-ai - */ - async getProfile() { - if(this.client.bot) throw new Error('INVALID_BOT_METHOD'); - try { - const data = await this.client.api.users(this.id).profile.get(); - this._ProfilePatch(data); - return this - } catch (e) { - throw e - } - } + /** + * Get profile from Discord, if client is in a server with the target. + *
Code written by https://github.com/aiko-chan-ai + */ + async getProfile() { + if (this.client.bot) throw new Error('INVALID_BOT_METHOD'); + try { + const data = await this.client.api.users(this.id).profile.get(); + this._ProfilePatch(data); + return this; + } catch (e) { + throw e; + } + } - /** - * Friends the user and send Request [If no request] - * @returns {Promise} the user object - */ - async setFriend() { - return await this.client.api + /** + * Friends the user and send Request [If no request] + * @returns {Promise} the user object + */ + async setFriend() { + return await this.client.api .user('@me') .relationships[this.id].put({ data: { type: 1 } }) .then((_) => _); - } + } - /** - * Send Friend Request to the user - * @returns {Promise} the user object - */ - async sendFriendRequest() { - return await this.client.api + /** + * Send Friend Request to the user + * @returns {Promise} the user object + */ + async sendFriendRequest() { + return await this.client.api .users('@me') .relationships.post({ data: { @@ -182,247 +185,256 @@ class User extends Base { }, }) .then((_) => _); - } - /** - * Blocks the user - * @returns {Promise} the user object - */ - async setBlock() { - return this.client.api - .users('@me') - .relationships[this.id].put({data:{type: 2}}) - .then(_ => _) - } + } + /** + * Blocks the user + * @returns {Promise} the user object + */ + async setBlock() { + return this.client.api + .users('@me') + .relationships[this.id].put({ data: { type: 2 } }) + .then((_) => _); + } - /** - * Removes the user from your blocks list - * @returns {Promise} the user object - */ - async unBlock() { - return this.client.api - .users('@me') - .relationships[this.id].delete - .then(_ => _) - } + /** + * Removes the user from your blocks list + * @returns {Promise} the user object + */ + async unBlock() { + return this.client.api + .users('@me') + .relationships[this.id].delete.then((_) => _); + } - /** - * Removes the user from your friends list - * @returns {Promise} the user object - */ - async unFriend() { - return this.client.api - .users('@me') - .relationships[this.id].delete - .then(_ => _) - } + /** + * Removes the user from your friends list + * @returns {Promise} the user object + */ + async unFriend() { + return this.client.api + .users('@me') + .relationships[this.id].delete.then((_) => _); + } - /** - * Whether this User is a partial - * @type {boolean} - * @readonly - */ - get partial() { - return typeof this.username !== 'string'; - } + /** + * Whether this User is a partial + * @type {boolean} + * @readonly + */ + get partial() { + return typeof this.username !== 'string'; + } - /** - * The timestamp the user was created at - * @type {number} - * @readonly - */ - get createdTimestamp() { - return DiscordSnowflake.timestampFrom(this.id); - } + /** + * The timestamp the user was created at + * @type {number} + * @readonly + */ + get createdTimestamp() { + return DiscordSnowflake.timestampFrom(this.id); + } - /** - * The time the user was created at - * @type {Date} - * @readonly - */ - get createdAt() { - return new Date(this.createdTimestamp); - } + /** + * The time the user was created at + * @type {Date} + * @readonly + */ + get createdAt() { + return new Date(this.createdTimestamp); + } - /** - * A link to the user's avatar. - * @param {ImageURLOptions} [options={}] Options for the image URL - * @returns {?string} - */ - avatarURL(options = {}) { - return this.avatar && this.client.rest.cdn.avatar(this.id, this.avatar, options); - } + /** + * A link to the user's avatar. + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + avatarURL({ format, size, dynamic } = {}) { + if (!this.avatar) return null; + return this.client.rest.cdn.Avatar( + this.id, + this.avatar, + format, + size, + dynamic, + ); + } - /** - * If the user is a bot then it'll return the slash commands else return null - * @readonly - */ - get slashCommands() { - if(this.bot) { - return this.client.api.applications(this.id).commands.get(); - } else return null; - } + /** + * If the user is a bot then it'll return the slash commands else return null + * @readonly + */ + get slashCommands() { + if (this.bot) { + return this.client.api.applications(this.id).commands.get(); + } else return null; + } - /** - * A link to the user's default avatar - * @type {string} - * @readonly - */ - get defaultAvatarURL() { - return this.client.rest.cdn.defaultAvatar(this.discriminator % 5); - } + /** + * A link to the user's default avatar + * @type {string} + * @readonly + */ + get defaultAvatarURL() { + return this.client.rest.cdn.defaultAvatar(this.discriminator % 5); + } - /** - * A link to the user's avatar if they have one. - * Otherwise a link to their default avatar will be returned. - * @param {ImageURLOptions} [options={}] Options for the Image URL - * @returns {string} - */ - displayAvatarURL(options) { - return this.avatarURL(options) ?? this.defaultAvatarURL; - } + /** + * A link to the user's avatar if they have one. + * Otherwise a link to their default avatar will be returned. + * @param {ImageURLOptions} [options={}] Options for the Image URL + * @returns {string} + */ + displayAvatarURL(options) { + return this.avatarURL(options) ?? this.defaultAvatarURL; + } - /** - * The hexadecimal version of the user accent color, with a leading hash - * The user must be force fetched for this property to be present - * @type {?string} - * @readonly - */ - get hexAccentColor() { - if (typeof this.accentColor !== 'number') return this.accentColor; - return `#${this.accentColor.toString(16).padStart(6, '0')}`; - } + /** + * The hexadecimal version of the user accent color, with a leading hash + * The user must be force fetched for this property to be present + * @type {?string} + * @readonly + */ + get hexAccentColor() { + if (typeof this.accentColor !== 'number') return this.accentColor; + return `#${this.accentColor.toString(16).padStart(6, '0')}`; + } - /** - * A link to the user's banner. See {@link User#banner} for more info - * @param {ImageURLOptions} [options={}] Options for the image URL - * @returns {?string} - */ - bannerURL(options = {}) { - return this.banner && this.client.rest.cdn.banner(this.id, this.banner, options); - } + /** + * A link to the user's banner. See {@link User#banner} for more info + * @param {ImageURLOptions} [options={}] Options for the image URL + * @returns {?string} + */ + bannerURL(options = {}) { + return ( + this.banner && this.client.rest.cdn.banner(this.id, this.banner, options) + ); + } - /** - * The Discord "tag" (e.g. `hydrabolt#0001`) for this user - * @type {?string} - * @readonly - */ - get tag() { - return typeof this.username === 'string' ? `${this.username}#${this.discriminator}` : null; - } + /** + * The Discord "tag" (e.g. `hydrabolt#0001`) for this user + * @type {?string} + * @readonly + */ + get tag() { + return typeof this.username === 'string' + ? `${this.username}#${this.discriminator}` + : null; + } - /** - * The DM between the client's user and this user - * @type {?DMChannel} - * @readonly - */ - get dmChannel() { - return this.client.users.dmChannel(this.id); - } + /** + * The DM between the client's user and this user + * @type {?DMChannel} + * @readonly + */ + get dmChannel() { + return this.client.users.dmChannel(this.id); + } - /** - * Creates a DM channel between the client and the user. - * @param {boolean} [force=false] Whether to skip the cache check and request the API - * @returns {Promise} - */ - createDM(force = false) { - return this.client.users.createDM(this.id, force); - } + /** + * Creates a DM channel between the client and the user. + * @param {boolean} [force=false] Whether to skip the cache check and request the API + * @returns {Promise} + */ + createDM(force = false) { + return this.client.users.createDM(this.id, force); + } - /** - * Deletes a DM channel (if one exists) between the client and the user. Resolves with the channel if successful. - * @returns {Promise} - */ - deleteDM() { - return this.client.users.deleteDM(this.id); - } + /** + * Deletes a DM channel (if one exists) between the client and the user. Resolves with the channel if successful. + * @returns {Promise} + */ + deleteDM() { + return this.client.users.deleteDM(this.id); + } - /** - * Checks if the user is equal to another. - * It compares id, username, discriminator, avatar, banner, accent color, and bot flags. - * It is recommended to compare equality by using `user.id === user2.id` unless you want to compare all properties. - * @param {User} user User to compare with - * @returns {boolean} - */ - equals(user) { - return ( - user && - this.id === user.id && - this.username === user.username && - this.discriminator === user.discriminator && - this.avatar === user.avatar && - this.flags?.bitfield === user.flags?.bitfield && - this.banner === user.banner && - this.accentColor === user.accentColor - ); - } + /** + * Checks if the user is equal to another. + * It compares id, username, discriminator, avatar, banner, accent color, and bot flags. + * It is recommended to compare equality by using `user.id === user2.id` unless you want to compare all properties. + * @param {User} user User to compare with + * @returns {boolean} + */ + equals(user) { + return ( + user && + this.id === user.id && + this.username === user.username && + this.discriminator === user.discriminator && + this.avatar === user.avatar && + this.flags?.bitfield === user.flags?.bitfield && + this.banner === user.banner && + this.accentColor === user.accentColor + ); + } - /** - * Compares the user with an API user object - * @param {APIUser} user The API user object to compare - * @returns {boolean} - * @private - */ - _equals(user) { - return ( - user && - this.id === user.id && - this.username === user.username && - this.discriminator === user.discriminator && - this.avatar === user.avatar && - this.flags?.bitfield === user.public_flags && - ('banner' in user ? this.banner === user.banner : true) && - ('accent_color' in user ? this.accentColor === user.accent_color : true) - ); - } + /** + * Compares the user with an API user object + * @param {APIUser} user The API user object to compare + * @returns {boolean} + * @private + */ + _equals(user) { + return ( + user && + this.id === user.id && + this.username === user.username && + this.discriminator === user.discriminator && + this.avatar === user.avatar && + this.flags?.bitfield === user.public_flags && + ('banner' in user ? this.banner === user.banner : true) && + ('accent_color' in user ? this.accentColor === user.accent_color : true) + ); + } - /** - * Fetches this user's flags. - * @param {boolean} [force=false] Whether to skip the cache check and request the API - * @returns {Promise} - */ - fetchFlags(force = false) { - return this.client.users.fetchFlags(this.id, { force }); - } + /** + * Fetches this user's flags. + * @param {boolean} [force=false] Whether to skip the cache check and request the API + * @returns {Promise} + */ + fetchFlags(force = false) { + return this.client.users.fetchFlags(this.id, { force }); + } - /** - * Fetches this user. - * @param {boolean} [force=true] Whether to skip the cache check and request the API - * @returns {Promise} - */ - fetch(force = true) { - return this.client.users.fetch(this.id, { force }); - } + /** + * Fetches this user. + * @param {boolean} [force=true] Whether to skip the cache check and request the API + * @returns {Promise} + */ + fetch(force = true) { + return this.client.users.fetch(this.id, { force }); + } - /** - * When concatenated with a string, this automatically returns the user's mention instead of the User object. - * @returns {string} - * @example - * // Logs: Hello from <@123456789012345678>! - * console.log(`Hello from ${user}!`); - */ - toString() { - return `<@${this.id}>`; - } + /** + * When concatenated with a string, this automatically returns the user's mention instead of the User object. + * @returns {string} + * @example + * // Logs: Hello from <@123456789012345678>! + * console.log(`Hello from ${user}!`); + */ + toString() { + return `<@${this.id}>`; + } - toJSON(...props) { - const json = super.toJSON( - { - createdTimestamp: true, - defaultAvatarURL: true, - hexAccentColor: true, - tag: true, - }, - ...props, - ); - json.avatarURL = this.avatarURL(); - json.displayAvatarURL = this.displayAvatarURL(); - json.bannerURL = this.banner ? this.bannerURL() : this.banner; - return json; - } + toJSON(...props) { + const json = super.toJSON( + { + createdTimestamp: true, + defaultAvatarURL: true, + hexAccentColor: true, + tag: true, + }, + ...props, + ); + json.avatarURL = this.avatarURL(); + json.displayAvatarURL = this.displayAvatarURL(); + json.bannerURL = this.banner ? this.bannerURL() : this.banner; + return json; + } - // These are here only for documentation purposes - they are implemented by TextBasedChannel - /* eslint-disable no-empty-function */ - send() {} + // These are here only for documentation purposes - they are implemented by TextBasedChannel + /* eslint-disable no-empty-function */ + send() {} } TextBasedChannel.applyToClass(User); diff --git a/src/util/Constants.js b/src/util/Constants.js index 63a780a..6bbe129 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -200,6 +200,12 @@ exports.Events = { GUILD_SCHEDULED_EVENT_USER_REMOVE: 'guildScheduledEventUserRemove', }; +const AllowedImageFormats = ['webp', 'png', 'jpg', 'jpeg', 'gif']; + +const AllowedImageSizes = [ + 16, 32, 56, 64, 96, 128, 256, 300, 512, 600, 1024, 2048, 4096, +]; + function makeImageUrl(root, { format = 'webp', size } = {}) { if (!['undefined', 'number'].includes(typeof size)) throw new TypeError('INVALID_TYPE', 'size', 'number'); if (format && !AllowedImageFormats.includes(format)) throw new Error('IMAGE_FORMAT', format); diff --git a/src/util/Options.js b/src/util/Options.js index def5ee1..5be7be5 100644 --- a/src/util/Options.js +++ b/src/util/Options.js @@ -101,7 +101,7 @@ class Options extends null { $browser: 'Chrome', $device: 'ASUS ROG Phone 5', }, - version: 9, + version: 10, }, http: { headers: {