How to create a vulnerability scanner ping #everyone? Discord.js - javascript

I had an idea to create a useful team for server administrators.
Thanks to this command, the bot shows in which channels you can ping #everyone #here.
Who has any suggestions on how to create this?

#user15517071's answer would work but only if #everyone has no 'MENTION_EVERYONE' permission by default. If you also want to check that, you will need to update your filter.
Check out the code below, I've added plenty of comments:
const textChannels = message.guild.channels.cache.filter((ch) => ch.type === 'text');
const canEveryoneMention = message.guild.roles.everyone.permissions.has('MENTION_EVERYONE');
const channelsWhereEveryoneCanBeMentioned = textChannels
.map((channel) => {
// if there are no overwrites, and everyone can mention #everyone by default
if (!channel.permissionOverwrites.size && canEveryoneMention)
return channel;
// a filter to check if the overwrites allow to mention #everyone
const overwriteFilter = (overwrite) => {
// only check if the overwrite belongs to the #everyone role
if (overwrite.id !== message.guild.id)
return false;
// check if MENTION_EVERYONE is allowed
if (overwrite.allow.has('MENTION_EVERYONE'))
return true;
// or it is allowed by default and it's not denied in this overwrite
if (canEveryoneMention && !overwrite.deny.has('MENTION_EVERYONE'))
return true;
// all other cases
return false;
};
const overwrites = channel.permissionOverwrites.filter(overwriteFilter);
// only return the channel if there are "valid" overwrites
return overwrites.size > 0 ? channel : null;
})
// remove null values
.filter(Boolean);
const channelList = channelsWhereEveryoneCanBeMentioned.join('\n');
message.channel.send(`People can mention everyone in the following channels:\n${channelList}`);

You can iterate through the TextChannels in a guild and look for channels where, say, #everyone has the MENTION_EVERYONE permission, allowing anyone to ping #everyone or #here.
For example, the below code finds all the TextChannels in a guild, then checks if there is a permission overwrite for #everyone and then checks if MENTION_EVERYONE is explicitly allowed.
const vulnerableChannels = [];
const channels = message.guild.channels.cache.array().filter(channel => channel.type === 'text');
for (const channel of channels) {
if (channel.permissionOverwrites.filter(overwrite => overwrite.id === message.guild.id && overwrite.allow.has('MENTION_EVERYONE')).array().length > 0) vulnerableChannels.push(channel.id);
}
let output = 'The following channel(s) are vulnerable:\n';
vulnerableChannels.forEach(channel => output = output.concat(` • <#${channel}>\n`));
message.channel.send(output);

Related

Can't send a message to a specific channel

I'm trying to create a modmail system and whenever I try to make it, it says "channel.send is not a function, here is my code."
const Discord = require("discord.js")
const client = new Discord.Client()
const db = require('quick.db')
// ...
client.on('message', message => {
if(db.fetch(`ticket-${message.author.id}`)){
if(message.channel.type == "dm"){
const channel = client.channels.cache.get(id => id.name == `ticket-${message.author.id}`)
channel.send(message.content)
}
}
})
// ...
client.login("MYTOKEN")
I'm trying this with version 12.0.0
EDIT:
I found my issue, for some reason the saved ID is the bots ID, not my ID
As MrMythical said, you should use the find function instead of get. I believe the issue is that you're grabbing a non-text channel, since channel is defined, you just can't send anything to it.
You could fix this by adding an additional catch to ensure you are getting a text channel, and not a category or voice channel. I would also return (or do an error message of sorts) if channel is undefined.
Discord.js v12:
const channel = client.channels.cache.find(c => c.name === `ticket-${message.author.id}` && c.type === 'text');
Discord.js v13:
const channel = client.channels.cache.find(c => c.name === `ticket-${message.author.id}` && c.type === 'GUILD_TEXT');
Edit:
You can tell channel is defined because if it weren't it would say something along the lines of: Cannot read property 'send' of undefined.
You are trying to find it with a function. Use .find for that instead:
const channel = client.channels.cache.find(id => id.name == `ticket-${message.author.id}`)

Doesn't create the voice channel with no error

I am trying to build a bot with the discord.js library in node.js that will create a new voice channel in a certain category when a user joins a certain channel. After the creation of the channel, I want the bot to then move the user to the new channel!
I am trying the following code:
var temporary = [];
client.on('voiceStateUpdate', async (oldMember, newMember) => {
const mainCatagory = '815281015207624704';
const mainChannel = '814938402137833484';
if (newMember.voiceChannelID == mainChannel) {
await newMember.guild
.createChannel(`📞 ┋ Support Room`, { type: 'voice', parent: mainCatagory })
.then(async (channel) => {
temporary.push({ newID: channel.id, guild: newMember.guild.id });
await newMember.setVoiceChannel(channel.id);
});
}
if (temporary.length >= 0)
for (let i = 0; i < temporary.length; i++) {
let ch = client.guilds
.find((x) => x.id === temporary[i].guild)
.channels.find((x) => x.id === temporary[i].newID);
if (ch.members.size <= 0) {
await ch.delete();
return temporary.splice(i, 1);
}
}
});
The code comes with no error but doesn't create the voice channel!
The problem is that you are using discord.js v12, but your code is made for v11.
Client#voiceStateUpdate now passes VoiceStates as parameters, not GuildMembers. You should rename newMember and oldMember to newState and oldState respectively.
GuildMember#voiceChannelID is a deprecated property, which is why you don't get any errors. Your code never actually gets past the if statement. It has turned into GuildMember#voice#channelID (newState.channelID).
Guild#createChannel is also deprecated, being replaced with Guild#channels#create. The function still looks and acts the same, so you only need to change the name (newState.guild.channels.create).
GuildMember#setVoiceChannel has turned into GuildMember#voice#setChannel (newState.setChannel)
Client#guilds#find has turned into Client#guilds#cache#find (client.guilds.cache.find)
Guild#channels#find has turned into Guild#channels#cache#find (client.cache.find(...).channels.cache.find)
(As a side note, always use Collection#get instead of Collection#find when searching by IDs. .find((value) => value.id === '...') should always be converted to simply .get('...'). This also applies to switching Collection#some with Collection#has)
Guild#members#size has turned into Guild#members#cache#size (ch.members.cache.size)
Every single one of these deprecations occurred as a result of discord.js switching to a Manager/caching system. For example, Client#guilds now returns a GuildManager instead of a collection.
More information about switching from v11 to v12 (including Managers)

Add user ID to Array to be banned upon return to guild?

As stated in the title I'm wanting to extend the current code I have for a ban function (included below).
If a user has left the guild/server how would I add their userID into an Array? This way I can loop through it every time someone joins the guild and check if they were previously banned: if so, they will be properly banned.
So the process would be:
<prefix>ban <userid>
If the user is not in the guild then add the ID to an Array and display a ban message
When a new member joins, check them against the Array and if ID exists then ban them and remove them from Array.
switch (args[0]) {
case 'ban':
if (!message.content.startsWith(PREFIX)) return;
if (!message.member.roles.cache.find(r => r.name === 'Moderator') && !message.member.roles.cache.find(r => r.name === 'Staff')) return message.channel.send('You dont not have the required permissions').then(msg => {
msg.delete({ timeout: 5000 })
})
var user1 = message.mentions.users.first();
if (member) {
// There's a valid user, you can do your stuff as usual
member.ban().then(() => {
message.channel.send('User has been banned')
})
} else {
let user = message.mentions.users.first(),
// The ID will be either picked from the mention (if there's one) or from the argument
// (I used args, I don't know how your variable's called)
userID = user ? user.id : args[1]
if (userID) {
// Read the existing banned ids. You can choose your own path for the JSON file
let bannedIDs = require('./bannedIDs.json').ids || []
// If this is a new ID, add it to the array
if (!bannedIDs.includes(userID)) bannedIDs.push(userID)
// Save the file
fs.writeFileSync('./bannedIDs.json', JSON.stringify({ ids: bannedIDs }))
// You can then send any message you want
message.channel.send('User added to the list')
} else {
message.channel.send('No ID was entered')
}
}
}
}
);
bot.on('guildMemberAdd', member => {
let banned = require('./bannedIDs.json').ids || []
if (banned.includes(member.id)) {
// The user should be properly banned
member.ban({
reason: 'Previously banned by a moderator.'
})
// You can also remove them from the array
let newFile = {
ids: banned.filter(id => id != member.id)
}
fs.writeFileSync('./bannedIDs.json', JSON.stringify(newFile))
}
})
This can be done, but you'll need to grab the user ID manually since you can't mention someone that's not in the guild (you technically can, but you would need to grab the ID anyway).
If there's no user mention or if there's one, but the user isn't in the guild, you'll need to grab their ID and push it to an array. You may want to save that array in a JSON file so it's kept between reloads: you can use fs.writeFileSync() for that.
Here's an example:
let member = message.mentions.members.first()
if (member) {
// There's a valid user, you can do your stuff as usual
member.ban().then(() => {
message.channel.send('User has been banned')
})
} else {
let user = message.mentions.users.first(),
// The ID will be either picked from the mention (if there's one) or from the argument
// (I used args, I don't know how your variable's called)
userID = user ? user.id : args[0]
if (userID) {
// Read the existing banned ids. You can choose your own path for the JSON file
let bannedIDs = require('./bannedIDs.json').ids || [] // WRONG: read the edit below
// If this is a new ID, add it to the array
if (!bannedIDs.includes(userID)) bannedIDs.push(userID)
// Save the file
fs.writeFileSync('./bannedIDs.json', JSON.stringify({ ids: bannedIDs }))
// You can then send any message you want
message.channel.send('User added to the list')
} else {
message.channel.send('No ID was entered')
}
}
Remember that you have to import the fs module, which is included with Node:
const fs = require('fs')
Also, create a JSON file that looks like this:
{
ids: []
}
When a new user joins, you can check their ID:
client.on('guildMemberAdd', member => {
let banned = require('./bannedIDs.json').ids || [] // WRONG: read the edit below
if (banned.includes(member.id)) {
// The user should be properly banned
member.ban({
reason: 'Previously banned by a moderator.'
})
// You can also remove them from the array
let newFile = {
ids: banned.filter(id => id != member.id)
}
fs.writeFileSync('./bannedIDs.json', JSON.stringify(newFile))
}
})
Edit:
How to solve the problem with the array being cached:
You load the array only once, when starting the bot, and store it in a variable. Every time you need to read or write to the array you use that variable, and periodically you update the JSON file.
As you mentioned in your comment, you can replace the require() with fs.readFileSync(). You can read the file with this fs method, and then you can parse the JSON object with the JSON.parse() function.
Here's how you can do it:
// Wrong way to do it:
let bannedIDs = require('./bannedIDs.json').ids || []
// Better way to do it:
let file = fs.readFileSync('./bannedIDs.json')
let bannedIDs = JSON.parse(file).ids || []

Adding/Removing Roles is not working (sometimes)

On some Discord servers my code to add/remove roles, however, on some it doesn't. I checked and they all have the correct permissions, so I'm kind of stumped.
Whenever I run the >addrole or >removerole command I always get the same Discord error message. It is ":x: Couldn't find mute role. Make sure you didn't make a typo (roles are case-sensitive too!)". I set this for when a user makes a typo while typing what role they want to add.
The format for the commands are as follows:
addrole [#User] [RoleName]
removerole [#User] [RoleName]
const Discord = require("discord.js");
exports.run = async(bot, message, args) => {
if (!message.member.hasPermission("MANAGE_ROLES")) return message.channel.send(":x: Insufficient permission.").then(msg => msg.delete(4000));
let rolemember = message.guild.member(message.mentions.users.first() || message.guild.members.get(args[0]));
if (!rolemember) return message.channel.send(":x: Could not find user.").then(msg => msg.delete(4000));
let role = args.join(" ").slice(22);
if (!role) return mesage.reply(":x: Specify a role.");
let gRole = message.guild.roles.find(`name`, role);
if (!gRole) return message.channel.send(":x: Couldn't find mute role. Make sure you didn't make a typo (roles are case-sensitive too!)");
if (!rolemember.roles.has(gRole.id)) return message.channel.send(`:x: User does not have role "${gRole.name}".`).then(msg => msg.delete(4000));
await (rolemember.removeRole(gRole.id));
try {
rolemember.send(`:white_check_mark: Your role "${gRole.name}" in`, message.guild.name, "has been removed :confused:.");
} catch (e) {
message.channel.send(`:white_check_mark: ${rolemember} Your role "${gRole.name}" has been removed :confused:.`);
}
let removeroleEmbed = new Discord.RichEmbed()
.setDescription("Role Changes")
.setColor("RANDOM")
.addField("Role Removed", gRole)
.addField("Removed From", rolemember)
.addField("Removed By", message.author);
let logChannel = message.guild.channels.find(`name`, "logs-reports");
if (!logChannel) return message.channel.send(":x: Couldn't find logs channel.").then(msg => msg.delete(4000));
logChannel.send(removeroleEmbed);
}
exports.help = {
name: "removerole"
}
I expect that the role should be added, however, it is not and the same error message is what I get every time.
As .find('name', 'name') is DEPRECATED. That thing you use may not work.. Instead, use let gRole = message.guild.roles.find(r => r.name === role). I am new to this community. So please fogive if I do something wrong.
Try replaceng the let gRole = message.guild.roles.find("name", role); with let gRole = message.guild.roles.find(r => r.name === role) This should work because it is how it is supposed to be, sorry I am not very good at explainin
Note:
Collection.find() is not totally deprecated, just format Collection.find("name", "yourName") is deprecated!

How to send message in Discord.js event "guildCreate"

I have been wondering how can I send messages when someone invites my bot to their server.
Please help me in this area I can't figure it out it's there in Python but I have not used to it.
Thank you for your help
All the above answers assume you know something about the server and in most cases you do not!
What you need to do is loop through the channels in the guild and find one that you have permission to text in.
You can get the channel cache from the guild.
Take the below example:
bot.on("guildCreate", guild => {
let defaultChannel = "";
guild.channels.cache.forEach((channel) => {
if(channel.type == "text" && defaultChannel == "") {
if(channel.permissionsFor(guild.me).has("SEND_MESSAGES")) {
defaultChannel = channel;
}
}
})
//defaultChannel will be the channel object that the bot first finds permissions for
defaultChannel.send('Hello, Im a Bot!')
});
You can of course do further checks to ensure you can text before texting but this will get you on the right path
Update discord.js 12+
Discord.JS now uses cache - here is the same answer for 12+
bot.on("guildCreate", guild => {
let found = 0;
guild.channels.cache.map((channel) => {
if (found === 0) {
if (channel.type === "text") {
if (channel.permissionsFor(bot.user).has("VIEW_CHANNEL") === true) {
if (channel.permissionsFor(bot.user).has("SEND_MESSAGES") === true) {
channel.send(`Hello - I'm a Bot!`);
found = 1;
}
}
}
}
});
})
You can simply send the owner for example a message using guild.author.send("Thanks for inviting my bot");
Or you can also send a message to a specific user:
client.users.get("USER ID").send("My bot has been invited to a new server!");
I'm not sure if you're using a command handler or not since you seem new to JS I'm going to assume you're not. The following is a code snippet for what you're trying to do:
client.on('guildCreate', (guild) => {
guild.channels.find(t => t.name == 'general').send('Hey their Im here now!'); // Change where it says 'general' if you wan't to look for a different channel name.
});

Categories

Resources