initial commit

This commit is contained in:
Ayden Jahola 2024-08-31 02:34:09 +01:00
commit c6a5dd2701
No known key found for this signature in database
GPG key ID: 71DD90AE4AE92742
6 changed files with 313 additions and 0 deletions

17
.gitignore vendored Normal file
View file

@ -0,0 +1,17 @@
# Node
node_modules/
package-lock.json
# .env
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# yarn stuff
yarn-error.log
yarn.lock
# db
db-data

1
Procfile Normal file
View file

@ -0,0 +1 @@
worker: node bot.js

60
README.md Normal file
View file

@ -0,0 +1,60 @@
# Esports Verification Bot
Welcome to the **Esports Verification Bot**! This bot is designed to handle user verification for Discord servers, specifically for esports communities. It verifies users through their student email addresses and manages roles based on their verification status.
## Features
- **Email Verification**: Users receive a verification code via email and must enter it in Discord to verify their account.
- **Role Management**: Automatically assigns a specific role to users once they have been verified.
- **Customizable**: Easy to configure email domains, roles, and channels for different needs.
- **Expiration Handling**: Verification codes expire after 10 minutes for added security.
## Getting Started
### Prerequisites
Before you begin, ensure you have:
- A Discord bot token (create a bot on the [Discord Developer Portal](https://discord.com/developers/applications)).
- Access to a MongoDB database (you can use [MongoDB Atlas](https://www.mongodb.com/cloud/atlas) for a free tier).
- A Gmail account for sending emails (you can use any email service, but make sure to adjust the Nodemailer configuration).
### Installation
1. **Clone the Repository**
```sh
git clone git@github.com:aydenjahola/esports-verification-bot.git
cd esports-verification-bot
```
2. **Install Dependencies**
```sh
npm install
```
3. **Set Up Environment Variables**
Create a `.env` file in the root directory and add the following:
```env
BOT_TOKEN=your_discord_bot_token
MONGODB_URI=your_mongodb_connection_string
EMAIL_USER=your_email@gmail.com
EMAIL_PASS=your_email_password
VERIFIED_ROLE_NAME=YourVerifiedRoleName
EMAIL_DOMAIN=mail.dcu.ie
GUILD_ID=your_discord_guild_id
```
4. **Run the Bot**
```sh
node bot.js
```
### Usage
- **!verify your_email@mail.dcu.ie**: Sends a verification code to the provided email.
- **!code your_code**: Validates the provided verification code.

206
bot.js Normal file
View file

@ -0,0 +1,206 @@
require("dotenv").config();
const { Client, GatewayIntentBits } = require("discord.js");
const nodemailer = require("nodemailer");
const mongoose = require("mongoose");
const VerificationCode = require("./models/VerificationCode");
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
});
const VERIFIED_ROLE_NAME = process.env.VERIFIED_ROLE_NAME; // Role name to assign after verification
const EMAIL_DOMAIN = process.env.EMAIL_DOMAIN; // Domain to verify against
const GUILD_ID = process.env.GUILD_ID; // Guild ID to restrict the bot
const VERIFICATION_CHANNEL_NAME = "verification"; // Channel name to restrict the bot
// Connect to MongoDB
mongoose
.connect(process.env.MONGODB_URI)
.then(() => console.log("Connected to MongoDB"))
.catch((err) => console.error("Failed to connect to MongoDB", err));
// Setup Nodemailer
const transporter = nodemailer.createTransport({
service: "Gmail",
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS,
},
});
client.once("ready", () => {
console.log(`Logged in as ${client.user.tag}`);
});
client.on("messageCreate", async (message) => {
try {
// Ensure bot only operates in the designated channel
const verificationChannel = message.guild.channels.cache.find(
(channel) => channel.name === VERIFICATION_CHANNEL_NAME
);
if (!message.guild || !verificationChannel) {
console.error("Guild or verification channel not found.");
return;
}
if (message.author.bot || message.channel.id !== verificationChannel.id)
return;
if (message.content.startsWith("!verify")) {
const email = message.content.split(" ")[1];
if (!email) {
return verificationChannel.send(
"Please provide your email address. Usage: `!verify your_email@mail.dcu.ie`"
);
}
const emailDomain = email.split("@")[1];
if (emailDomain !== EMAIL_DOMAIN) {
return verificationChannel.send(
"You must use a valid DCU student email address."
);
}
const guild = client.guilds.cache.get(GUILD_ID);
if (!guild) {
console.error("Guild not found.");
return;
}
const member = guild.members.cache.get(message.author.id);
if (!member) {
console.error("Member not found.");
return;
}
const role = guild.roles.cache.find((r) => r.name === VERIFIED_ROLE_NAME);
if (!role) {
console.error("Role not found.");
return;
}
if (member.roles.cache.has(role.id)) {
return verificationChannel.send("You are already verified!");
}
const verificationCode = Math.floor(
100000 + Math.random() * 900000
).toString();
const emailHtml = `
<html>
<body style="font-family: Arial, sans-serif; color: #333;">
<h2 style="color: #1e90ff;">Your Verification Code</h2>
<p>Hi there,</p>
<p>Thank you for requesting verification. Your verification code is:</p>
<h3 style="background-color: #f4f4f4; padding: 10px; border: 1px solid #ddd; border-radius: 5px; text-align: center; color: #1e90ff;">
${verificationCode}
</h3>
<p>This code is valid for 10 minutes. Please enter it in the Discord channel using the command <code>!code your_code</code>.</p>
<p>If you did not request this code, please ignore this email.</p>
<p>Best regards,<br>Esports Committee</p>
</body>
</html>
`;
try {
await transporter.sendMail({
from: process.env.EMAIL_USER,
to: email,
subject: "Esports Verification Code",
html: emailHtml, // Use HTML content
});
await VerificationCode.create({
userId: message.author.id,
email: email,
code: verificationCode,
});
verificationChannel.send(
`**A verification code has been sent to your email.**\n` +
`Please reply with \`!code your_code\` to verify your account.\n` +
`**Note:** The code is only valid for **10 minutes**.`
);
} catch (err) {
console.error("Error sending email or saving verification code:", err);
verificationChannel.send(
"There was an error sending the verification email."
);
}
}
if (message.content.startsWith("!code")) {
const code = message.content.split(" ")[1];
if (!code) {
return verificationChannel.send(
"Please provide the verification code. Usage: `!code your_code`"
);
}
try {
const verificationEntry = await VerificationCode.findOne({
userId: message.author.id,
code,
});
if (!verificationEntry) {
return verificationChannel.send(
"Invalid or expired verification code. Please try again."
);
}
const guild = client.guilds.cache.get(GUILD_ID);
if (!guild) {
console.error("Guild not found.");
return;
}
const member = guild.members.cache.get(message.author.id);
if (!member) {
console.error("Member not found.");
return;
}
const role = guild.roles.cache.find(
(r) => r.name === VERIFIED_ROLE_NAME
);
if (!role) {
console.error("Role not found.");
return;
}
if (member.roles.cache.has(role.id)) {
return verificationChannel.send("You are already verified!");
}
await member.roles.add(role);
verificationChannel.send(
`Congratulations ${message.author}, you have been verified!`
);
// No need to manually delete the verification entry, as it will expire automatically in 10 minutes
} catch (err) {
console.error("Error processing verification code:", err);
verificationChannel.send(
"There was an error processing your verification. Please try again later."
);
}
}
} catch (err) {
console.error("Unhandled error in messageCreate event:", err);
}
});
client.on("error", (err) => {
console.error("Client error:", err);
});
client.login(process.env.BOT_TOKEN);

View file

@ -0,0 +1,10 @@
const mongoose = require("mongoose");
const VerificationCodeSchema = new mongoose.Schema({
userId: { type: String, required: true },
email: { type: String, required: true },
code: { type: String, required: true },
createdAt: { type: Date, expires: "10m", default: Date.now }, // Code expires in 10 minutes
});
module.exports = mongoose.model("VerificationCode", VerificationCodeSchema);

19
package.json Normal file
View file

@ -0,0 +1,19 @@
{
"name": "esports-bot",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"discord.js": "^14.15.3",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"mongoose": "^8.6.0",
"nodemailer": "^6.9.14"
}
}