202 lines
6.0 KiB
TypeScript
202 lines
6.0 KiB
TypeScript
import { Request, Response, NextFunction } from 'express';
|
|
import { RBACService } from '../services/rbac.service';
|
|
|
|
export interface AuthorizedRequest extends Request {
|
|
user?: {
|
|
id: string;
|
|
email: string;
|
|
subscription: string;
|
|
roles: string[];
|
|
[key: string]: any;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Middleware to check if user has required permission
|
|
*/
|
|
export function requirePermission(permissionId: string, projectIdParam?: string) {
|
|
return (req: AuthorizedRequest, res: Response, next: NextFunction) => {
|
|
if (!req.user) {
|
|
return res.status(401).json({ error: 'Authentication required' });
|
|
}
|
|
|
|
const userId = req.user.id;
|
|
let projectId: string | undefined;
|
|
|
|
// Extract project ID from request parameters if specified
|
|
if (projectIdParam) {
|
|
projectId = req.params[projectIdParam] || req.body[projectIdParam] || req.query[projectIdParam] as string;
|
|
}
|
|
|
|
// Check if user has the required permission
|
|
if (!RBACService.hasPermission(userId, permissionId, projectId)) {
|
|
return res.status(403).json({
|
|
error: 'Insufficient permissions',
|
|
required: permissionId,
|
|
projectId: projectId || 'global'
|
|
});
|
|
}
|
|
|
|
next();
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Middleware to check if user has any of the required permissions
|
|
*/
|
|
export function requireAnyPermission(permissionIds: string[], projectIdParam?: string) {
|
|
return (req: AuthorizedRequest, res: Response, next: NextFunction) => {
|
|
if (!req.user) {
|
|
return res.status(401).json({ error: 'Authentication required' });
|
|
}
|
|
|
|
const userId = req.user.id;
|
|
let projectId: string | undefined;
|
|
|
|
// Extract project ID from request parameters if specified
|
|
if (projectIdParam) {
|
|
projectId = req.params[projectIdParam] || req.body[projectIdParam] || req.query[projectIdParam] as string;
|
|
}
|
|
|
|
// Check if user has any of the required permissions
|
|
if (!RBACService.hasAnyPermission(userId, permissionIds, projectId)) {
|
|
return res.status(403).json({
|
|
error: 'Insufficient permissions',
|
|
required: `Any of: ${permissionIds.join(', ')}`,
|
|
projectId: projectId || 'global'
|
|
});
|
|
}
|
|
|
|
next();
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Middleware to check if user has all of the required permissions
|
|
*/
|
|
export function requireAllPermissions(permissionIds: string[], projectIdParam?: string) {
|
|
return (req: AuthorizedRequest, res: Response, next: NextFunction) => {
|
|
if (!req.user) {
|
|
return res.status(401).json({ error: 'Authentication required' });
|
|
}
|
|
|
|
const userId = req.user.id;
|
|
let projectId: string | undefined;
|
|
|
|
// Extract project ID from request parameters if specified
|
|
if (projectIdParam) {
|
|
projectId = req.params[projectIdParam] || req.body[projectIdParam] || req.query[projectIdParam] as string;
|
|
}
|
|
|
|
// Check if user has all of the required permissions
|
|
if (!RBACService.hasAllPermissions(userId, permissionIds, projectId)) {
|
|
return res.status(403).json({
|
|
error: 'Insufficient permissions',
|
|
required: `All of: ${permissionIds.join(', ')}`,
|
|
projectId: projectId || 'global'
|
|
});
|
|
}
|
|
|
|
next();
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Middleware to check if user is admin
|
|
*/
|
|
export function requireAdmin() {
|
|
return requirePermission('admin:system');
|
|
}
|
|
|
|
/**
|
|
* Middleware to check project access
|
|
*/
|
|
export function requireProjectAccess(action: 'read' | 'update' | 'delete' | 'share' = 'read', projectIdParam: string = 'projectId') {
|
|
return (req: AuthorizedRequest, res: Response, next: NextFunction) => {
|
|
if (!req.user) {
|
|
return res.status(401).json({ error: 'Authentication required' });
|
|
}
|
|
|
|
const userId = req.user.id;
|
|
const projectId = req.params[projectIdParam] || req.body[projectIdParam] || req.query[projectIdParam] as string;
|
|
|
|
if (!projectId) {
|
|
return res.status(400).json({ error: 'Project ID required' });
|
|
}
|
|
|
|
// Check if user can access the project
|
|
if (!RBACService.canAccessProject(userId, projectId, action)) {
|
|
return res.status(403).json({
|
|
error: 'Project access denied',
|
|
action,
|
|
projectId
|
|
});
|
|
}
|
|
|
|
next();
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Middleware to check if user owns the resource or is admin
|
|
*/
|
|
export function requireOwnershipOrAdmin(ownerIdParam: string = 'userId') {
|
|
return (req: AuthorizedRequest, res: Response, next: NextFunction) => {
|
|
if (!req.user) {
|
|
return res.status(401).json({ error: 'Authentication required' });
|
|
}
|
|
|
|
const userId = req.user.id;
|
|
const resourceOwnerId = req.params[ownerIdParam] || req.body[ownerIdParam] || req.query[ownerIdParam] as string;
|
|
|
|
// Allow if user is the owner or is admin
|
|
if (userId === resourceOwnerId || RBACService.isAdmin(userId)) {
|
|
return next();
|
|
}
|
|
|
|
return res.status(403).json({
|
|
error: 'Access denied - ownership or admin privileges required'
|
|
});
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Utility function to get user permissions for response
|
|
*/
|
|
export function getUserPermissionsForResponse(userId: string, projectId?: string) {
|
|
return {
|
|
permissions: RBACService.getUserPermissions(userId, projectId).map(p => ({
|
|
id: p.id,
|
|
name: p.name,
|
|
resource: p.resource,
|
|
action: p.action
|
|
})),
|
|
roles: RBACService.getUserRoles(userId, projectId).map(ur => ({
|
|
roleId: ur.roleId,
|
|
projectId: ur.projectId,
|
|
grantedAt: ur.grantedAt
|
|
})),
|
|
isAdmin: RBACService.isAdmin(userId)
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Middleware to add user permissions to response
|
|
*/
|
|
export function addUserPermissions(projectIdParam?: string) {
|
|
return (req: AuthorizedRequest, res: Response, next: NextFunction) => {
|
|
if (req.user) {
|
|
const userId = req.user.id;
|
|
let projectId: string | undefined;
|
|
|
|
if (projectIdParam) {
|
|
projectId = req.params[projectIdParam] || req.body[projectIdParam] || req.query[projectIdParam] as string;
|
|
}
|
|
|
|
// Add permissions to request for use in route handlers
|
|
(req as any).userPermissions = getUserPermissionsForResponse(userId, projectId);
|
|
}
|
|
|
|
next();
|
|
};
|
|
} |