1 | const { Client, Events, GatewayIntentBits } = require('discord.js');
|
2 | const { token, sftp, pterodactyl } = require('./config.json');
|
3 | const fetch = require('node-fetch');
|
4 | const SFTPClient = require('ssh2-sftp-client');
|
5 | const axios = require('axios');
|
6 |
|
7 | process.on('unhandledRejection', error => {
|
8 | console.error('Unhandled promise rejection:', error);
|
9 | });
|
10 |
|
11 | const client = new Client({
|
12 | intents: [
|
13 | GatewayIntentBits.Guilds,
|
14 | GatewayIntentBits.GuildMessages,
|
15 | GatewayIntentBits.MessageContent,
|
16 | GatewayIntentBits.GuildMembers
|
17 | ]
|
18 | });
|
19 |
|
20 | client.on(Events.MessageCreate, async message => {
|
21 | if (!message.content.startsWith('!whitelist') || message.author.bot) return;
|
22 |
|
23 | try {
|
24 | const args = message.content.slice('!whitelist'.length).trim().split(/ +/);
|
25 | const command = args.shift().toLowerCase();
|
26 |
|
27 | if (command === 'help') {
|
28 | const helpMessage = `**Whitelist Bot Commands:**\n\`\`\`
|
29 | 1. !whitelist <username>
|
30 | → Add a player to the whitelist
|
31 |
|
32 | 2. !whitelist remove <username>
|
33 | → Remove a player from the whitelist
|
34 |
|
35 | 3. !whitelist list
|
36 | → Show all whitelisted players
|
37 |
|
38 | 4. !whitelist check <username/uuid>
|
39 | → Look up a player's UUID or username
|
40 |
|
41 | 5. !whitelist help
|
42 | → Show this help message\`\`\``;
|
43 | await message.channel.send(helpMessage);
|
44 | return;
|
45 | }
|
46 |
|
47 | if (!message.member.roles.cache.has('REDACTED')) {
|
48 | return message.channel.send('You do not have permission to use this command!');
|
49 | }
|
50 |
|
51 | if (command === 'check') {
|
52 | const query = args[0];
|
53 | if (!query) {
|
54 | return message.channel.send('Please provide a username or UUID!');
|
55 | }
|
56 |
|
57 | const reply = await message.channel.send('Processing lookup request...');
|
58 |
|
59 | try {
|
60 | const isUUID = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(query);
|
61 |
|
62 | if (isUUID) {
|
63 | const formattedUUID = query.replace(/-/g, '');
|
64 | const response = await fetch(`https://sessionserver.mojang.com/session/minecraft/profile/${formattedUUID}`);
|
65 | if (!response.ok) {
|
66 | return await reply.edit('Invalid UUID or player not found.');
|
67 | }
|
68 | const data = await response.json();
|
69 | await reply.edit(`**UUID Lookup Result:**\n\`\`\`\nUsername: ${data.name}\nUUID: ${query}\`\`\``);
|
70 | } else {
|
71 | const response = await fetch(`https://api.mojang.com/users/profiles/minecraft/${query}`);
|
72 | if (!response.ok) {
|
73 | return await reply.edit('Invalid username or player not found.');
|
74 | }
|
75 | const data = await response.json();
|
76 | const formattedUUID = data.id.replace(/(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/, '$1-$2-$3-$4-$5');
|
77 | await reply.edit(`**Username Lookup Result:**\n\`\`\`\nUsername: ${data.name}\nUUID: ${formattedUUID}\`\`\``);
|
78 | }
|
79 | } catch (error) {
|
80 | console.error('Lookup Error:', error);
|
81 | await reply.edit('An error occurred while looking up the player.');
|
82 | }
|
83 | return;
|
84 | }
|
85 |
|
86 | if (command === 'list') {
|
87 | const sftpClient = new SFTPClient();
|
88 | try {
|
89 | await sftpClient.connect({
|
90 | host: sftp.host,
|
91 | port: sftp.port,
|
92 | username: sftp.username,
|
93 | password: sftp.password
|
94 | });
|
95 |
|
96 | const whitelistData = await sftpClient.get(sftp.whitelistPath);
|
97 | const whitelist = JSON.parse(whitelistData.toString());
|
98 | const playerList = whitelist.map((player, index) => `${index + 1}. ${player.name}`).join('\n');
|
99 | const formattedMessage = `**Whitelisted Players (${whitelist.length}):**\n\`\`\`\n${playerList}\n\`\`\``;
|
100 | await message.channel.send(formattedMessage);
|
101 | } catch (error) {
|
102 | console.error('SFTP Error:', error);
|
103 | await message.channel.send('Failed to retrieve whitelist.');
|
104 | } finally {
|
105 | await sftpClient.end();
|
106 | }
|
107 | } else if (command === 'remove') {
|
108 | const ign = args[0];
|
109 | if (!ign) {
|
110 | return message.channel.send('Please provide a Minecraft username!');
|
111 | }
|
112 |
|
113 | const reply = await message.channel.send('Processing whitelist removal request...');
|
114 | const sftpClient = new SFTPClient();
|
115 | try {
|
116 | await sftpClient.connect({
|
117 | host: sftp.host,
|
118 | port: sftp.port,
|
119 | username: sftp.username,
|
120 | password: sftp.password
|
121 | });
|
122 |
|
123 | const whitelistData = await sftpClient.get(sftp.whitelistPath);
|
124 | let whitelist = JSON.parse(whitelistData.toString());
|
125 | const initialLength = whitelist.length;
|
126 | whitelist = whitelist.filter(player => player.name.toLowerCase() !== ign.toLowerCase());
|
127 |
|
128 | if (whitelist.length === initialLength) {
|
129 | await sftpClient.end();
|
130 | return await reply.edit(`${ign} is not whitelisted!`);
|
131 | }
|
132 |
|
133 | await sftpClient.put(Buffer.from(JSON.stringify(whitelist, null, 2)), sftp.whitelistPath);
|
134 | } catch (error) {
|
135 | console.error('SFTP Error:', error);
|
136 | return await reply.edit('Failed to update whitelist file');
|
137 | } finally {
|
138 | await sftpClient.end();
|
139 | }
|
140 |
|
141 | try {
|
142 | await axios.post(
|
143 | `${pterodactyl.apiUrl}/api/client/servers/${pterodactyl.serverId}/command`,
|
144 | { command: 'whitelist reload' },
|
145 | {
|
146 | headers: { 'Authorization': `Bearer ${pterodactyl.apiKey}` },
|
147 | timeout: 5000
|
148 | }
|
149 | );
|
150 | } catch (error) {
|
151 | console.error('Pterodactyl API Error:', error);
|
152 | return await reply.edit('Whitelist updated but failed to reload server whitelist');
|
153 | }
|
154 |
|
155 | await reply.edit(`Successfully removed ${ign} from the whitelist!`);
|
156 | } else {
|
157 | const ign = command;
|
158 | if (!ign) {
|
159 | return message.channel.send('Please provide a Minecraft username!');
|
160 | }
|
161 |
|
162 | const reply = await message.channel.send('Processing whitelist request...');
|
163 | const response = await fetch(`https://api.mojang.com/users/profiles/minecraft/${ign}`);
|
164 | if (!response.ok) {
|
165 | return await reply.edit('Failed to fetch player data from Mojang API');
|
166 | }
|
167 | const data = await response.json();
|
168 | if (!data?.id) {
|
169 | return await reply.edit('Invalid username!');
|
170 | }
|
171 |
|
172 | const sftpClient = new SFTPClient();
|
173 | try {
|
174 | await sftpClient.connect({
|
175 | host: sftp.host,
|
176 | port: sftp.port,
|
177 | username: sftp.username,
|
178 | password: sftp.password
|
179 | });
|
180 |
|
181 | let whitelist = [];
|
182 | try {
|
183 | const whitelistData = await sftpClient.get(sftp.whitelistPath);
|
184 | whitelist = JSON.parse(whitelistData.toString());
|
185 | } catch (error) {
|
186 | console.log('Creating new whitelist file');
|
187 | whitelist = [];
|
188 | }
|
189 |
|
190 | const isWhitelisted = whitelist.some(player =>
|
191 | player.uuid === data.id ||
|
192 | player.name.toLowerCase() === data.name.toLowerCase()
|
193 | );
|
194 |
|
195 | if (isWhitelisted) {
|
196 | await sftpClient.end();
|
197 | return await reply.edit(`${data.name} is already whitelisted!`);
|
198 | }
|
199 |
|
200 | whitelist.push({
|
201 | uuid: data.id,
|
202 | name: data.name
|
203 | });
|
204 |
|
205 | await sftpClient.put(Buffer.from(JSON.stringify(whitelist, null, 2)), sftp.whitelistPath);
|
206 | } catch (error) {
|
207 | console.error('SFTP Error:', error);
|
208 | return await reply.edit('Failed to update whitelist file');
|
209 | } finally {
|
210 | await sftpClient.end();
|
211 | }
|
212 |
|
213 | try {
|
214 | await axios.post(
|
215 | `${pterodactyl.apiUrl}/api/client/servers/${pterodactyl.serverId}/command`,
|
216 | { command: 'whitelist reload' },
|
217 | {
|
218 | headers: { 'Authorization': `Bearer ${pterodactyl.apiKey}` },
|
219 | timeout: 5000
|
220 | }
|
221 | );
|
222 | } catch (error) {
|
223 | console.error('Pterodactyl API Error:', error);
|
224 | return await reply.edit('Whitelist updated but failed to reload server whitelist');
|
225 | }
|
226 |
|
227 | await reply.edit(`Successfully whitelisted ${data.name}!`);
|
228 | }
|
229 | } catch (error) {
|
230 | console.error('Command Error:', error);
|
231 | try {
|
232 | await message.channel.send('An error occurred while processing the whitelist command.');
|
233 | } catch (e) {
|
234 | console.error('Failed to send error message:', e);
|
235 | }
|
236 | }
|
237 | });
|
238 |
|
239 | client.once(Events.ClientReady, c => {
|
240 | console.log(`Ready! Logged in as ${c.user.tag}`);
|
241 | client.user.setActivity('!whitelist help', { type: 0 });
|
242 | });
|
243 |
|
244 | client.on('error', error => {
|
245 | console.error('Discord client error:', error);
|
246 | });
|
247 |
|
248 | client.login(token);
|