Files
dss/admin-ui/js/core/route-guards.js
Digital Production Factory 276ed71f31 Initial commit: Clean DSS implementation
Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm

Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)

Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability

Migration completed: $(date)
🤖 Clean migration with full functionality preserved
2025-12-09 18:45:48 -03:00

180 lines
4.4 KiB
JavaScript

/**
* Route Guards - Phase 8 Enterprise Pattern
*
* Validates route access, enforces permissions, and handles
* authentication/authorization before allowing navigation.
*/
import store from '../stores/app-store.js';
import auditLogger from './audit-logger.js';
class RouteGuard {
constructor() {
this.guards = new Map();
this.setupDefaultGuards();
}
/**
* Register a guard for a specific route
*/
register(route, guard) {
this.guards.set(route, guard);
}
/**
* Check if user can access route
*/
canActivate(route) {
const state = store.get();
// Not authenticated
if (!state.user) {
auditLogger.logPermissionCheck('route_access', false, 'anonymous', `Unauthenticated access to ${route}`);
return {
allowed: false,
reason: 'User must be logged in',
redirect: '/#/login'
};
}
// Check route-specific guard
const guard = this.guards.get(route);
if (guard) {
const result = guard(state);
if (!result.allowed) {
auditLogger.logPermissionCheck('route_access', false, state.user.id, `Access denied to ${route}: ${result.reason}`);
}
return result;
}
auditLogger.logPermissionCheck('route_access', true, state.user.id, `Access granted to ${route}`);
return { allowed: true };
}
/**
* Check user permission
*/
hasPermission(permission) {
const state = store.get();
if (!state.user) {
auditLogger.logPermissionCheck('permission_check', false, 'anonymous', `Checking ${permission}`);
return false;
}
const allowed = store.hasPermission(permission);
auditLogger.logPermissionCheck('permission_check', allowed, state.user.id, `Checking ${permission}`);
return allowed;
}
/**
* Require permission before action
*/
requirePermission(permission) {
if (!this.hasPermission(permission)) {
throw new Error(`Permission denied: ${permission}`);
}
return true;
}
/**
* Setup default route guards
*/
setupDefaultGuards() {
// Settings page - requires TEAM_LEAD or SUPER_ADMIN
this.register('settings', (state) => {
const allowed = ['TEAM_LEAD', 'SUPER_ADMIN'].includes(state.role);
return {
allowed,
reason: allowed ? '' : 'Settings access requires team lead or admin role'
};
});
// Admin page - requires SUPER_ADMIN
this.register('admin', (state) => {
const allowed = state.role === 'SUPER_ADMIN';
return {
allowed,
reason: allowed ? '' : 'Admin access requires super admin role'
};
});
// Projects page - requires active team
this.register('projects', (state) => {
const allowed = !!state.team;
return {
allowed,
reason: allowed ? '' : 'Must select a team first'
};
});
// Figma integration - requires DEVELOPER or above
this.register('figma', (state) => {
const allowed = ['DEVELOPER', 'TEAM_LEAD', 'SUPER_ADMIN'].includes(state.role);
return {
allowed,
reason: allowed ? '' : 'Figma integration requires developer or higher role'
};
});
}
/**
* Validate action before execution
*/
validateAction(action, resource) {
const state = store.get();
if (!state.user) {
throw new Error('User must be authenticated');
}
const requiredPermission = this.getRequiredPermission(action, resource);
if (!this.hasPermission(requiredPermission)) {
throw new Error(`Permission denied: ${action} on ${resource}`);
}
auditLogger.logAction(`${action}_${resource}`, {
user: state.user.id,
role: state.role
});
return true;
}
/**
* Map action to required permission
*/
getRequiredPermission(action, resource) {
const permissions = {
'create_project': 'write',
'delete_project': 'write',
'sync_figma': 'write',
'export_tokens': 'read',
'modify_settings': 'write',
'manage_team': 'manage_team',
'view_audit': 'read',
};
return permissions[`${action}_${resource}`] || 'read';
}
/**
* Get all available routes
*/
getRoutes() {
return Array.from(this.guards.keys());
}
/**
* Check if route is protected
*/
isProtected(route) {
return this.guards.has(route);
}
}
// Create and export singleton
const routeGuard = new RouteGuard();
export { RouteGuard };
export default routeGuard;