UNPKG

@brandazm/dynamic-permissions

Version:

A flexible and powerful permissions management system for NestJS applications with built-in security features

225 lines 9.95 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.SchemaValidatorService = void 0; const common_1 = require("@nestjs/common"); const path = __importStar(require("path")); const fs = __importStar(require("fs")); let SchemaValidatorService = class SchemaValidatorService { validateFieldMappings(config) { const result = { isValid: true, errors: [] }; this.validateEntityFields(config.database.entities.permissions.fields, ['id', 'name'], 'permissions', result); this.validateEntityFields(config.database.entities.routerPermissions.fields, ['id', 'route', 'method', 'permissionId'], 'routerPermissions', result); this.validateEntityFields(config.database.entities.userPermissions.fields, ['id', 'userId', 'permissionId', 'grantedAt'], 'userPermissions', result); result.isValid = result.errors.length === 0; return result; } validateDatabaseSchema(entities) { const result = { isValid: true, errors: [] }; const entityNames = entities.map((e) => e.name.toLowerCase()); const requiredEntities = ['permission', 'routerpermission', 'userpermission']; for (const entity of requiredEntities) { if (!entityNames.includes(entity.toLowerCase())) { result.errors.push(`Missing required entity: ${entity}`); } } entities.forEach((entity) => { const columnNames = entity.columns.map((c) => c.propertyName.toLowerCase()); switch (entity.name.toLowerCase()) { case 'permission': this.validateColumns(columnNames, ['id', 'name'], entity.name, result); break; case 'routerpermission': this.validateColumns(columnNames, ['id', 'route', 'method', 'permissionId'], entity.name, result); break; case 'userpermission': this.validateColumns(columnNames, ['id', 'userId', 'permissionId', 'grantedAt'], entity.name, result); break; } }); result.isValid = result.errors.length === 0; return result; } validateEntityFields(fields, required, entityName, result) { for (const field of required) { if (!fields[field]) { result.errors.push(`Missing required field mapping for ${entityName}: ${field}`); } } const mappedFields = Object.values(fields).filter((field) => field !== undefined); const duplicates = mappedFields.filter((field, index) => mappedFields.indexOf(field) !== index); if (duplicates.length > 0) { result.errors.push(`Duplicate field mappings found in ${entityName}: ${duplicates.join(', ')}`); } } validateColumns(columns, required, entityName, result) { for (const column of required) { if (!columns.includes(column.toLowerCase())) { result.errors.push(`Missing required column in ${entityName}: ${column}`); } } } async validateConfig(projectPath) { try { const tsConfigPath = path.join(projectPath, 'config', 'permissions.config.ts'); if (!fs.existsSync(tsConfigPath)) { console.error('Configuration file not found. Expected:', tsConfigPath); return false; } const config = await this.loadConfig(tsConfigPath); if (!config) { return false; } if (!this.validateTopLevelConfig(config)) { return false; } if (!this.validateDatabaseConfig(config.database)) { return false; } if (!this.validatePermissionsConfig(config.permissions)) { return false; } if (!this.validateSecurityConfig(config.security)) { return false; } const fieldValidation = this.validateFieldMappings(config); if (!fieldValidation.isValid) { console.error('Field mapping validation failed:', fieldValidation.errors); return false; } console.log('Configuration validation successful'); return true; } catch (error) { console.error('Error validating configuration:', error); return false; } } async loadConfig(configPath) { try { const configFileContent = fs.readFileSync(configPath, 'utf8'); const [, fileContent] = configFileContent.split('='); return JSON.parse(fileContent); } catch (error) { console.error('Error loading configuration file:', error); return null; } } validateTopLevelConfig(config) { const requiredProperties = ['database', 'permissions', 'security']; for (const prop of requiredProperties) { if (!config[prop]) { console.error(`Missing required top-level property: ${prop}`); return false; } } return true; } validateDatabaseConfig(database) { if (!database.entities) { console.error('Missing database entities configuration'); return false; } const requiredEntities = ['permissions', 'routerPermissions', 'userPermissions']; for (const entity of requiredEntities) { if (!database.entities[entity]) { console.error(`Missing required entity configuration: ${entity}`); return false; } if (!database.entities[entity].tableName) { console.error(`Missing tableName for entity: ${entity}`); return false; } if (!database.entities[entity].fields) { console.error(`Missing fields configuration for entity: ${entity}`); return false; } } return true; } validatePermissionsConfig(permissions) { const requiredProperties = ['defaultRole', 'adminRole', 'permissionStrategy']; for (const prop of requiredProperties) { if (!permissions[prop]) { console.error(`Missing required permissions property: ${prop}`); return false; } } if (permissions.permissionStrategy !== 'whitelist' && permissions.permissionStrategy !== 'blacklist') { console.error('Invalid permission strategy. Must be either "whitelist" or "blacklist"'); return false; } if (!Array.isArray(permissions.publicRoutes)) { console.error('publicRoutes must be an array'); return false; } return true; } validateSecurityConfig(security) { const requiredProperties = ['enableCaching', 'cacheTimeout', 'enableAuditLog']; for (const prop of requiredProperties) { if (security[prop] === undefined) { console.error(`Missing required security property: ${prop}`); return false; } } if (typeof security.enableCaching !== 'boolean') { console.error('enableCaching must be a boolean'); return false; } if (typeof security.cacheTimeout !== 'number' || security.cacheTimeout < 0) { console.error('cacheTimeout must be a positive number'); return false; } if (typeof security.enableAuditLog !== 'boolean') { console.error('enableAuditLog must be a boolean'); return false; } return true; } }; exports.SchemaValidatorService = SchemaValidatorService; exports.SchemaValidatorService = SchemaValidatorService = __decorate([ (0, common_1.Injectable)() ], SchemaValidatorService); //# sourceMappingURL=schema-validator.service.js.map