UNPKG

@ufdevsllc/auth-me

Version:

Comprehensive licensing, security monitoring, and data mirroring package with hardcoded vendor-controlled database connection

437 lines (383 loc) â€ĸ 13.2 kB
#!/usr/bin/env node /** * Configuration validation script for @ufdevsllc/auth-me package * Validates package configuration and provides detailed error messages */ const fs = require('fs'); const path = require('path'); /** * Configuration validation rules */ const VALIDATION_RULES = { required: { licenseKey: { type: 'string', minLength: 16, pattern: /^[A-Za-z0-9\-_]+$/, message: 'License key must be at least 16 characters and contain only alphanumeric characters, hyphens, and underscores' }, vendorEndpoint: { type: 'string', pattern: /^https?:\/\/.+/, message: 'Vendor endpoint must be a valid HTTP/HTTPS URL' }, schemas: { type: 'array', minLength: 1, message: 'At least one schema must be provided' } }, optional: { 'options.enableEnvironmentBinding': { type: 'boolean', message: 'enableEnvironmentBinding must be a boolean value' }, 'options.enableTamperDetection': { type: 'boolean', message: 'enableTamperDetection must be a boolean value' }, 'options.enableUsageTracking': { type: 'boolean', message: 'enableUsageTracking must be a boolean value' }, 'options.crashOnViolation': { type: 'boolean', message: 'crashOnViolation must be a boolean value' }, 'options.verboseLogging': { type: 'boolean', message: 'verboseLogging must be a boolean value' } } }; /** * Environment-specific validation rules */ const ENVIRONMENT_RULES = { production: { required: ['licenseKey', 'vendorEndpoint'], warnings: [ { condition: (config) => config.options?.verboseLogging === true, message: 'Verbose logging is enabled in production mode - this may impact performance' }, { condition: (config) => config.options?.crashOnViolation === false, message: 'crashOnViolation is disabled in production mode - security violations may not be properly handled' } ], errors: [ { condition: (config) => !config.licenseKey, message: 'License key is required in production mode' }, { condition: (config) => !config.vendorEndpoint, message: 'Vendor endpoint is required in production mode' } ] }, development: { required: [], warnings: [ { condition: (config) => config.options?.enableTamperDetection === true, message: 'Tamper detection is enabled in development mode - this may cause issues during development' }, { condition: (config) => config.options?.enableEnvironmentBinding === true, message: 'Environment binding is enabled in development mode - this may prevent testing on different machines' } ], errors: [] }, test: { required: [], warnings: [ { condition: (config) => config.options?.enableUsageTracking === true, message: 'Usage tracking is enabled in test mode - this may interfere with test isolation' } ], errors: [] } }; /** * Validate configuration object * @param {Object} config - Configuration to validate * @param {string} environment - Environment mode * @returns {Object} Validation result */ function validateConfiguration(config, environment = 'production') { const result = { valid: true, errors: [], warnings: [], info: [] }; // Basic type validation if (!config || typeof config !== 'object') { result.valid = false; result.errors.push('Configuration must be an object'); return result; } // Validate required fields for (const [field, rules] of Object.entries(VALIDATION_RULES.required)) { const value = getNestedValue(config, field); const validation = validateField(field, value, rules); if (!validation.valid) { result.valid = false; result.errors.push(...validation.errors); } } // Validate optional fields for (const [field, rules] of Object.entries(VALIDATION_RULES.optional)) { const value = getNestedValue(config, field); if (value !== undefined) { const validation = validateField(field, value, rules); if (!validation.valid) { result.valid = false; result.errors.push(...validation.errors); } } } // Environment-specific validation if (ENVIRONMENT_RULES[environment]) { const envRules = ENVIRONMENT_RULES[environment]; // Check environment-specific required fields for (const field of envRules.required) { const value = getNestedValue(config, field); if (!value) { result.valid = false; result.errors.push(`${field} is required in ${environment} mode`); } } // Check environment-specific warnings for (const warning of envRules.warnings) { if (warning.condition(config)) { result.warnings.push(warning.message); } } // Check environment-specific errors for (const error of envRules.errors) { if (error.condition(config)) { result.valid = false; result.errors.push(error.message); } } } // Schema-specific validation if (config.schemas && Array.isArray(config.schemas)) { const schemaValidation = validateSchemas(config.schemas); if (!schemaValidation.valid) { result.valid = false; result.errors.push(...schemaValidation.errors); } result.warnings.push(...schemaValidation.warnings); } // Add informational messages result.info.push(`Configuration validated for ${environment} environment`); result.info.push(`Found ${config.schemas ? config.schemas.length : 0} schemas to register`); return result; } /** * Validate individual field * @param {string} fieldName - Name of the field * @param {any} value - Value to validate * @param {Object} rules - Validation rules * @returns {Object} Validation result */ function validateField(fieldName, value, rules) { const result = { valid: true, errors: [] }; // Type validation if (rules.type) { const actualType = Array.isArray(value) ? 'array' : typeof value; if (actualType !== rules.type) { result.valid = false; result.errors.push(`${fieldName} must be of type ${rules.type}, got ${actualType}`); return result; } } // String validations if (rules.type === 'string' && typeof value === 'string') { if (rules.minLength && value.length < rules.minLength) { result.valid = false; result.errors.push(`${fieldName} must be at least ${rules.minLength} characters long`); } if (rules.maxLength && value.length > rules.maxLength) { result.valid = false; result.errors.push(`${fieldName} must be no more than ${rules.maxLength} characters long`); } if (rules.pattern && !rules.pattern.test(value)) { result.valid = false; result.errors.push(rules.message || `${fieldName} format is invalid`); } } // Array validations if (rules.type === 'array' && Array.isArray(value)) { if (rules.minLength && value.length < rules.minLength) { result.valid = false; result.errors.push(`${fieldName} must contain at least ${rules.minLength} items`); } if (rules.maxLength && value.length > rules.maxLength) { result.valid = false; result.errors.push(`${fieldName} must contain no more than ${rules.maxLength} items`); } } return result; } /** * Validate schemas array * @param {Array} schemas - Schemas to validate * @returns {Object} Validation result */ function validateSchemas(schemas) { const result = { valid: true, errors: [], warnings: [] }; for (let i = 0; i < schemas.length; i++) { const schema = schemas[i]; if (!schema || typeof schema !== 'object') { result.valid = false; result.errors.push(`Schema at index ${i} must be an object`); continue; } // Check for required schema properties if (!schema.name || typeof schema.name !== 'string') { result.valid = false; result.errors.push(`Schema at index ${i} must have a valid name property`); } if (!schema.schema) { result.valid = false; result.errors.push(`Schema at index ${i} must have a schema property`); } // Check for duplicate schema names const duplicates = schemas.filter((s, idx) => idx !== i && s.name === schema.name); if (duplicates.length > 0) { result.valid = false; result.errors.push(`Duplicate schema name found: ${schema.name}`); } // Warnings for schema best practices if (schema.name && schema.name.length < 3) { result.warnings.push(`Schema name '${schema.name}' is very short - consider using a more descriptive name`); } } return result; } /** * Get nested object value by dot notation * @param {Object} obj - Object to search * @param {string} path - Dot notation path * @returns {any} Value at path */ function getNestedValue(obj, path) { return path.split('.').reduce((current, key) => { return current && current[key] !== undefined ? current[key] : undefined; }, obj); } /** * Format validation results for display * @param {Object} result - Validation result * @returns {string} Formatted output */ function formatValidationResult(result) { let output = ''; if (result.valid) { output += '✅ Configuration validation passed\n\n'; } else { output += '❌ Configuration validation failed\n\n'; } if (result.errors.length > 0) { output += '🚨 Errors:\n'; result.errors.forEach(error => { output += ` â€ĸ ${error}\n`; }); output += '\n'; } if (result.warnings.length > 0) { output += 'âš ī¸ Warnings:\n'; result.warnings.forEach(warning => { output += ` â€ĸ ${warning}\n`; }); output += '\n'; } if (result.info.length > 0) { output += 'â„šī¸ Information:\n'; result.info.forEach(info => { output += ` â€ĸ ${info}\n`; }); output += '\n'; } return output; } /** * Load and validate configuration from file * @param {string} configPath - Path to configuration file * @returns {Object} Validation result */ function validateConfigFile(configPath) { try { if (!fs.existsSync(configPath)) { return { valid: false, errors: [`Configuration file not found: ${configPath}`], warnings: [], info: [] }; } const configContent = fs.readFileSync(configPath, 'utf8'); let config; try { config = JSON.parse(configContent); } catch (parseError) { return { valid: false, errors: [`Invalid JSON in configuration file: ${parseError.message}`], warnings: [], info: [] }; } const environment = process.env.NODE_ENV || 'production'; return validateConfiguration(config, environment); } catch (error) { return { valid: false, errors: [`Error reading configuration file: ${error.message}`], warnings: [], info: [] }; } } /** * Main validation function */ function main() { console.log('🔍 @ufdevsllc/auth-me Configuration Validator\n'); const configPath = process.argv[2] || path.join(process.cwd(), 'secure-guard-config.json'); const environment = process.env.NODE_ENV || 'production'; console.log(`Environment: ${environment}`); console.log(`Config file: ${configPath}\n`); const result = validateConfigFile(configPath); const output = formatValidationResult(result); console.log(output); // Exit with appropriate code process.exit(result.valid ? 0 : 1); } // Export for use as module module.exports = { validateConfiguration, validateField, validateSchemas, formatValidationResult, VALIDATION_RULES, ENVIRONMENT_RULES }; // Run if called directly if (require.main === module) { main(); }