Skip to content

Commit 16cf06e

Browse files
committed
add permission checks and error logging
1 parent f4f9cbf commit 16cf06e

1 file changed

Lines changed: 131 additions & 7 deletions

File tree

index.js

Lines changed: 131 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,101 @@ function checkRateLimit(userId, action, limit) {
154154
return { allowed: true, retryAfter: 0 };
155155
}
156156

157+
/**
158+
* Required permissions for bot operations
159+
*/
160+
const REQUIRED_PERMISSIONS = {
161+
SEND_MESSAGES: "SendMessages",
162+
EMBED_LINKS: "EmbedLinks",
163+
READ_MESSAGE_HISTORY: "ReadMessageHistory",
164+
VIEW_CHANNEL: "ViewChannel"
165+
};
166+
167+
/**
168+
* Check if bot has required permissions in a channel
169+
* @param {import('discord.js').GuildChannel} channel - The channel to check
170+
* @param {string[]} requiredPermissions - Array of permission names to check
171+
* @returns {Object} - { hasPermissions: boolean, missing: string[] }
172+
*/
173+
function checkChannelPermissions(channel, requiredPermissions = []) {
174+
if (!channel) {
175+
return { hasPermissions: false, missing: ["Channel not found"] };
176+
}
177+
178+
// Check if channel is a text-based channel
179+
if (!channel.isTextBased?.()) {
180+
return { hasPermissions: false, missing: ["Channel is not text-based"] };
181+
}
182+
183+
const missing = [];
184+
const botMember = channel.guild?.members?.me;
185+
186+
if (!botMember) {
187+
return { hasPermissions: false, missing: ["Bot member not found in guild"] };
188+
}
189+
190+
const permissions = channel.permissionsFor(botMember);
191+
if (!permissions) {
192+
return { hasPermissions: false, missing: ["Could not resolve permissions"] };
193+
}
194+
195+
// Check each required permission
196+
for (const perm of requiredPermissions) {
197+
if (!permissions.has(perm)) {
198+
missing.push(perm);
199+
}
200+
}
201+
202+
return {
203+
hasPermissions: missing.length === 0,
204+
missing
205+
};
206+
}
207+
208+
/**
209+
* Validate bot can send messages to a channel
210+
* @param {import('discord.js').GuildChannel} channel - The channel to validate
211+
* @returns {Object} - { valid: boolean, error?: string }
212+
*/
213+
function validateChannelForSend(channel) {
214+
const result = checkChannelPermissions(channel, [
215+
REQUIRED_PERMISSIONS.VIEW_CHANNEL,
216+
REQUIRED_PERMISSIONS.SEND_MESSAGES,
217+
REQUIRED_PERMISSIONS.EMBED_LINKS
218+
]);
219+
220+
if (!result.hasPermissions) {
221+
return {
222+
valid: false,
223+
error: `Missing permissions: ${result.missing.join(", ")}`
224+
};
225+
}
226+
227+
return { valid: true };
228+
}
229+
230+
/**
231+
* Validate bot can edit messages in a channel
232+
* @param {import('discord.js').GuildChannel} channel - The channel to validate
233+
* @returns {Object} - { valid: boolean, error?: string }
234+
*/
235+
function validateChannelForEdit(channel) {
236+
const result = checkChannelPermissions(channel, [
237+
REQUIRED_PERMISSIONS.VIEW_CHANNEL,
238+
REQUIRED_PERMISSIONS.READ_MESSAGE_HISTORY,
239+
REQUIRED_PERMISSIONS.EMBED_LINKS
240+
]);
241+
242+
if (!result.hasPermissions) {
243+
return {
244+
valid: false,
245+
error: `Missing permissions: ${result.missing.join(", ")}`
246+
};
247+
}
248+
249+
return { valid: true };
250+
}
251+
157252
/**
158253
* Validate IPv4 address format
159254
* @param {string} ip - The IP address to validate
@@ -736,6 +831,13 @@ bot.on("ready", async () => {
736831
logChannel = guild.channels.cache.get(config.logging.channelID);
737832
if (!logChannel) {
738833
console.warn(`Log channel ${config.logging.channelID} not found in guild ${config.logging.guildID}`);
834+
} else {
835+
// Validate bot has required permissions in log channel
836+
const permCheck = validateChannelForSend(logChannel);
837+
if (!permCheck.valid) {
838+
console.warn(`Log channel ${config.logging.channelID} permission issue: ${permCheck.error}`);
839+
logChannel = null; // Disable logging if permissions are missing
840+
}
739841
}
740842
} else {
741843
console.warn(`Guild ${config.logging.guildID} not found`);
@@ -826,6 +928,13 @@ async function intervalFunction() {
826928
try {
827929
await withRetry(async () => {
828930
const channel = await bot.channels.fetch(e.channelID);
931+
932+
// Validate permissions before editing
933+
const permCheck = validateChannelForEdit(channel);
934+
if (!permCheck.valid) {
935+
throw new Error(`Permission check failed for channel ${e.channelID}: ${permCheck.error}`);
936+
}
937+
829938
const message = await channel.messages.fetch(e.messageID);
830939
await message.edit({ content: "‎", embeds: [embed] });
831940
});
@@ -1477,6 +1586,11 @@ const notifyUsers = async (map, serverObj) => {
14771586
if (!channel) {
14781587
throw new Error(`Fallback channel ${config.fallback.channelID} not found`);
14791588
}
1589+
// Validate permissions before sending
1590+
const permCheck = validateChannelForSend(channel);
1591+
if (!permCheck.valid) {
1592+
throw new Error(`Fallback channel permission error: ${permCheck.error}`);
1593+
}
14801594
channel.send({
14811595
embeds: [backupEmbed],
14821596
content: fallbackContent
@@ -1563,13 +1677,23 @@ const notifyUsers = async (map, serverObj) => {
15631677

15641678
try {
15651679
await withRetry(async () => {
1566-
bot.guilds.cache
1567-
.get(config.fallback.guildID)
1568-
.channels.cache.get(config.fallback.channelID)
1569-
.send({
1570-
embeds: [backupEmbed],
1571-
content: fallbackContent
1572-
});
1680+
const guild = bot.guilds.cache.get(config.fallback.guildID);
1681+
if (!guild) {
1682+
throw new Error(`Fallback guild ${config.fallback.guildID} not found`);
1683+
}
1684+
const channel = guild.channels.cache.get(config.fallback.channelID);
1685+
if (!channel) {
1686+
throw new Error(`Fallback channel ${config.fallback.channelID} not found`);
1687+
}
1688+
// Validate permissions before sending
1689+
const permCheck = validateChannelForSend(channel);
1690+
if (!permCheck.valid) {
1691+
throw new Error(`Fallback channel permission error: ${permCheck.error}`);
1692+
}
1693+
channel.send({
1694+
embeds: [backupEmbed],
1695+
content: fallbackContent
1696+
});
15731697
});
15741698
} catch (fallbackError) {
15751699
console.error(`Failed to send fallback notification for ${map}:`, fallbackError);

0 commit comments

Comments
 (0)