All files / src/validators UserValidator.js

100% Statements 14/14
100% Branches 10/10
100% Functions 5/5
100% Lines 14/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 966x                                                                       4x 1x         3x 1x         2x 1x                 1x               5x       5x   5x                 2x                   3x       6x
const { PermissionFlagsBits } = require('discord.js');
 
/**
 * UserValidator - Centralized permission and eligibility validation
 * 
 * Provides consistent security checks across all bot features to prevent unauthorized access.
 * Validates user eligibility based on roles, permissions, and account status.
 * 
 * Security design rationale:
 * - Centralized validation prevents inconsistent permission checks across modules
 * - Detailed rejection reasons aid in troubleshooting and user support
 * - Bot detection prevents automation loops and abuse
 * - Timeout/mute awareness ensures compliance with moderation actions
 * 
 * Permission levels:
 * - Member: Basic bot interactions (requires member role)
 * - Moderator: Administrative actions (requires moderator role OR ManageRoles permission)
 * - Bot: System-level access (internal bot operations only)
 */
class UserValidator {
    constructor() {
        // Future: Add mute tracking, timeout tracking, etc.
    }
 
    /**
     * Comprehensive eligibility check for bot interactions
     * 
     * Validates all aspects of user eligibility including membership, moderation status,
     * and bot detection. Provides detailed feedback for denied actions.
     * 
     * @param {GuildMember} member - Discord guild member object
     * @param {string} memberRoleId - Required member role ID
     * @returns {Object} - {canAct: boolean, reason?: string}
     */
    canAct(member, memberRoleId) {
        // Prevent bots from triggering actions to avoid automation loops
        if (member.user.bot) {
            return { canAct: false, reason: 'User is a bot' };
        }
 
        // Require member role for most bot interactions
        // This ensures only verified community members can use advanced features
        if (!member.roles.cache.has(memberRoleId)) {
            return { canAct: false, reason: 'User is not a member' };
        }
 
        // Respect Discord timeouts as a form of moderation
        // Timed out users shouldn't be able to bypass restrictions via bot actions
        if (member.isCommunicationDisabled()) {
            return { canAct: false, reason: 'User is currently timed out' };
        }
 
        // Future checks can be added here:
        // - Custom mute role check
        // - Blacklist check
        // - Rate limiting check
        // - etc.
 
        return { canAct: true };
    }
 
    // Determine if user has moderator privileges for bot commands
    // Checks both designated moderator role and Discord permissions
    // Allows flexibility in permission assignment while maintaining security
    canUseModerator(member, moderatorRoleId) {
        // Check for assigned moderator role
        const hasModerator = moderatorRoleId && member.roles.cache.has(moderatorRoleId);
        
        // Check for Discord manage roles permission as alternative
        // This allows server admins to use moderator commands without specific role
        const hasPermissions = member.permissions.has(PermissionFlagsBits.ManageRoles);
        
        return hasModerator || hasPermissions;
    }
 
    /**
     * Check if user is a bot
     * @param {User} user - Discord user
     * @returns {boolean}
     */
    isBot(user) {
        return user.bot;
    }
 
    /**
     * Check if user has a specific role
     * @param {GuildMember} member - Discord guild member  
     * @param {string} roleId - Role ID to check
     * @returns {boolean}
     */
    hasRole(member, roleId) {
        return member.roles.cache.has(roleId);
    }
}
 
module.exports = UserValidator;