A portion of my soul.
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
.env
|
||||
package-lock.json
|
||||
@@ -0,0 +1,27 @@
|
||||
module.exports = {
|
||||
"prefix": "!?",
|
||||
"guilds": {
|
||||
"1033940528317866105": { //guild id
|
||||
"channelId": "1033941062101766245", //channel id where the command is allowed
|
||||
'roleToAdd': '1033996796109795408', //verified role id
|
||||
'firstRole': '1203243427081355264', //unverified role id
|
||||
},
|
||||
"1203447255491809351": {
|
||||
"channelId": "1203448057723748382",
|
||||
'roleToAdd': '1203448287894704178',
|
||||
'firstRole': '1203448332144611328',
|
||||
}
|
||||
},
|
||||
'captchaCount': '7',
|
||||
'captchaTimeout': '120000', //in milliseconds (seconds multiplied by 1000)
|
||||
'messages': {
|
||||
//literally messages lmao
|
||||
'toVerify': 'Please verify that you are not a robot.',
|
||||
'success': 'You have been verified successfully.',
|
||||
'fail': 'You have failed the captcha verification. Please try again.',
|
||||
'wrongChannel': 'You can\'t use this command here.',
|
||||
'alreadyVerified': 'You are already verified.',
|
||||
'tookTooLong': 'You took too long to respond. Please try again.',
|
||||
'unableToDM': 'I was unable to send you a DM. Please make sure "Allow Direct Message" for this guild is enabled.'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
const { EmbedBuilder, AttachmentBuilder } = require('discord.js');
|
||||
const client = require('..');
|
||||
const cfg = require('../config/config.js');
|
||||
|
||||
client.on('guildMemberAdd', async member => {
|
||||
//get guild id
|
||||
const guildId = member.guild.id;
|
||||
await member.roles.add(cfg.guilds[guildId].firstRole);
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
const { EmbedBuilder, Collection, PermissionsBitField, ChannelType } = require('discord.js');
|
||||
const client = require('..');
|
||||
const config = require('../config/config.js');
|
||||
|
||||
client.on('interactionCreate', async interaction => {
|
||||
const slashCommand = client.slashCommands.get(interaction.commandName);
|
||||
if (interaction.type === 4) {
|
||||
if (slashCommand.autocomplete) {
|
||||
const choices = [];
|
||||
await slashCommand.autocomplete(interaction, choices);
|
||||
}
|
||||
}
|
||||
if (!interaction.type === 2) return;
|
||||
|
||||
if (interaction.channel.type === ChannelType.DM) {
|
||||
return interaction.reply({ content: "This weren't supposed to be used here...", ephemeral: true });
|
||||
}
|
||||
|
||||
if (!slashCommand) return client.slashCommands.delete(interaction.commandName);
|
||||
|
||||
await slashCommand.run(client, interaction);
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
const { EmbedBuilder, Collection, PermissionsBitField, ChannelType } = require('discord.js');
|
||||
const client = require('..');
|
||||
const config = require('../config/config.js');
|
||||
|
||||
client.on('messageCreate', async message => {
|
||||
if (message.author.bot) return;
|
||||
if (message.channel.type === ChannelType.DM) return;
|
||||
if (!message.content.startsWith(config.prefix)) return;
|
||||
const args = message.content.slice(config.prefix.length).trim().split(/ +/);
|
||||
const cmd = args.shift().toLowerCase();
|
||||
if (cmd.length === 0) return;
|
||||
const commands = client.commands.get(cmd);
|
||||
|
||||
commands.run(client, message, args);
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
const { ActivityType } = require('discord.js');
|
||||
const client = require('..');
|
||||
const chalk = require('chalk');
|
||||
|
||||
client.on('ready', () => {
|
||||
console.log(chalk.green(`Logged in as ${client.user.tag}!`));
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
const fs = require('fs');
|
||||
const chalk = require('chalk');
|
||||
var AsciiTable = require('ascii-table');
|
||||
var table = new AsciiTable();
|
||||
table.setHeading('Buttons', 'Status').setBorder('|', '-', '+', '+');
|
||||
|
||||
module.exports.name = 'buttons';
|
||||
module.exports = (client) => {
|
||||
fs.readdirSync('./buttons/').filter((file) => file.endsWith('.js')).forEach((file) => {
|
||||
const button = require(`../buttons/${file}`);
|
||||
client.buttons.set(button.id, button);
|
||||
table.addRow(button.id, chalk.green('Loaded'));
|
||||
});
|
||||
|
||||
console.log(chalk.magenta(table.toString()));
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
const chalk = require('chalk');
|
||||
const fs = require('fs');
|
||||
const AsciiTable = require('ascii-table');
|
||||
const table = new AsciiTable();
|
||||
table.setHeading('Commands', 'Status').setBorder('|', '-', '+', '+');
|
||||
|
||||
module.exports.name = 'commands';
|
||||
module.exports = (client) => {
|
||||
fs.readdirSync('./commands/').forEach((dir) => {
|
||||
const files = fs.readdirSync(`./commands/${dir}`).filter((file) => file.endsWith('.js'));
|
||||
if (files.length <= 0) return;
|
||||
files.forEach((file) => {
|
||||
let command = require(`../commands/${dir}/${file}`);
|
||||
if (command) {
|
||||
client.commands.set(command.name, command);
|
||||
table.addRow(command.name, chalk.green('Loaded'));
|
||||
} else {
|
||||
table.addRow(file, chalk.red('Failed'));
|
||||
}
|
||||
});
|
||||
});
|
||||
console.log(chalk.magenta(table.toString()));
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
const fs = require('fs');
|
||||
const chalk = require('chalk');
|
||||
var AsciiTable = require('ascii-table');
|
||||
var table = new AsciiTable();
|
||||
table.setHeading('Events', 'Status').setBorder('|', '-', '+', '+');
|
||||
|
||||
module.exports.name = 'events';
|
||||
module.exports = (client) => {
|
||||
fs.readdirSync('./events/').filter((file) => file.endsWith('.js')).forEach((file) => {
|
||||
require(`../events/${file}`);
|
||||
table.addRow(file.split('.js')[0], chalk.green('Loaded'));
|
||||
});
|
||||
|
||||
console.log(chalk.magenta(table.toString()));
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
const fs = require('fs');
|
||||
const chalk = require('chalk');
|
||||
var AsciiTable = require('ascii-table');
|
||||
var table = new AsciiTable();
|
||||
table.setHeading('Handlers', 'Status').setBorder('|', '-', '+', '+');
|
||||
|
||||
module.exports.name = 'handlers';
|
||||
module.exports = (client) => {
|
||||
fs.readdirSync('./handlers/').filter((file) => file.endsWith('.js')).forEach((file) => {
|
||||
if (file === 'handlers.js') return;
|
||||
require(`./${file}`)(client);
|
||||
table.addRow(file.split('.js')[0], chalk.green('Loaded'));
|
||||
});
|
||||
console.log(chalk.magenta(table.toString()));
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
const fs = require('fs');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const { PermissionsBitField } = require('discord.js');
|
||||
const { Routes } = require('discord-api-types/v9');
|
||||
const { REST } = require('@discordjs/rest');
|
||||
|
||||
const AsciiTable = require('ascii-table');
|
||||
const table = new AsciiTable().setHeading('Slash Commands', 'Status').setBorder('|', '-', '+', '+');
|
||||
|
||||
const token = process.env.TOKEN;
|
||||
const clientId = process.env.CLIENTID;
|
||||
|
||||
const rest = new REST({ version: '9' }).setToken(token);
|
||||
module.exports.name = 'slashCommands';
|
||||
module.exports = async (client) => {
|
||||
const slashCommands = [];
|
||||
|
||||
fs.readdirSync('./slashCommands/').forEach(async dir => {
|
||||
const files = fs.readdirSync(`./slashCommands/${dir}`).filter(file => file.endsWith('.js'));
|
||||
for (const file of files) {
|
||||
const slashCommand = require(`../slashCommands/${dir}/${file}`);
|
||||
slashCommands.push({
|
||||
name: slashCommand.name,
|
||||
description: slashCommand.description,
|
||||
type: slashCommand.type
|
||||
});
|
||||
|
||||
if (slashCommand.name) {
|
||||
client.slashCommands.set(slashCommand.name, slashCommand);
|
||||
table.addRow(file.split('.js')[0], chalk.green('Loaded'));
|
||||
} else {
|
||||
table.addRow(file.split('.js')[0], chalk.red('Failed'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(chalk.blue(table.toString()));
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
await rest.put(
|
||||
Routes.applicationCommands(clientId),
|
||||
{ body: slashCommands },
|
||||
);
|
||||
console.log(chalk.cyan('Successfully registered application commands.'));
|
||||
} catch (error) {
|
||||
console.error(chalk.red('Error while registering application commands:'), error);
|
||||
}
|
||||
})();
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
const { Client, Collection, Permissions, GatewayIntentBits, Partials } = require('discord.js');
|
||||
require('dotenv').config();
|
||||
|
||||
const client = new Client({
|
||||
allowedMentions: { parse: ['users', 'roles'], repliedUser: true },
|
||||
intents: [
|
||||
GatewayIntentBits.Guilds,
|
||||
GatewayIntentBits.GuildMembers,
|
||||
GatewayIntentBits.GuildMessages,
|
||||
GatewayIntentBits.DirectMessages,
|
||||
GatewayIntentBits.MessageContent,
|
||||
],
|
||||
partials: [
|
||||
Partials.Channel,
|
||||
Partials.Message,
|
||||
Partials.User,
|
||||
]
|
||||
});
|
||||
|
||||
module.exports = client;
|
||||
|
||||
|
||||
client.commands = new Collection();
|
||||
client.slashCommands = new Collection();
|
||||
client.buttons = new Collection();
|
||||
|
||||
require('./handlers/handlers.js')(client);
|
||||
client.login(process.env.TOKEN);
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "discordjs-verification-bot",
|
||||
"version": "0.0.0-no-version",
|
||||
"description": "",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node main.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.ssh.surf/Nahokey/discordjs-verification-bot/"
|
||||
},
|
||||
"author": "Nahokey",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"ascii-table": "^0.0.9",
|
||||
"canvas": "^2.11.2",
|
||||
"chalk": "^2.4.1",
|
||||
"discord.js": "^14.14.1",
|
||||
"dotenv": "^16.4.1",
|
||||
"fs": "^0.0.1-security"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
const { EmbedBuilder, ApplicationCommandType, Collection, AttachmentBuilder } = require('discord.js');
|
||||
const { createCanvas, loadImage } = require('canvas');
|
||||
const cfg = require('../../config/config.js');
|
||||
const captchaUser = new Collection();
|
||||
|
||||
module.exports = {
|
||||
name: 'verify',
|
||||
description: 'To verify yourself.',
|
||||
type: ApplicationCommandType.ChatInput,
|
||||
run: async (client, interaction) => {
|
||||
const guildId = interaction.guild.id;
|
||||
//functions here
|
||||
async function generateCaptcha(count) {
|
||||
var chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
var captcha = '';
|
||||
for (var i = 0; i < count; i++) {
|
||||
captcha += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return captcha;
|
||||
}
|
||||
|
||||
async function createCaptcha(captcha) {
|
||||
const canvas = createCanvas(200, 75);
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.font = '30px Arial';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.fillText(captcha, 100, 37.5);
|
||||
|
||||
const buffer = canvas.toBuffer('image/png');
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//check if user is in the correct channel
|
||||
if (interaction.channel.id !== cfg.guilds[guildId].channelId) {
|
||||
return interaction.reply({ content: cfg.messages.wrongChannel, ephemeral: true })
|
||||
}
|
||||
|
||||
//check if user has the roleToRemove
|
||||
if (interaction.member.roles.cache.has(cfg.guilds[guildId].roleToAdd)) {
|
||||
return interaction.reply({ content: cfg.messages.alreadyVerified, ephemeral: true })
|
||||
}
|
||||
|
||||
const captcha = await generateCaptcha(cfg.captchaCount);
|
||||
const buff = await createCaptcha(captcha);
|
||||
|
||||
|
||||
const attachment = new AttachmentBuilder(buff, { name: 'captcha.png' });
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle("Captcha Verification")
|
||||
.setDescription(`Please type the captcha below. You have ${cfg.captchaTimeout / 1000} seconds to respond.`)
|
||||
.setColor('Green')
|
||||
.setImage('attachment://captcha.png')
|
||||
.setTimestamp();
|
||||
|
||||
await interaction.user.send({
|
||||
embeds: [embed], files: [attachment]
|
||||
}).then(async (msg) => {
|
||||
await interaction.reply({
|
||||
content: cfg.messages.toVerify,
|
||||
ephemeral: true
|
||||
})
|
||||
const filter = m => m.author.id === interaction.user.id;
|
||||
const collector = msg.channel.createMessageCollector({
|
||||
filter,
|
||||
time: cfg.captchaTimeout
|
||||
});
|
||||
|
||||
collector.on('collect', async (m) => {
|
||||
if (m.content === captcha) {
|
||||
await interaction.member.roles.add(cfg.guilds[guildId].roleToAdd);
|
||||
await interaction.member.roles.remove(cfg.guilds[guildId].firstRole);
|
||||
await interaction.user.send(cfg.messages.success);
|
||||
collector.stop();
|
||||
} else {
|
||||
await interaction.user.send(cfg.messages.fail);
|
||||
collector.stop();
|
||||
}
|
||||
});
|
||||
|
||||
collector.on('end', async (collected, reason) => {
|
||||
if (reason === 'time') {
|
||||
await interaction.user.send(cfg.messages.tookTooLong);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(async (err) => {
|
||||
await interaction.reply({
|
||||
content: cfg.messages.unableToDM,
|
||||
ephemeral: true
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Note from Naoki:
|
||||
This looks simple enough but damn.
|
||||
Canvas is driving me nuts due to how hard to work with it.
|
||||
Had to StackOverFlow-ed it to get it to work.
|
||||
I'm not sure if this is the best way to do it but it works.
|
||||
Big shoutout to StackOverFlow and the people I got the code from.
|
||||
*/
|
||||
Reference in New Issue
Block a user